From 4c897d35abbd03a8a85b0d376f261e4e44c8bf3a Mon Sep 17 00:00:00 2001 From: cafitac Date: Tue, 28 Apr 2026 20:57:45 +0900 Subject: [PATCH] fix: use active node npm for wrapper updates --- lib/wrapper.cjs | 6 ++++-- test/wrapper.test.cjs | 17 ++++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/lib/wrapper.cjs b/lib/wrapper.cjs index 603484b..6e61e65 100644 --- a/lib/wrapper.cjs +++ b/lib/wrapper.cjs @@ -658,8 +658,10 @@ function printDoctor(report, jsonMode = false) { } } -function runWrapperUpdate(stdio = 'inherit', runner = spawnSync) { - const result = runner('npm', ['install', '-g', '@cafitac/agent-learner@latest'], { +function runWrapperUpdate(stdio = 'inherit', runner = spawnSync, nodeExecutable = process.execPath) { + const siblingNpm = path.join(path.dirname(nodeExecutable), process.platform === 'win32' ? 'npm.cmd' : 'npm'); + const tool = fs.existsSync(siblingNpm) ? siblingNpm : 'npm'; + const result = runner(tool, ['install', '-g', '@cafitac/agent-learner@latest'], { stdio, encoding: 'utf-8' }); diff --git a/test/wrapper.test.cjs b/test/wrapper.test.cjs index a2151de..b95a089 100644 --- a/test/wrapper.test.cjs +++ b/test/wrapper.test.cjs @@ -302,12 +302,23 @@ test('printHelp advertises bootstrap as the install path', () => { assert.doesNotMatch(output, /install-claude/); }); -test('runWrapperUpdate shells out to npm global install', () => { +test('runWrapperUpdate prefers the npm next to the active node executable', () => { + const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-learner-wrapper-update-')); + const binDir = path.join(tempRoot, 'bin'); + fs.mkdirSync(binDir, { recursive: true }); + const nodeExecutable = path.join(binDir, process.platform === 'win32' ? 'node.exe' : 'node'); + const npmExecutable = path.join(binDir, process.platform === 'win32' ? 'npm.cmd' : 'npm'); + fs.writeFileSync(nodeExecutable, ''); + fs.writeFileSync(npmExecutable, ''); + const calls = []; const fakeRunner = (tool, args) => { calls.push({ tool, args }); return { status: 0, stdout: '', stderr: '' }; }; - assert.equal(runWrapperUpdate('pipe', fakeRunner), 0); - assert.deepEqual(calls[0], { tool: 'npm', args: ['install', '-g', '@cafitac/agent-learner@latest'] }); + assert.equal(runWrapperUpdate('pipe', fakeRunner, nodeExecutable), 0); + assert.deepEqual(calls[0], { + tool: npmExecutable, + args: ['install', '-g', '@cafitac/agent-learner@latest'] + }); });