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 { FileContentResolver } from '@main/services/team/FileContentResolver';
|
||||
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 { TeamBackupService } from '@main/services/team/TeamBackupService';
|
||||
import { TeamConfigReader } from '@main/services/team/TeamConfigReader';
|
||||
|
|
@ -145,10 +151,6 @@ import {
|
|||
OpenCodeBridgeCommandHandshakePort,
|
||||
} from './services/team/opencode/bridge/OpenCodeBridgeHandshakeClient';
|
||||
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 { OpenCodeRuntimeManifestEvidenceReader } from './services/team/opencode/store/OpenCodeRuntimeManifestEvidenceReader';
|
||||
import {
|
||||
|
|
@ -361,6 +363,7 @@ async function createOpenCodeRuntimeAdapterRegistry(
|
|||
if (!useHttpMcpBridge) {
|
||||
delete bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL;
|
||||
} else {
|
||||
delete bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL;
|
||||
clearOpenCodeLocalMcpLaunchEnv(bridgeEnv);
|
||||
}
|
||||
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 {
|
||||
const appManagedOpenCodeBinary = await resolveVerifiedAppManagedOpenCodeRuntimeBinaryPath();
|
||||
if (appManagedOpenCodeBinary && !bridgeEnv.CLAUDE_MULTIMODEL_OPENCODE_BIN_PATH) {
|
||||
|
|
@ -433,8 +450,8 @@ async function createOpenCodeRuntimeAdapterRegistry(
|
|||
);
|
||||
}
|
||||
}
|
||||
if (!useHttpMcpBridge && !bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL) {
|
||||
await applyMcpLaunchSpecEnv(bridgeEnv, { emitProgress: true });
|
||||
if (!bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL) {
|
||||
await ensureOpenCodeLocalMcpLaunchEnv(bridgeEnv, { emitProgress: true });
|
||||
}
|
||||
|
||||
reportProgress('runtime-bridge', 'Preparing OpenCode bridge...');
|
||||
|
|
@ -453,6 +470,7 @@ async function createOpenCodeRuntimeAdapterRegistry(
|
|||
delete bridgeEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL;
|
||||
delete nextEnv.CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_URL;
|
||||
clearOpenCodeLocalMcpLaunchEnv(nextEnv);
|
||||
await ensureOpenCodeLocalMcpLaunchEnv(nextEnv);
|
||||
logger.warn(
|
||||
`[OpenCode] Runtime adapter bridge MCP HTTP server refresh failed: ${
|
||||
error instanceof Error ? error.message : String(error)
|
||||
|
|
|
|||
|
|
@ -6,18 +6,32 @@ const LOCAL_MCP_LAUNCH_ENV_KEYS = [
|
|||
'CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_ARGS_JSON',
|
||||
] as const;
|
||||
|
||||
export interface OpenCodeMcpHttpBridgeEnv {
|
||||
CLAUDE_TEAM_OPENCODE_MCP_HTTP?: string;
|
||||
}
|
||||
export type OpenCodeMcpBridgeEnv = Record<string, string | undefined>;
|
||||
|
||||
export function isOpenCodeMcpHttpBridgeEnabled(
|
||||
env: OpenCodeMcpHttpBridgeEnv = process.env
|
||||
): boolean {
|
||||
export function isOpenCodeMcpHttpBridgeEnabled(env: OpenCodeMcpBridgeEnv = 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 {
|
||||
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) {
|
||||
delete env[key];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import { describe, expect, it } from 'vitest';
|
|||
|
||||
import {
|
||||
clearOpenCodeLocalMcpLaunchEnv,
|
||||
copyOpenCodeLocalMcpLaunchEnv,
|
||||
hasOpenCodeLocalMcpLaunchEnv,
|
||||
isOpenCodeMcpHttpBridgeEnabled,
|
||||
} from '@main/services/team/opencode/bridge/OpenCodeMcpBridgeEnv';
|
||||
|
||||
|
|
@ -20,6 +22,53 @@ describe('OpenCodeMcpBridgeEnv', () => {
|
|||
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', () => {
|
||||
const env: NodeJS.ProcessEnv = {
|
||||
CLAUDE_MULTIMODEL_AGENT_TEAMS_MCP_COMMAND: 'node',
|
||||
|
|
|
|||
Loading…
Reference in a new issue