Skip to content
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"test:unit": "bun test --isolate tests/unit",
"test:integration": "bun test tests/integration",
"test:perf": "bun test tests/unit/perf.test.ts tests/unit/utils/logger.test.ts tests/unit/proxy/prompt-builder.test.ts tests/unit/proxy/session-resume.test.ts tests/unit/proxy/incremental-prompt.test.ts tests/unit/proxy/plugin-resume.test.ts tests/unit/cursor-agent-child.test.ts tests/unit/cursor-agent-runner.test.ts tests/unit/streaming/line-buffer.test.ts tests/unit/streaming/parser.test.ts tests/unit/streaming/delta-tracker.test.ts tests/unit/streaming/openai-sse.test.ts tests/integration/sdk-demux-roundtrip.test.ts",
"test:ci:unit": "bun test --isolate tests/tools/defaults.test.ts tests/tools/executor-chain.test.ts tests/tools/sdk-executor.test.ts tests/tools/mcp-executor.test.ts tests/tools/skills.test.ts tests/tools/registry.test.ts tests/unit/cli/opencode-cursor.test.ts tests/unit/cli/cursor-bridge-install.test.ts tests/unit/cli/model-discovery.test.ts tests/unit/cursor-agent-child.test.ts tests/unit/cursor-agent-pool.test.ts tests/unit/cursor-agent-runner.test.ts tests/unit/errors.test.ts tests/unit/binary-strict.test.ts tests/unit/cursor-agent-fallback.test.ts tests/unit/models/discovery.test.ts tests/unit/proxy/bridge-json.test.ts tests/unit/proxy/prompt-builder.test.ts tests/unit/proxy/tool-loop.test.ts tests/unit/proxy/session-resume.test.ts tests/unit/proxy/incremental-prompt.test.ts tests/unit/proxy/plugin-resume.test.ts tests/unit/provider-backend.test.ts tests/unit/provider-boundary.test.ts tests/unit/provider-runtime-interception.test.ts tests/unit/provider-tool-schema-compat.test.ts tests/unit/provider-tool-loop-guard.test.ts tests/unit/mcp/tool-bridge.test.ts tests/unit/sdk-child.test.ts tests/unit/sdk-runner.test.ts tests/unit/plugin.test.ts tests/unit/plugin-tools-hook.test.ts tests/unit/plugin-tool-resolution.test.ts tests/unit/plugin-config.test.ts tests/unit/plugin-stream-extraction.test.ts tests/unit/auth.test.ts tests/unit/streaming/line-buffer.test.ts tests/unit/streaming/parser.test.ts tests/unit/streaming/types.test.ts tests/unit/streaming/delta-tracker.test.ts tests/unit/streaming/openai-sse.test.ts tests/unit/streaming/ai-sdk-parts.test.ts tests/competitive/edge.test.ts",
"test:ci:unit": "bun test --isolate tests/tools/defaults.test.ts tests/tools/executor-chain.test.ts tests/tools/sdk-executor.test.ts tests/tools/mcp-executor.test.ts tests/tools/skills.test.ts tests/tools/registry.test.ts tests/unit/cli/opencode-cursor.test.ts tests/unit/cli/cursor-bridge-install.test.ts tests/unit/cli/model-discovery.test.ts tests/unit/cursor-agent-child.test.ts tests/unit/cursor-agent-pool.test.ts tests/unit/cursor-agent-runner.test.ts tests/unit/errors.test.ts tests/unit/binary-strict.test.ts tests/unit/cursor-agent-fallback.test.ts tests/unit/models/discovery.test.ts tests/unit/proxy/bridge-json.test.ts tests/unit/proxy/prompt-builder.test.ts tests/unit/proxy/tool-loop.test.ts tests/unit/proxy/session-resume.test.ts tests/unit/proxy/incremental-prompt.test.ts tests/unit/proxy/plugin-resume.test.ts tests/unit/provider-backend.test.ts tests/unit/provider-boundary.test.ts tests/unit/provider-runtime-interception.test.ts tests/unit/provider-tool-schema-compat.test.ts tests/unit/provider-tool-loop-guard.test.ts tests/unit/mcp/tool-bridge.test.ts tests/unit/sdk-child.test.ts tests/unit/sdk-runner.test.ts tests/unit/plugin.test.ts tests/unit/plugin-system-message.test.ts tests/unit/plugin-tools-hook.test.ts tests/unit/plugin-tool-resolution.test.ts tests/unit/plugin-config.test.ts tests/unit/plugin-stream-extraction.test.ts tests/unit/auth.test.ts tests/unit/streaming/line-buffer.test.ts tests/unit/streaming/parser.test.ts tests/unit/streaming/types.test.ts tests/unit/streaming/delta-tracker.test.ts tests/unit/streaming/openai-sse.test.ts tests/unit/streaming/ai-sdk-parts.test.ts tests/competitive/edge.test.ts",
"test:ci:integration": "bun test tests/integration/comprehensive.test.ts tests/integration/tools-router.integration.test.ts tests/integration/stream-router.integration.test.ts tests/integration/opencode-loop.integration.test.ts",
"verify:issue-92": "bash scripts/verify-issue-92.sh",
"check:pricing": "bun run scripts/check-cursor-pricing-coverage.ts",
Expand Down
71 changes: 0 additions & 71 deletions src/mcp/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,77 +93,6 @@ export function readMcpConfigs(deps: ReadMcpConfigsDeps = {}): McpServerConfig[]
return configs;
}

let _subagentCache: { names: string[]; expiry: number } | null = null;
const SUBAGENT_CACHE_TTL_MS = 60_000;

/** Clear cached subagent names (for testing only). */
export function _resetSubagentCache(): void {
_subagentCache = null;
}

interface ReadSubagentNamesDeps {
configJson?: string;
existsSync?: (path: string) => boolean;
readFileSync?: (path: string, enc: BufferEncoding) => string;
env?: NodeJS.ProcessEnv;
}

export function readSubagentNames(deps: ReadSubagentNamesDeps = {}): string[] {
const useCache = deps.configJson == null;
if (useCache && _subagentCache && Date.now() < _subagentCache.expiry) {
return _subagentCache.names;
}

const result = readSubagentNamesUncached(deps);

if (useCache) {
_subagentCache = { names: result, expiry: Date.now() + SUBAGENT_CACHE_TTL_MS };
}
return result;
}

function readSubagentNamesUncached(deps: ReadSubagentNamesDeps): string[] {
let raw: string;

if (deps.configJson != null) {
raw = deps.configJson;
} else {
const exists = deps.existsSync ?? nodeExistsSync;
const readFile = deps.readFileSync ?? nodeReadFileSync;
const configPath = resolveOpenCodeConfigPath(deps.env ?? process.env);
if (!exists(configPath)) return ["general-purpose"];
try {
raw = readFile(configPath, "utf8");
} catch {
return ["general-purpose"];
}
}

let parsed: Record<string, unknown>;
try {
parsed = JSON.parse(raw);
} catch {
return ["general-purpose"];
}

const agentSection = parsed.agent;
if (!agentSection || typeof agentSection !== "object" || Array.isArray(agentSection)) {
return ["general-purpose"];
}

const agents = agentSection as Record<string, unknown>;
const names = Object.keys(agents);
if (names.length === 0) return ["general-purpose"];

const subagentNames = names.filter((name) => {
const entry = agents[name];
return entry && typeof entry === "object" && !Array.isArray(entry)
&& (entry as Record<string, unknown>).mode === "subagent";
});

return subagentNames.length > 0 ? subagentNames : names;
}

function isStringRecord(v: unknown): v is Record<string, string> {
return typeof v === "object" && v !== null && !Array.isArray(v);
}
Loading
Loading