diff --git a/apps/ai-game-creator-shell/scripts/stage-node-runtime.mjs b/apps/ai-game-creator-shell/scripts/stage-node-runtime.mjs index 9b6c5a934..e2fe1b8d1 100644 --- a/apps/ai-game-creator-shell/scripts/stage-node-runtime.mjs +++ b/apps/ai-game-creator-shell/scripts/stage-node-runtime.mjs @@ -132,7 +132,9 @@ export function runtimeSourceForTarget( } return { nodePath: configured, - npmCli: undefined, + // 明令不使用宿主 npm(`npm_execpath`):另一架构的 npm 必须来自它自己那份发行版 + // 安装目录,否则两份切片的 npm 来源不同源,架构与来源对不上。null 表示"按 node 目录查找"。 + npmCli: null, licensePath: env[`AGC_NODE_RUNTIME_${key}_LICENSE_PATH`]?.trim(), }; } @@ -372,6 +374,7 @@ export function inspectRuntimeSource( ); } const nodeDirectory = path.dirname(node); + // `npmCli: null` 表示显式拒绝沿用宿主 npm,只按这份 node 自己的安装目录查找。 const npmCandidates = [ npmCli, path.join(nodeDirectory, 'node_modules/npm/bin/npm-cli.js'), diff --git a/apps/ai-game-creator-shell/scripts/stage-node-runtime.test.mjs b/apps/ai-game-creator-shell/scripts/stage-node-runtime.test.mjs index 23836fe21..c42ee8754 100644 --- a/apps/ai-game-creator-shell/scripts/stage-node-runtime.test.mjs +++ b/apps/ai-game-creator-shell/scripts/stage-node-runtime.test.mjs @@ -376,10 +376,20 @@ test('universal stages one runtime per architecture with architecture-correct ma 'aarch64-apple-darwin', 'x86_64-apple-darwin', ]); - const manifests = stageNodeRuntimeForTarget( - 'universal-apple-darwin', - optionsFor(root, sources), - ); + // 模拟经 `npm run` 触发的构建:npm 把宿主的 npm-cli.js 放进环境变量。 + // 另一架构的切片必须无视它,只能使用自己发行版目录里的 npm。 + const previousNpmExecPath = process.env.npm_execpath; + process.env.npm_execpath = sources.arm64.npmCli; + let manifests; + try { + manifests = stageNodeRuntimeForTarget( + 'universal-apple-darwin', + optionsFor(root, sources), + ); + } finally { + if (previousNpmExecPath === undefined) delete process.env.npm_execpath; + else process.env.npm_execpath = previousNpmExecPath; + } assert.deepEqual( manifests.map((manifest) => `${manifest.platform}-${manifest.arch}`), ['darwin-arm64', 'darwin-x64'], @@ -400,6 +410,14 @@ test('universal stages one runtime per architecture with architecture-correct ma assert.ok( fs.existsSync(path.join(directory, 'node_modules/npm/LICENSE')), ); + // 每份切片必须自带对应架构发行版的 npm,不能借用宿主那一份。 + assert.equal( + fs.readFileSync( + path.join(directory, 'node_modules/npm/bin/npm-cli.js'), + 'utf8', + ), + `// ${manifest.arch}`, + ); } // 单架构目标仍写扁平目录(与既有发布一致),不产生分架构子目录。 const flat = stageNodeRuntimeForTarget(