mirror of
https://fastgit.cc/github.com/Yeachan-Heo/oh-my-claudecode
synced 2026-04-20 21:00:50 +08:00
Fix Windows HUD npm root discovery
The HUD wrapper needs npm root discovery to keep global installs reachable when cache and marketplace paths are absent. Node 20.12+ rejects direct npm.cmd execFileSync calls on Windows unless shell execution is enabled, so limit shell:true to the Windows npm.cmd probe while preserving the existing non-Windows npm exec behavior.
Constraint: Node 20.12+ requires shell execution for Windows .cmd/.bat child_process calls.
Rejected: Use execSync('npm root -g') everywhere | broader behavior change for non-Windows wrapper runtime.
Confidence: high
Scope-risk: narrow
Tested: npm test -- --run src/installer/__tests__/hud-wrapper-env.test.ts src/__tests__/hud-windows.test.ts src/__tests__/hud-wrapper-template-sync.test.ts src/__tests__/hud-marketplace-resolution.test.ts
Tested: npx tsc
This commit is contained in:
8
dist/__tests__/hud-windows.test.js
generated
vendored
8
dist/__tests__/hud-windows.test.js
generated
vendored
@@ -53,6 +53,14 @@ describe('HUD Windows Compatibility', () => {
|
||||
const content = readFileSync(templatePath, 'utf-8');
|
||||
expect(content).toContain('pathToFileURL(pluginPath).href');
|
||||
});
|
||||
it('shared HUD wrapper template uses shell:true only for Windows npm root discovery', () => {
|
||||
const templatePath = join(packageRoot, 'scripts', 'lib', 'hud-wrapper-template.txt');
|
||||
const content = readFileSync(templatePath, 'utf-8');
|
||||
expect(content).toContain('const isWin = process.platform === "win32";');
|
||||
expect(content).toContain('const npmCommand = isWin ? "npm.cmd" : "npm";');
|
||||
expect(content).toContain('shell: isWin');
|
||||
expect(content).not.toContain('shell: true');
|
||||
});
|
||||
it('pathToFileURL should correctly convert Unix paths', () => {
|
||||
const unixPath = '/home/user/test.js';
|
||||
expect(pathToFileURL(unixPath).href).toBe(process.platform === 'win32'
|
||||
|
||||
2
dist/__tests__/hud-windows.test.js.map
generated
vendored
2
dist/__tests__/hud-windows.test.js.map
generated
vendored
File diff suppressed because one or more lines are too long
7
dist/installer/__tests__/hud-wrapper-env.test.js
generated
vendored
7
dist/installer/__tests__/hud-wrapper-env.test.js
generated
vendored
@@ -229,6 +229,13 @@ describe('HUD wrapper — OMC_PLUGIN_ROOT resolution', () => {
|
||||
expect(txt).not.toContain('Workspace/oh-my-claudecode');
|
||||
expect(txt).not.toContain('projects/oh-my-claudecode');
|
||||
});
|
||||
it('uses shell:true only for Windows npm root discovery', () => {
|
||||
const txt = readFileSync(TEMPLATE_TXT, 'utf8');
|
||||
expect(txt).toContain('const isWin = process.platform === "win32";');
|
||||
expect(txt).toContain('const npmCommand = isWin ? "npm.cmd" : "npm";');
|
||||
expect(txt).toContain('shell: isWin');
|
||||
expect(txt).not.toContain('shell: true');
|
||||
});
|
||||
});
|
||||
describe('HUD wrapper — fixture sanity', () => {
|
||||
it('the template txt file exists in the repo', () => {
|
||||
|
||||
2
dist/installer/__tests__/hud-wrapper-env.test.js.map
generated
vendored
2
dist/installer/__tests__/hud-wrapper-env.test.js.map
generated
vendored
File diff suppressed because one or more lines are too long
@@ -46,11 +46,15 @@ function getGlobalNodeModuleRoots() {
|
||||
}
|
||||
|
||||
try {
|
||||
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
||||
const isWin = process.platform === "win32";
|
||||
const npmCommand = isWin ? "npm.cmd" : "npm";
|
||||
const npmRoot = String(execFileSync(npmCommand, ["root", "-g"], {
|
||||
encoding: "utf8",
|
||||
stdio: ["ignore", "pipe", "ignore"],
|
||||
timeout: 1500,
|
||||
// Node 20.12+ rejects direct .cmd/.bat spawns without a shell on Windows.
|
||||
// Keep non-Windows behavior unchanged by only enabling shell there.
|
||||
shell: isWin,
|
||||
})).trim();
|
||||
if (npmRoot) roots.unshift(npmRoot);
|
||||
} catch { /* continue */ }
|
||||
|
||||
@@ -63,6 +63,15 @@ describe('HUD Windows Compatibility', () => {
|
||||
expect(content).toContain('pathToFileURL(pluginPath).href');
|
||||
});
|
||||
|
||||
it('shared HUD wrapper template uses shell:true only for Windows npm root discovery', () => {
|
||||
const templatePath = join(packageRoot, 'scripts', 'lib', 'hud-wrapper-template.txt');
|
||||
const content = readFileSync(templatePath, 'utf-8');
|
||||
expect(content).toContain('const isWin = process.platform === "win32";');
|
||||
expect(content).toContain('const npmCommand = isWin ? "npm.cmd" : "npm";');
|
||||
expect(content).toContain('shell: isWin');
|
||||
expect(content).not.toContain('shell: true');
|
||||
});
|
||||
|
||||
it('pathToFileURL should correctly convert Unix paths', () => {
|
||||
const unixPath = '/home/user/test.js';
|
||||
expect(pathToFileURL(unixPath).href).toBe(
|
||||
|
||||
@@ -302,6 +302,15 @@ describe('HUD wrapper — OMC_PLUGIN_ROOT resolution', () => {
|
||||
expect(txt).not.toContain('Workspace/oh-my-claudecode');
|
||||
expect(txt).not.toContain('projects/oh-my-claudecode');
|
||||
});
|
||||
|
||||
it('uses shell:true only for Windows npm root discovery', () => {
|
||||
const txt = readFileSync(TEMPLATE_TXT, 'utf8');
|
||||
|
||||
expect(txt).toContain('const isWin = process.platform === "win32";');
|
||||
expect(txt).toContain('const npmCommand = isWin ? "npm.cmd" : "npm";');
|
||||
expect(txt).toContain('shell: isWin');
|
||||
expect(txt).not.toContain('shell: true');
|
||||
});
|
||||
});
|
||||
|
||||
describe('HUD wrapper — fixture sanity', () => {
|
||||
|
||||
Reference in New Issue
Block a user