mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-20 09:09:35 +02:00
fix(mcp-sync): read Gemini bare url as http, OpenCode V2 mcp.servers, and opencode.jsonc
Gemini v0.63.0 treats a bare url as streamable HTTP first, OpenCode V2 nests servers under mcp.servers with disabled instead of enabled, and a config kept only as opencode.jsonc was read as "no OpenCode config". Fix all three read gaps; the write path is unchanged. Fixes #586.
This commit is contained in:
1 parent
aa3730aace
commit
331841f482
5 files changed
+101
-8
No files matched your search
+39
-2
@@ -98,7 +98,7 @@ describe('dialect parsing', () => {
|
||||
expect(servers.fs).toEqual({ transport: 'stdio', command: 'npx', args: ['-y'] });
|
||||
});
|
||||
|
||||
it('reads gemini url (sse) vs httpUrl / type http, and opencode local/remote', () => {
|
||||
it('reads gemini bare url as http (v0.63), httpUrl / type sse, and opencode local/remote', () => {
|
||||
const g = parseServers(
|
||||
'gemini-json',
|
||||
JSON.stringify({
|
||||
@@ -107,13 +107,15 @@ describe('dialect parsing', () => {
|
||||
b: { httpUrl: 'https://b' },
|
||||
c: { command: 'c', args: ['1'] },
|
||||
d: { url: 'https://d', type: 'http' },
|
||||
e: { url: 'https://e', type: 'sse' },
|
||||
},
|
||||
})
|
||||
);
|
||||
expect(g.a.transport).toBe('sse');
|
||||
expect(g.a.transport).toBe('http');
|
||||
expect(g.b.transport).toBe('http');
|
||||
expect(g.c).toEqual({ transport: 'stdio', command: 'c', args: ['1'] });
|
||||
expect(g.d.transport).toBe('http');
|
||||
expect(g.e.transport).toBe('sse');
|
||||
const o = parseServers(
|
||||
'opencode-json',
|
||||
JSON.stringify({
|
||||
@@ -127,6 +129,24 @@ describe('dialect parsing', () => {
|
||||
expect(o.r).toEqual({ transport: 'http', url: 'https://r' });
|
||||
});
|
||||
|
||||
it('reads OpenCode V2 servers nested under mcp.servers, with disabled', () => {
|
||||
const o = parseServers(
|
||||
'opencode-json',
|
||||
JSON.stringify({
|
||||
mcp: {
|
||||
servers: {
|
||||
off: { type: 'remote', url: 'https://off', disabled: true },
|
||||
nested: { type: 'local', command: ['npx', '-y', 'x'] },
|
||||
},
|
||||
direct: { type: 'remote', url: 'https://direct' },
|
||||
},
|
||||
})
|
||||
);
|
||||
expect(o.off).toEqual({ transport: 'http', url: 'https://off', disabled: true });
|
||||
expect(o.nested).toEqual({ transport: 'stdio', command: 'npx', args: ['-y', 'x'] });
|
||||
expect(o.direct).toEqual({ transport: 'http', url: 'https://direct' });
|
||||
});
|
||||
|
||||
it('throws on unparseable files so they are never written', () => {
|
||||
expect(() => parseServers('opencode-json', '{ // jsonc\n}')).toThrow();
|
||||
expect(() => parseServers('codex-toml', '[mcp_servers.a]\ncommand="x"\n[mcp_servers.a]\ncommand="y"\n')).toThrow();
|
||||
@@ -325,6 +345,23 @@ describe('syncMcpServers', () => {
|
||||
put('.gemini/config/mcp_config.json', '{}');
|
||||
};
|
||||
|
||||
it('reads opencode.jsonc when opencode.json is absent', async () => {
|
||||
put('.config/opencode/opencode.jsonc', JSON.stringify({ mcp: { fs: { type: 'local', command: ['a'] } } }));
|
||||
const opencode = target('opencode', { altPath: '.config/opencode/opencode.jsonc' });
|
||||
const r = await syncMcpServers([opencode], { apply: false, home });
|
||||
const o = result(r, 'opencode');
|
||||
expect(o.status).toBe('ok');
|
||||
expect(o.servers).toContain('fs');
|
||||
});
|
||||
|
||||
it('reports opencode.jsonc with comments as unreadable, not absent', async () => {
|
||||
put('.config/opencode/opencode.jsonc', '{\n // jsonc comment\n "mcp": {}\n}');
|
||||
const opencode = target('opencode', { altPath: '.config/opencode/opencode.jsonc' });
|
||||
const r = await syncMcpServers([opencode], { apply: false, home });
|
||||
const o = result(r, 'opencode');
|
||||
expect(o.status).toBe('unreadable');
|
||||
});
|
||||
|
||||
it('previews without writing and never leaks env values', async () => {
|
||||
setUpAll();
|
||||
put('.claude.json', claudeFile);
|
||||
|
||||
Reference in new issue
Block a user