From 4759ba12f721f98d79242029804311094326c6df Mon Sep 17 00:00:00 2001 From: sean Date: Mon, 2 Jun 2025 11:44:04 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=91=BD=E4=BB=A4=E5=89=8D?= =?UTF-8?q?=E7=BC=80=E6=8F=90=E5=8F=96=E9=80=BB=E8=BE=91=EF=BC=9A=E4=BB=8E?= =?UTF-8?q?=20process.argv=20=E4=B8=AD=E6=8F=90=E5=8F=96=20init=20?= =?UTF-8?q?=E4=B9=8B=E5=89=8D=E7=9A=84=E5=8F=82=E6=95=B0=E4=BD=9C=E4=B8=BA?= =?UTF-8?q?=E5=91=BD=E4=BB=A4=E5=89=8D=E7=BC=80=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=BC=80=E5=8F=91=E6=A8=A1=E5=BC=8F=E4=B8=8B=E7=AE=80=E5=8C=96?= =?UTF-8?q?=E4=B8=BA=E5=8C=85=E5=90=8D=E3=80=82=E6=9B=B4=E6=96=B0=20E2E=20?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B=EF=BC=8C=E7=A1=AE=E4=BF=9D?= =?UTF-8?q?=E5=9C=A8=E4=B8=8D=E5=90=8C=E8=B0=83=E7=94=A8=E6=96=B9=E5=BC=8F?= =?UTF-8?q?=E4=B8=8B=E6=AD=A3=E7=A1=AE=E4=BF=9D=E5=AD=98=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E5=89=8D=E7=BC=80=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/constants.js | 37 ++++++++++++---- src/tests/commands/command-prefix.e2e.test.js | 42 +++++++++++++++---- 2 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/constants.js b/src/constants.js index e096438..970ae6c 100644 --- a/src/constants.js +++ b/src/constants.js @@ -63,16 +63,39 @@ function detectCommandPrefix() { /** * 智能推测用户使用的命令前缀 - * 基于环境变量和执行路径的启发式判断 + * 从 process.argv 中提取 init 之前的所有部分作为命令前缀 */ function reconstructCommandPrefix() { - // 最简单最直接的判断:如果有 npm_execpath 且包含 npx,就是 npx 调用 - if (process.env.npm_execpath && process.env.npm_execpath.includes('npx')) { - return 'npx dpml-prompt@snapshot' // 默认 snapshot 版本 + try { + // 从 process.argv 中找到 init 命令的位置 + const initIndex = process.argv.findIndex(arg => arg === 'init') + + if (initIndex > 0) { + // 提取 init 之前的所有参数,跳过 node 可执行文件路径 + const prefixParts = process.argv.slice(1, initIndex) + + if (prefixParts.length > 0) { + // 如果第一部分是脚本路径,简化为包名 + const firstPart = prefixParts[0] + if (firstPart.includes('cli.js') || firstPart.includes('bin')) { + // 开发模式,替换为包名 + prefixParts[0] = 'dpml-prompt' + } + + return prefixParts.join(' ') + } + } + + // 如果找不到 init 或解析失败,使用环境变量判断 + if (process.env.npm_execpath && process.env.npm_execpath.includes('npx')) { + return 'npx dpml-prompt@snapshot' + } + + return 'dpml-prompt' + } catch (error) { + // 解析失败时的回退逻辑 + return 'dpml-prompt' } - - // 其他情况默认是全局安装 - return 'dpml-prompt' } /** diff --git a/src/tests/commands/command-prefix.e2e.test.js b/src/tests/commands/command-prefix.e2e.test.js index 694f99c..802d91b 100644 --- a/src/tests/commands/command-prefix.e2e.test.js +++ b/src/tests/commands/command-prefix.e2e.test.js @@ -44,7 +44,7 @@ describe('命令前缀动态检测 E2E', () => { describe('init命令保存命令前缀', () => { test('npx方式调用时应保存npx前缀', async () => { // 模拟npx调用init命令 - process.argv = ['node', 'npx_cache/dpml-prompt@snapshot/dist/bin/promptx.js', 'init'] + process.argv = ['node', 'npx', 'dpml-prompt@snapshot', 'init'] process.env.npm_execpath = '/usr/local/lib/node_modules/npm/bin/npx-cli.js' // 导入并执行init命令 @@ -71,7 +71,7 @@ describe('命令前缀动态检测 E2E', () => { }) test('指定版本号时应正确保存', async () => { - process.argv = ['node', 'npx_cache/dpml-prompt@latest/dist/bin/promptx.js', 'init'] + process.argv = ['node', 'npx', 'dpml-prompt@latest', 'init'] process.env.npm_execpath = '/usr/local/lib/node_modules/npm/bin/npx-cli.js' const cli = new PouchCLI() @@ -79,7 +79,7 @@ describe('命令前缀动态检测 E2E', () => { await cli.execute('init', []) const savedPrefix = await config.readText('command-prefix') - expect(savedPrefix).toBe('npx dpml-prompt@snapshot') // 简化逻辑只会返回默认snapshot版本 + expect(savedPrefix).toBe('npx dpml-prompt@latest') }) }) @@ -130,25 +130,25 @@ describe('命令前缀动态检测 E2E', () => { const testCases = [ { name: 'npx最新版本', - argv: ['node', '/tmp/.npm/_npx/1234/lib/node_modules/dpml-prompt/src/bin/promptx.js', 'init'], + argv: ['node', 'npx', 'dpml-prompt', 'init'], hasNpxEnv: true, - expected: 'npx dpml-prompt@snapshot' + expected: 'npx dpml-prompt' }, { name: 'npx指定版本', - argv: ['node', '/tmp/.npm/_npx/1234/lib/node_modules/dpml-prompt@0.1.0/src/bin/promptx.js', 'init'], + argv: ['node', 'npx', 'dpml-prompt@0.1.0', 'init'], hasNpxEnv: true, - expected: 'npx dpml-prompt@snapshot' + expected: 'npx dpml-prompt@0.1.0' }, { name: 'npx snapshot版本', - argv: ['node', '/tmp/.npm/_npx/1234/lib/node_modules/dpml-prompt@snapshot/src/bin/promptx.js', 'init'], + argv: ['node', 'npx', 'dpml-prompt@snapshot', 'init'], hasNpxEnv: true, expected: 'npx dpml-prompt@snapshot' }, { name: '全局安装', - argv: ['node', '/usr/local/bin/dpml-prompt', 'init'], + argv: ['node', 'dpml-prompt', 'init'], hasNpxEnv: false, expected: 'dpml-prompt' }, @@ -157,6 +157,30 @@ describe('命令前缀动态检测 E2E', () => { argv: ['node', '/Users/dev/PromptX/src/bin/promptx.js', 'init'], hasNpxEnv: false, expected: 'dpml-prompt' + }, + { + name: 'npx -y 参数', + argv: ['node', 'npx', '-y', 'dpml-prompt', 'init'], + hasNpxEnv: true, + expected: 'npx -y dpml-prompt' + }, + { + name: 'npx 复杂参数', + argv: ['node', 'npx', '--yes', '--registry=https://registry.npm.taobao.org', 'dpml-prompt@latest', 'init'], + hasNpxEnv: true, + expected: 'npx --yes --registry=https://registry.npm.taobao.org dpml-prompt@latest' + }, + { + name: 'pnpm dlx', + argv: ['node', 'pnpm', 'dlx', 'dpml-prompt@snapshot', 'init'], + hasNpxEnv: false, + expected: 'pnpm dlx dpml-prompt@snapshot' + }, + { + name: 'yarn dlx', + argv: ['node', 'yarn', 'dlx', 'dpml-prompt', 'init'], + hasNpxEnv: false, + expected: 'yarn dlx dpml-prompt' } ]