fix(opencode): preserve local mcp fallback
This commit is contained in:
parent
429dfe5528
commit
2c393bc78f
3 changed files with 94 additions and 13 deletions
|
|
@ -68,6 +68,12 @@ import { ChangeExtractorService } from '@main/services/team/ChangeExtractorServi
|
||||||
import { CrossTeamService } from '@main/services/team/CrossTeamService';
|
import { CrossTeamService } from '@main/services/team/CrossTeamService';
|
||||||
import { FileContentResolver } from '@main/services/team/FileContentResolver';
|
import { FileContentResolver } from '@main/services/team/FileContentResolver';
|
||||||
import { GitDiffFallback } from '@main/services/team/GitDiffFallback';
|
import { GitDiffFallback } from '@main/services/team/GitDiffFallback';
|
||||||
|
import {
|
||||||
|
clearOpenCodeLocalMcpLaunchEnv,
|
||||||
|
copyOpenCodeLocalMcpLaunchEnv,
|
||||||
|
hasOpenCodeLocalMcpLaunchEnv,
|
||||||
|
isOpenCodeMcpHttpBridgeEnabled,
|
||||||
|
} from '@main/services/team/opencode/bridge/OpenCodeMcpBridgeEnv';
|
||||||
import { ReviewApplierService } from '@main/services/team/ReviewApplierService';
|
import { ReviewApplierService } from '@main/services/team/ReviewApplierService';
|
||||||
import { TeamBackupService } from '@main/services/team/TeamBackupService';
|
import { TeamBackupService } from '@main/services/team/TeamBackupService';
|
||||||
import { TeamConfigReader } from '@main/services/team/TeamConfigReader';
|
import { TeamConfigReader } from '@main/services/team/TeamConfigReader';
|
||||||
|
|
@ -145,10 +151,6 @@ 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 {
|
||||||
|
|
@ -361,6 +363,7 @@ async function createOpenCodeRuntimeAdapterRegistry(
|
||||||
if (!useHttpMcpBridge) {
|
if (!useHttpMcpBridge) {
|
||||||
delete bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL;
|
delete bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL;
|
||||||
} else {
|
} else {
|
||||||
|
delete bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL;
|
||||||
clearOpenCodeLocalMcpLaunchEnv(bridgeEnv);
|
clearOpenCodeLocalMcpLaunchEnv(bridgeEnv);
|
||||||
}
|
}
|
||||||
const applyMcpLaunchSpecEnv = async (
|
const applyMcpLaunchSpecEnv = async (
|
||||||
|
|
@ -390,6 +393,20 @@ async function createOpenCodeRuntimeAdapterRegistry(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const ensureOpenCodeLocalMcpLaunchEnv = async (
|
||||||
|
targetEnv: NodeJS.ProcessEnv,
|
||||||
|
options: { emitProgress?: boolean } = {}
|
||||||
|
): Promise<void> => {
|
||||||
|
if (hasOpenCodeLocalMcpLaunchEnv(bridgeEnv)) {
|
||||||
|
copyOpenCodeLocalMcpLaunchEnv(bridgeEnv, targetEnv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await applyMcpLaunchSpecEnv(targetEnv, options);
|
||||||
|
if (hasOpenCodeLocalMcpLaunchEnv(targetEnv)) {
|
||||||
|
copyOpenCodeLocalMcpLaunchEnv(targetEnv, bridgeEnv);
|
||||||
|
}
|
||||||
|
};
|
||||||
try {
|
try {
|
||||||
const appManagedOpenCodeBinary = await resolveVerifiedAppManagedOpenCodeRuntimeBinaryPath();
|
const appManagedOpenCodeBinary = await resolveVerifiedAppManagedOpenCodeRuntimeBinaryPath();
|
||||||
if (appManagedOpenCodeBinary && !bridgeEnv.CLAUDE_MULTIMODEL_OPENCODE_BIN_PATH) {
|
if (appManagedOpenCodeBinary && !bridgeEnv.CLAUDE_MULTIMODEL_OPENCODE_BIN_PATH) {
|
||||||
|
|
@ -433,8 +450,8 @@ async function createOpenCodeRuntimeAdapterRegistry(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!useHttpMcpBridge && !bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL) {
|
if (!bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL) {
|
||||||
await applyMcpLaunchSpecEnv(bridgeEnv, { emitProgress: true });
|
await ensureOpenCodeLocalMcpLaunchEnv(bridgeEnv, { emitProgress: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
reportProgress('runtime-bridge', 'Preparing OpenCode bridge...');
|
reportProgress('runtime-bridge', 'Preparing OpenCode bridge...');
|
||||||
|
|
@ -453,6 +470,7 @@ async function createOpenCodeRuntimeAdapterRegistry(
|
||||||
delete bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL;
|
delete bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL;
|
||||||
delete nextEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL;
|
delete nextEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL;
|
||||||
clearOpenCodeLocalMcpLaunchEnv(nextEnv);
|
clearOpenCodeLocalMcpLaunchEnv(nextEnv);
|
||||||
|
await ensureOpenCodeLocalMcpLaunchEnv(nextEnv);
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -6,18 +6,32 @@ const LOCAL_MCP_LAUNCH_ENV_KEYS = [
|
||||||
'CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ARGS_JSON',
|
'CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ARGS_JSON',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export interface OpenCodeMcpHttpBridgeEnv {
|
export type OpenCodeMcpBridgeEnv = Record<string, string | undefined>;
|
||||||
CLAUDE_TEAM_OPENCODE_MCP_HTTP?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isOpenCodeMcpHttpBridgeEnabled(
|
export function isOpenCodeMcpHttpBridgeEnabled(env: OpenCodeMcpBridgeEnv = process.env): boolean {
|
||||||
env: OpenCodeMcpHttpBridgeEnv = process.env
|
|
||||||
): boolean {
|
|
||||||
const rawValue = env.CLAUDE_TEAM_OPENCODE_MCP_HTTP?.trim().toLowerCase();
|
const rawValue = env.CLAUDE_TEAM_OPENCODE_MCP_HTTP?.trim().toLowerCase();
|
||||||
return rawValue ? !DISABLED_HTTP_MCP_VALUES.has(rawValue) : true;
|
return rawValue ? !DISABLED_HTTP_MCP_VALUES.has(rawValue) : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clearOpenCodeLocalMcpLaunchEnv(env: NodeJS.ProcessEnv): void {
|
export function hasOpenCodeLocalMcpLaunchEnv(env: OpenCodeMcpBridgeEnv): boolean {
|
||||||
|
return LOCAL_MCP_LAUNCH_ENV_KEYS.every((key) => Boolean(env[key]?.trim()));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function copyOpenCodeLocalMcpLaunchEnv(
|
||||||
|
sourceEnv: OpenCodeMcpBridgeEnv,
|
||||||
|
targetEnv: OpenCodeMcpBridgeEnv
|
||||||
|
): void {
|
||||||
|
for (const key of LOCAL_MCP_LAUNCH_ENV_KEYS) {
|
||||||
|
const value = sourceEnv[key]?.trim();
|
||||||
|
if (value) {
|
||||||
|
targetEnv[key] = value;
|
||||||
|
} else {
|
||||||
|
delete targetEnv[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearOpenCodeLocalMcpLaunchEnv(env: OpenCodeMcpBridgeEnv): void {
|
||||||
for (const key of LOCAL_MCP_LAUNCH_ENV_KEYS) {
|
for (const key of LOCAL_MCP_LAUNCH_ENV_KEYS) {
|
||||||
delete env[key];
|
delete env[key];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@ import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
clearOpenCodeLocalMcpLaunchEnv,
|
clearOpenCodeLocalMcpLaunchEnv,
|
||||||
|
copyOpenCodeLocalMcpLaunchEnv,
|
||||||
|
hasOpenCodeLocalMcpLaunchEnv,
|
||||||
isOpenCodeMcpHttpBridgeEnabled,
|
isOpenCodeMcpHttpBridgeEnabled,
|
||||||
} from '@main/services/team/opencode/bridge/OpenCodeMcpBridgeEnv';
|
} from '@main/services/team/opencode/bridge/OpenCodeMcpBridgeEnv';
|
||||||
|
|
||||||
|
|
@ -20,6 +22,53 @@ describe('OpenCodeMcpBridgeEnv', () => {
|
||||||
expect(isOpenCodeMcpHttpBridgeEnabled({ CLAUDE_TEAM_OPENCODE_MCP_HTTP: 'off' })).toBe(false);
|
expect(isOpenCodeMcpHttpBridgeEnabled({ CLAUDE_TEAM_OPENCODE_MCP_HTTP: 'off' })).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('accepts process-style env objects', () => {
|
||||||
|
const env: NodeJS.ProcessEnv = {
|
||||||
|
PATH: '/usr/bin',
|
||||||
|
CLAUDE_TEAM_OPENCODE_MCP_HTTP: 'no',
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(isOpenCodeMcpHttpBridgeEnabled(env)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('detects complete local MCP launch env', () => {
|
||||||
|
expect(
|
||||||
|
hasOpenCodeLocalMcpLaunchEnv({
|
||||||
|
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"]',
|
||||||
|
})
|
||||||
|
).toBe(true);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
hasOpenCodeLocalMcpLaunchEnv({
|
||||||
|
CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_COMMAND: 'node',
|
||||||
|
CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ENTRY: '',
|
||||||
|
CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ARGS_JSON: '["mcp-server/dist/index.js"]',
|
||||||
|
})
|
||||||
|
).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('copies local MCP launch env for HTTP fallback without copying the HTTP URL', () => {
|
||||||
|
const target: NodeJS.ProcessEnv = {
|
||||||
|
CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL: 'http://127.0.0.1:41001/mcp',
|
||||||
|
};
|
||||||
|
|
||||||
|
copyOpenCodeLocalMcpLaunchEnv(
|
||||||
|
{
|
||||||
|
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"]',
|
||||||
|
},
|
||||||
|
target
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(target.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_COMMAND).toBe('node');
|
||||||
|
expect(target.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ENTRY).toBe('mcp-server/dist/index.js');
|
||||||
|
expect(target.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ARGS_JSON).toBe('["mcp-server/dist/index.js"]');
|
||||||
|
expect(target.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL).toBe('http://127.0.0.1:41001/mcp');
|
||||||
|
});
|
||||||
|
|
||||||
it('removes local MCP launch env when HTTP MCP is active', () => {
|
it('removes local MCP launch env when HTTP MCP is active', () => {
|
||||||
const env: NodeJS.ProcessEnv = {
|
const env: NodeJS.ProcessEnv = {
|
||||||
CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_COMMAND: 'node',
|
CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_COMMAND: 'node',
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue