mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-23 00:41:36 +00:00
Merge branch 'main' into feat/Desktop-app
This commit is contained in:
commit
81eb63cd9d
4 changed files with 106 additions and 8 deletions
|
|
@ -61,11 +61,13 @@ function resolveGitnexusBin(): string | null {
|
|||
.filter(Boolean);
|
||||
|
||||
if (isWin) {
|
||||
// On Windows, `where` returns multiple entries (e.g. the POSIX shell
|
||||
// script AND the .cmd/.bat wrapper). Prefer the wrapper because
|
||||
// child_process.spawn() cannot execute a shell script directly.
|
||||
// On Windows, npm global installs can surface multiple launchers for the
|
||||
// same package (e.g. a POSIX shell shim plus .cmd/.bat wrappers). Claude
|
||||
// and the other MCP hosts need a directly spawnable command path, so only
|
||||
// accept the Windows wrapper. If it is missing, fall back to the slower
|
||||
// npx entry instead of persisting a non-spawnable shim path.
|
||||
const cmdLine = lines.find((l) => /\.(cmd|bat)$/i.test(l));
|
||||
return cmdLine || lines[0] || null;
|
||||
return cmdLine || null;
|
||||
}
|
||||
|
||||
return lines[0] || null;
|
||||
|
|
|
|||
|
|
@ -15,8 +15,13 @@ const execFileMock = vi.fn((...args: any[]) => {
|
|||
}
|
||||
});
|
||||
|
||||
const execFileSyncMock = vi.fn(() => {
|
||||
throw new Error('not found');
|
||||
});
|
||||
|
||||
vi.mock('child_process', () => ({
|
||||
execFile: execFileMock,
|
||||
execFileSync: execFileSyncMock,
|
||||
}));
|
||||
|
||||
describe('setupCommand codex execution', () => {
|
||||
|
|
@ -74,6 +79,21 @@ describe('setupCommand codex execution', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('uses Windows npx fallback arguments when where returns only a non-wrapper shim', async () => {
|
||||
execFileSyncMock.mockReturnValueOnce('C:\\Users\\dev\\AppData\\Roaming\\npm\\gitnexus\n');
|
||||
|
||||
const { setupCommand } = await import('../../src/cli/setup.js');
|
||||
|
||||
await setupCommand();
|
||||
|
||||
expect(execFileMock).toHaveBeenCalledWith(
|
||||
'codex',
|
||||
['mcp', 'add', 'gitnexus', '--', 'cmd', '/c', 'npx', '-y', NPX_REF, 'mcp'],
|
||||
{ shell: true },
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
|
||||
it('invokes codex mcp add without shell on non-Windows and does not write fallback config', async () => {
|
||||
setPlatform('darwin');
|
||||
|
||||
|
|
|
|||
|
|
@ -241,6 +241,50 @@ describe('setupOpenCode — JSONC preservation', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('uses Windows npx fallback when where returns only a non-wrapper shim', async () => {
|
||||
setPlatform('win32');
|
||||
execFileSyncMock.mockReturnValueOnce('C:\\Users\\dev\\AppData\\Roaming\\npm\\gitnexus\n');
|
||||
|
||||
const jsonc = `{
|
||||
"model": "test",
|
||||
"mcp": {}
|
||||
}`;
|
||||
await fs.writeFile(opencodeJsonPath(), jsonc, 'utf-8');
|
||||
|
||||
const { setupCommand } = await import('../../src/cli/setup.js');
|
||||
await setupCommand();
|
||||
|
||||
const raw = await fs.readFile(opencodeJsonPath(), 'utf-8');
|
||||
const config = parseJsonc(raw);
|
||||
|
||||
expect(config.mcp.gitnexus).toEqual({
|
||||
type: 'local',
|
||||
command: ['cmd', '/c', 'npx', '-y', NPX_REF, 'mcp'],
|
||||
});
|
||||
});
|
||||
|
||||
it('uses Windows npx fallback when where returns only a .ps1 path', async () => {
|
||||
setPlatform('win32');
|
||||
execFileSyncMock.mockReturnValueOnce('C:\\Users\\dev\\AppData\\Roaming\\npm\\gitnexus.ps1\n');
|
||||
|
||||
const jsonc = `{
|
||||
"model": "test",
|
||||
"mcp": {}
|
||||
}`;
|
||||
await fs.writeFile(opencodeJsonPath(), jsonc, 'utf-8');
|
||||
|
||||
const { setupCommand } = await import('../../src/cli/setup.js');
|
||||
await setupCommand();
|
||||
|
||||
const raw = await fs.readFile(opencodeJsonPath(), 'utf-8');
|
||||
const config = parseJsonc(raw);
|
||||
|
||||
expect(config.mcp.gitnexus).toEqual({
|
||||
type: 'local',
|
||||
command: ['cmd', '/c', 'npx', '-y', NPX_REF, 'mcp'],
|
||||
});
|
||||
});
|
||||
|
||||
it('preserves tab indentation in existing file', async () => {
|
||||
const tabbed = `{\n\t"model": "test"\n}`;
|
||||
await fs.writeFile(opencodeJsonPath(), tabbed, 'utf-8');
|
||||
|
|
@ -360,6 +404,22 @@ describe('setupCursor — JSONC preservation', () => {
|
|||
const raw = await fs.readFile(mcpPath(), 'utf-8');
|
||||
expect(raw).toBe(corrupt);
|
||||
});
|
||||
|
||||
it('uses Windows npx fallback when where returns only a non-wrapper shim', async () => {
|
||||
setPlatform('win32');
|
||||
execFileSyncMock.mockReturnValueOnce('C:\\Users\\dev\\AppData\\Roaming\\npm\\gitnexus\n');
|
||||
|
||||
const { setupCommand } = await import('../../src/cli/setup.js');
|
||||
await setupCommand();
|
||||
|
||||
const raw = await fs.readFile(mcpPath(), 'utf-8');
|
||||
const config = parseJsonc(raw);
|
||||
|
||||
expect(config.mcpServers.gitnexus).toEqual({
|
||||
command: 'cmd',
|
||||
args: ['/c', 'npx', '-y', NPX_REF, 'mcp'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('setupClaudeCode — JSONC preservation', () => {
|
||||
|
|
|
|||
|
|
@ -282,9 +282,9 @@ describe('setupClaudeCode', () => {
|
|||
).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('falls back to first line on Windows when no .cmd/.bat wrapper found', async () => {
|
||||
it('falls back to npx on Windows when no .cmd/.bat wrapper is found', async () => {
|
||||
setPlatform('win32');
|
||||
// Edge case: where returns only the POSIX script (no .cmd wrapper)
|
||||
// Edge case: where returns only a non-spawnable shim (no .cmd wrapper)
|
||||
execFileSyncMock.mockReturnValueOnce('C:\\Users\\dev\\AppData\\Roaming\\npm\\gitnexus\n');
|
||||
|
||||
const { setupCommand } = await import('../../src/cli/setup.js');
|
||||
|
|
@ -294,8 +294,24 @@ describe('setupClaudeCode', () => {
|
|||
const config = JSON.parse(raw);
|
||||
|
||||
expect(config.mcpServers.gitnexus).toEqual({
|
||||
command: 'C:\\Users\\dev\\AppData\\Roaming\\npm\\gitnexus',
|
||||
args: ['mcp'],
|
||||
command: 'cmd',
|
||||
args: ['/c', 'npx', '-y', NPX_REF, 'mcp'],
|
||||
});
|
||||
});
|
||||
|
||||
it('falls back to npx on Windows when where returns only a .ps1 path', async () => {
|
||||
setPlatform('win32');
|
||||
execFileSyncMock.mockReturnValueOnce('C:\\Users\\dev\\AppData\\Roaming\\npm\\gitnexus.ps1\n');
|
||||
|
||||
const { setupCommand } = await import('../../src/cli/setup.js');
|
||||
await setupCommand();
|
||||
|
||||
const raw = await fs.readFile(path.join(tempHome, '.claude.json'), 'utf-8');
|
||||
const config = JSON.parse(raw);
|
||||
|
||||
expect(config.mcpServers.gitnexus).toEqual({
|
||||
command: 'cmd',
|
||||
args: ['/c', 'npx', '-y', NPX_REF, 'mcp'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue