fix(opencode): default to http mcp bridge
This commit is contained in:
parent
279439de10
commit
429dfe5528
5 changed files with 211 additions and 56 deletions
|
|
@ -145,6 +145,10 @@ import {
|
||||||
OpenCodeBridgeCommandHandshakePort,
|
OpenCodeBridgeCommandHandshakePort,
|
||||||
} from './services/team/opencode/bridge/OpenCodeBridgeHandshakeClient';
|
} from './services/team/opencode/bridge/OpenCodeBridgeHandshakeClient';
|
||||||
import { cleanupManagedOpenCodeServeProcesses } from './services/team/opencode/bridge/OpenCodeManagedHostProcessCleanup';
|
import { cleanupManagedOpenCodeServeProcesses } from './services/team/opencode/bridge/OpenCodeManagedHostProcessCleanup';
|
||||||
|
import {
|
||||||
|
clearOpenCodeLocalMcpLaunchEnv,
|
||||||
|
isOpenCodeMcpHttpBridgeEnabled,
|
||||||
|
} from './services/team/opencode/bridge/OpenCodeMcpBridgeEnv';
|
||||||
import { OpenCodeStateChangingBridgeCommandService } from './services/team/opencode/bridge/OpenCodeStateChangingBridgeCommandService';
|
import { OpenCodeStateChangingBridgeCommandService } from './services/team/opencode/bridge/OpenCodeStateChangingBridgeCommandService';
|
||||||
import { OpenCodeRuntimeManifestEvidenceReader } from './services/team/opencode/store/OpenCodeRuntimeManifestEvidenceReader';
|
import { OpenCodeRuntimeManifestEvidenceReader } from './services/team/opencode/store/OpenCodeRuntimeManifestEvidenceReader';
|
||||||
import {
|
import {
|
||||||
|
|
@ -353,10 +357,11 @@ async function createOpenCodeRuntimeAdapterRegistry(
|
||||||
const bridgeEnv = applyOpenCodeAutoUpdatePolicy({ ...process.env });
|
const bridgeEnv = applyOpenCodeAutoUpdatePolicy({ ...process.env });
|
||||||
bridgeEnv.CLAUDE_TEAM_APP_INSTANCE_ID = openCodeManagedHostInstanceId;
|
bridgeEnv.CLAUDE_TEAM_APP_INSTANCE_ID = openCodeManagedHostInstanceId;
|
||||||
bridgeEnv.AGENT_TEAMS_MCP_CLAUDE_DIR = getClaudeBasePath();
|
bridgeEnv.AGENT_TEAMS_MCP_CLAUDE_DIR = getClaudeBasePath();
|
||||||
const useHttpMcpBridge = bridgeEnv.CLAUDE_TEAM_OPENCODE_MCP_HTTP === '1';
|
const useHttpMcpBridge = isOpenCodeMcpHttpBridgeEnabled(bridgeEnv);
|
||||||
if (!useHttpMcpBridge) {
|
if (!useHttpMcpBridge) {
|
||||||
// The OpenCode bridge direct tools/list proof currently requires a local MCP command.
|
|
||||||
delete bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL;
|
delete bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL;
|
||||||
|
} else {
|
||||||
|
clearOpenCodeLocalMcpLaunchEnv(bridgeEnv);
|
||||||
}
|
}
|
||||||
const applyMcpLaunchSpecEnv = async (
|
const applyMcpLaunchSpecEnv = async (
|
||||||
targetEnv: NodeJS.ProcessEnv,
|
targetEnv: NodeJS.ProcessEnv,
|
||||||
|
|
@ -418,6 +423,7 @@ async function createOpenCodeRuntimeAdapterRegistry(
|
||||||
reportProgress('runtime-mcp-http', 'Starting Agent Teams MCP server...');
|
reportProgress('runtime-mcp-http', 'Starting Agent Teams MCP server...');
|
||||||
const mcpHttpServer = await agentTeamsMcpHttpServer.ensureStarted();
|
const mcpHttpServer = await agentTeamsMcpHttpServer.ensureStarted();
|
||||||
bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL = mcpHttpServer.url;
|
bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL = mcpHttpServer.url;
|
||||||
|
clearOpenCodeLocalMcpLaunchEnv(bridgeEnv);
|
||||||
reportProgress('runtime-mcp-http-ready', 'Agent Teams MCP server is ready...');
|
reportProgress('runtime-mcp-http-ready', 'Agent Teams MCP server is ready...');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
|
|
@ -427,45 +433,26 @@ async function createOpenCodeRuntimeAdapterRegistry(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL) {
|
if (!useHttpMcpBridge && !bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL) {
|
||||||
await applyMcpLaunchSpecEnv(bridgeEnv, { emitProgress: true });
|
await applyMcpLaunchSpecEnv(bridgeEnv, { emitProgress: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
reportProgress('runtime-bridge', 'Preparing OpenCode bridge...');
|
reportProgress('runtime-bridge', 'Preparing OpenCode bridge...');
|
||||||
const resolveBridgeCommandEnv = async (): Promise<NodeJS.ProcessEnv> => {
|
const resolveBridgeCommandEnv = async (): Promise<NodeJS.ProcessEnv> => {
|
||||||
const nextEnv = { ...bridgeEnv };
|
const nextEnv = { ...bridgeEnv };
|
||||||
if (!useHttpMcpBridge || !bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL) {
|
if (!useHttpMcpBridge) {
|
||||||
return nextEnv;
|
return nextEnv;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const mcpHttpServer = await agentTeamsMcpHttpServer.ensureStarted();
|
const mcpHttpServer = await agentTeamsMcpHttpServer.ensureStarted();
|
||||||
bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL = mcpHttpServer.url;
|
bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL = mcpHttpServer.url;
|
||||||
nextEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL = mcpHttpServer.url;
|
nextEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL = mcpHttpServer.url;
|
||||||
delete nextEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_COMMAND;
|
clearOpenCodeLocalMcpLaunchEnv(bridgeEnv);
|
||||||
delete nextEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ENTRY;
|
clearOpenCodeLocalMcpLaunchEnv(nextEnv);
|
||||||
delete nextEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ARGS_JSON;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
delete bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL;
|
||||||
delete nextEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL;
|
delete nextEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL;
|
||||||
if (
|
clearOpenCodeLocalMcpLaunchEnv(nextEnv);
|
||||||
bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_COMMAND &&
|
|
||||||
bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ENTRY &&
|
|
||||||
bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ARGS_JSON
|
|
||||||
) {
|
|
||||||
nextEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_COMMAND =
|
|
||||||
bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_COMMAND;
|
|
||||||
nextEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ENTRY =
|
|
||||||
bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ENTRY;
|
|
||||||
nextEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ARGS_JSON =
|
|
||||||
bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ARGS_JSON;
|
|
||||||
} else {
|
|
||||||
await applyMcpLaunchSpecEnv(nextEnv);
|
|
||||||
bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_COMMAND =
|
|
||||||
nextEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_COMMAND;
|
|
||||||
bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ENTRY =
|
|
||||||
nextEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ENTRY;
|
|
||||||
bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ARGS_JSON =
|
|
||||||
nextEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ARGS_JSON;
|
|
||||||
}
|
|
||||||
logger.warn(
|
logger.warn(
|
||||||
`[OpenCode] Runtime adapter bridge MCP HTTP server refresh failed: ${
|
`[OpenCode] Runtime adapter bridge MCP HTTP server refresh failed: ${
|
||||||
error instanceof Error ? error.message : String(error)
|
error instanceof Error ? error.message : String(error)
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,25 @@ export interface OpenCodeBridgeCommandClientOptions {
|
||||||
|
|
||||||
const DEFAULT_STDOUT_LIMIT_BYTES = 1_000_000;
|
const DEFAULT_STDOUT_LIMIT_BYTES = 1_000_000;
|
||||||
const DEFAULT_STDERR_LIMIT_BYTES = 256_000;
|
const DEFAULT_STDERR_LIMIT_BYTES = 256_000;
|
||||||
|
const WINDOWS_BATCH_EXTENSIONS = new Set(['.cmd', '.bat']);
|
||||||
|
|
||||||
|
export function resolveOpenCodeBridgeProcessCwd(
|
||||||
|
binaryPath: string,
|
||||||
|
requestedCwd: string,
|
||||||
|
platform: NodeJS.Platform = process.platform
|
||||||
|
): string {
|
||||||
|
if (platform !== 'win32') {
|
||||||
|
return requestedCwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
const extension = path.win32.extname(binaryPath).toLowerCase();
|
||||||
|
if (!WINDOWS_BATCH_EXTENSIONS.has(extension)) {
|
||||||
|
return requestedCwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
const launcherDirectory = path.win32.dirname(binaryPath);
|
||||||
|
return launcherDirectory && launcherDirectory !== '.' ? launcherDirectory : requestedCwd;
|
||||||
|
}
|
||||||
|
|
||||||
export class ExecCliOpenCodeBridgeProcessRunner implements OpenCodeBridgeProcessRunner {
|
export class ExecCliOpenCodeBridgeProcessRunner implements OpenCodeBridgeProcessRunner {
|
||||||
async run(input: OpenCodeBridgeProcessRunInput): Promise<OpenCodeBridgeProcessRunResult> {
|
async run(input: OpenCodeBridgeProcessRunInput): Promise<OpenCodeBridgeProcessRunResult> {
|
||||||
|
|
@ -146,7 +165,7 @@ export class OpenCodeBridgeCommandClient {
|
||||||
const processResult = await this.processRunner.run({
|
const processResult = await this.processRunner.run({
|
||||||
binaryPath: this.binaryPath,
|
binaryPath: this.binaryPath,
|
||||||
args: ['runtime', 'opencode-command', '--json', '--input', inputPath],
|
args: ['runtime', 'opencode-command', '--json', '--input', inputPath],
|
||||||
cwd: options.cwd,
|
cwd: resolveOpenCodeBridgeProcessCwd(this.binaryPath, options.cwd),
|
||||||
timeoutMs: options.timeoutMs,
|
timeoutMs: options.timeoutMs,
|
||||||
stdoutLimitBytes: options.stdoutLimitBytes ?? DEFAULT_STDOUT_LIMIT_BYTES,
|
stdoutLimitBytes: options.stdoutLimitBytes ?? DEFAULT_STDOUT_LIMIT_BYTES,
|
||||||
stderrLimitBytes: options.stderrLimitBytes ?? DEFAULT_STDERR_LIMIT_BYTES,
|
stderrLimitBytes: options.stderrLimitBytes ?? DEFAULT_STDERR_LIMIT_BYTES,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
const DISABLED_HTTP_MCP_VALUES = new Set(['0', 'false', 'no', 'off']);
|
||||||
|
|
||||||
|
const LOCAL_MCP_LAUNCH_ENV_KEYS = [
|
||||||
|
'CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_COMMAND',
|
||||||
|
'CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ENTRY',
|
||||||
|
'CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ARGS_JSON',
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export interface OpenCodeMcpHttpBridgeEnv {
|
||||||
|
CLAUDE_TEAM_OPENCODE_MCP_HTTP?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isOpenCodeMcpHttpBridgeEnabled(
|
||||||
|
env: OpenCodeMcpHttpBridgeEnv = process.env
|
||||||
|
): boolean {
|
||||||
|
const rawValue = env.CLAUDE_TEAM_OPENCODE_MCP_HTTP?.trim().toLowerCase();
|
||||||
|
return rawValue ? !DISABLED_HTTP_MCP_VALUES.has(rawValue) : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearOpenCodeLocalMcpLaunchEnv(env: NodeJS.ProcessEnv): void {
|
||||||
|
for (const key of LOCAL_MCP_LAUNCH_ENV_KEYS) {
|
||||||
|
delete env[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
import {
|
import {
|
||||||
OpenCodeBridgeCommandClient,
|
OpenCodeBridgeCommandClient,
|
||||||
redactBridgeDiagnosticText,
|
redactBridgeDiagnosticText,
|
||||||
|
resolveOpenCodeBridgeProcessCwd,
|
||||||
type OpenCodeBridgeDiagnosticsSink,
|
type OpenCodeBridgeDiagnosticsSink,
|
||||||
type OpenCodeBridgeProcessRunInput,
|
type OpenCodeBridgeProcessRunInput,
|
||||||
type OpenCodeBridgeProcessRunResult,
|
type OpenCodeBridgeProcessRunResult,
|
||||||
|
|
@ -41,10 +42,14 @@ describe('OpenCodeBridgeCommandClient', () => {
|
||||||
};
|
};
|
||||||
const client = createClient();
|
const client = createClient();
|
||||||
|
|
||||||
const result = await client.execute('opencode.launchTeam', { runId: 'run-1' }, {
|
const result = await client.execute(
|
||||||
cwd: '/tmp/project',
|
'opencode.launchTeam',
|
||||||
timeoutMs: 10_000,
|
{ runId: 'run-1' },
|
||||||
});
|
{
|
||||||
|
cwd: '/tmp/project',
|
||||||
|
timeoutMs: 10_000,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
expect(result).toMatchObject({
|
expect(result).toMatchObject({
|
||||||
ok: true,
|
ok: true,
|
||||||
|
|
@ -83,10 +88,14 @@ describe('OpenCodeBridgeCommandClient', () => {
|
||||||
};
|
};
|
||||||
const client = createClient();
|
const client = createClient();
|
||||||
|
|
||||||
const result = await client.execute('opencode.launchTeam', { runId: 'run-1' }, {
|
const result = await client.execute(
|
||||||
cwd: '/tmp/project',
|
'opencode.launchTeam',
|
||||||
timeoutMs: 10_000,
|
{ runId: 'run-1' },
|
||||||
});
|
{
|
||||||
|
cwd: '/tmp/project',
|
||||||
|
timeoutMs: 10_000,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
expect(result).toMatchObject({
|
expect(result).toMatchObject({
|
||||||
ok: false,
|
ok: false,
|
||||||
|
|
@ -116,10 +125,14 @@ describe('OpenCodeBridgeCommandClient', () => {
|
||||||
};
|
};
|
||||||
const client = createClient();
|
const client = createClient();
|
||||||
|
|
||||||
const result = await client.execute('opencode.launchTeam', { runId: 'run-1' }, {
|
const result = await client.execute(
|
||||||
cwd: '/tmp/project',
|
'opencode.launchTeam',
|
||||||
timeoutMs: 10_000,
|
{ runId: 'run-1' },
|
||||||
});
|
{
|
||||||
|
cwd: '/tmp/project',
|
||||||
|
timeoutMs: 10_000,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
expect(result).toMatchObject({
|
expect(result).toMatchObject({
|
||||||
ok: false,
|
ok: false,
|
||||||
|
|
@ -148,10 +161,14 @@ describe('OpenCodeBridgeCommandClient', () => {
|
||||||
};
|
};
|
||||||
const client = createClient();
|
const client = createClient();
|
||||||
|
|
||||||
const result = await client.execute('opencode.launchTeam', { runId: 'run-1' }, {
|
const result = await client.execute(
|
||||||
cwd: '/tmp/project',
|
'opencode.launchTeam',
|
||||||
timeoutMs: 10_000,
|
{ runId: 'run-1' },
|
||||||
});
|
{
|
||||||
|
cwd: '/tmp/project',
|
||||||
|
timeoutMs: 10_000,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
expect(result).toMatchObject({
|
expect(result).toMatchObject({
|
||||||
ok: false,
|
ok: false,
|
||||||
|
|
@ -175,10 +192,14 @@ describe('OpenCodeBridgeCommandClient', () => {
|
||||||
};
|
};
|
||||||
const client = createClient();
|
const client = createClient();
|
||||||
|
|
||||||
const result = await client.execute('opencode.launchTeam', { runId: 'run-1' }, {
|
const result = await client.execute(
|
||||||
cwd: '/tmp/project',
|
'opencode.launchTeam',
|
||||||
timeoutMs: 10_000,
|
{ runId: 'run-1' },
|
||||||
});
|
{
|
||||||
|
cwd: '/tmp/project',
|
||||||
|
timeoutMs: 10_000,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
expect(result).toMatchObject({
|
expect(result).toMatchObject({
|
||||||
ok: false,
|
ok: false,
|
||||||
|
|
@ -208,14 +229,22 @@ describe('OpenCodeBridgeCommandClient', () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await client.execute('opencode.launchTeam', { runId: 'run-1' }, {
|
await client.execute(
|
||||||
cwd: '/tmp/project',
|
'opencode.launchTeam',
|
||||||
timeoutMs: 10_000,
|
{ runId: 'run-1' },
|
||||||
});
|
{
|
||||||
await client.execute('opencode.launchTeam', { runId: 'run-2' }, {
|
cwd: '/tmp/project',
|
||||||
cwd: '/tmp/project',
|
timeoutMs: 10_000,
|
||||||
timeoutMs: 10_000,
|
}
|
||||||
});
|
);
|
||||||
|
await client.execute(
|
||||||
|
'opencode.launchTeam',
|
||||||
|
{ runId: 'run-2' },
|
||||||
|
{
|
||||||
|
cwd: '/tmp/project',
|
||||||
|
timeoutMs: 10_000,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
expect(runner.calls[0].env).toMatchObject({
|
expect(runner.calls[0].env).toMatchObject({
|
||||||
CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL: 'http://127.0.0.1:5001/mcp',
|
CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL: 'http://127.0.0.1:5001/mcp',
|
||||||
|
|
@ -226,6 +255,36 @@ describe('OpenCodeBridgeCommandClient', () => {
|
||||||
OPENCODE_DISABLE_AUTOUPDATE: '1',
|
OPENCODE_DISABLE_AUTOUPDATE: '1',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('runs Windows batch launchers from their launcher directory while preserving envelope cwd', async () => {
|
||||||
|
runner.nextResult = {
|
||||||
|
stdout: `${JSON.stringify(bridgeSuccess({ data: { runId: 'run-1' } }))}\n`,
|
||||||
|
stderr: '',
|
||||||
|
exitCode: 0,
|
||||||
|
timedOut: false,
|
||||||
|
};
|
||||||
|
const client = createClient({
|
||||||
|
binaryPath: 'C:\\runtime\\agent_teams_orchestrator\\cli-dev.cmd',
|
||||||
|
});
|
||||||
|
|
||||||
|
await client.execute(
|
||||||
|
'opencode.launchTeam',
|
||||||
|
{ runId: 'run-1' },
|
||||||
|
{
|
||||||
|
cwd: 'C:\\projects\\team workspace',
|
||||||
|
timeoutMs: 10_000,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(runner.calls[0].cwd).toBe(
|
||||||
|
process.platform === 'win32'
|
||||||
|
? 'C:\\runtime\\agent_teams_orchestrator'
|
||||||
|
: 'C:\\projects\\team workspace'
|
||||||
|
);
|
||||||
|
expect(JSON.parse(await runner.readInputEnvelope(0))).toMatchObject({
|
||||||
|
cwd: 'C:\\projects\\team workspace',
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('redactBridgeDiagnosticText', () => {
|
describe('redactBridgeDiagnosticText', () => {
|
||||||
|
|
@ -242,6 +301,34 @@ describe('redactBridgeDiagnosticText', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('resolveOpenCodeBridgeProcessCwd', () => {
|
||||||
|
it('keeps non-Windows launchers on the requested project cwd', () => {
|
||||||
|
expect(
|
||||||
|
resolveOpenCodeBridgeProcessCwd('/usr/local/bin/claude-multimodel', '/repo', 'linux')
|
||||||
|
).toBe('/repo');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses the launcher directory for Windows batch launchers', () => {
|
||||||
|
expect(
|
||||||
|
resolveOpenCodeBridgeProcessCwd(
|
||||||
|
'C:\\runtime\\agent_teams_orchestrator\\cli-dev.cmd',
|
||||||
|
'C:\\projects\\team workspace',
|
||||||
|
'win32'
|
||||||
|
)
|
||||||
|
).toBe('C:\\runtime\\agent_teams_orchestrator');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps Windows exe launchers on the requested project cwd', () => {
|
||||||
|
expect(
|
||||||
|
resolveOpenCodeBridgeProcessCwd(
|
||||||
|
'C:\\runtime-cache\\claude-multimodel.exe',
|
||||||
|
'C:\\projects\\team workspace',
|
||||||
|
'win32'
|
||||||
|
)
|
||||||
|
).toBe('C:\\projects\\team workspace');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
function createClient(
|
function createClient(
|
||||||
overrides: Partial<ConstructorParameters<typeof OpenCodeBridgeCommandClient>[0]> = {}
|
overrides: Partial<ConstructorParameters<typeof OpenCodeBridgeCommandClient>[0]> = {}
|
||||||
): OpenCodeBridgeCommandClient {
|
): OpenCodeBridgeCommandClient {
|
||||||
|
|
|
||||||
38
test/main/services/team/OpenCodeMcpBridgeEnv.test.ts
Normal file
38
test/main/services/team/OpenCodeMcpBridgeEnv.test.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
import {
|
||||||
|
clearOpenCodeLocalMcpLaunchEnv,
|
||||||
|
isOpenCodeMcpHttpBridgeEnabled,
|
||||||
|
} from '@main/services/team/opencode/bridge/OpenCodeMcpBridgeEnv';
|
||||||
|
|
||||||
|
describe('OpenCodeMcpBridgeEnv', () => {
|
||||||
|
it('uses the app-owned HTTP MCP bridge by default', () => {
|
||||||
|
expect(isOpenCodeMcpHttpBridgeEnabled({})).toBe(true);
|
||||||
|
expect(isOpenCodeMcpHttpBridgeEnabled({ CLAUDE_TEAM_OPENCODE_MCP_HTTP: '1' })).toBe(true);
|
||||||
|
expect(isOpenCodeMcpHttpBridgeEnabled({ CLAUDE_TEAM_OPENCODE_MCP_HTTP: 'true' })).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps the legacy local MCP command path behind an explicit opt-out', () => {
|
||||||
|
expect(isOpenCodeMcpHttpBridgeEnabled({ CLAUDE_TEAM_OPENCODE_MCP_HTTP: '0' })).toBe(false);
|
||||||
|
expect(isOpenCodeMcpHttpBridgeEnabled({ CLAUDE_TEAM_OPENCODE_MCP_HTTP: ' false ' })).toBe(
|
||||||
|
false
|
||||||
|
);
|
||||||
|
expect(isOpenCodeMcpHttpBridgeEnabled({ CLAUDE_TEAM_OPENCODE_MCP_HTTP: 'off' })).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('removes local MCP launch env when HTTP MCP is active', () => {
|
||||||
|
const env: NodeJS.ProcessEnv = {
|
||||||
|
CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_COMMAND: 'node',
|
||||||
|
CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ENTRY: 'mcp-server/dist/index.js',
|
||||||
|
CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ARGS_JSON: '["mcp-server/dist/index.js"]',
|
||||||
|
CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL: 'http://127.0.0.1:41001/mcp',
|
||||||
|
};
|
||||||
|
|
||||||
|
clearOpenCodeLocalMcpLaunchEnv(env);
|
||||||
|
|
||||||
|
expect(env.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_COMMAND).toBeUndefined();
|
||||||
|
expect(env.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ENTRY).toBeUndefined();
|
||||||
|
expect(env.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ARGS_JSON).toBeUndefined();
|
||||||
|
expect(env.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL).toBe('http://127.0.0.1:41001/mcp');
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue