xcode-copilot-server 3.3.2 → 3.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/banner.d.ts +4 -4
- package/dist/banner.js +48 -12
- package/dist/banner.js.map +1 -1
- package/dist/bridge-constants.d.ts +2 -0
- package/dist/bridge-constants.js +3 -0
- package/dist/bridge-constants.js.map +1 -0
- package/dist/cli-validators.d.ts +2 -2
- package/dist/cli-validators.js +7 -2
- package/dist/cli-validators.js.map +1 -1
- package/dist/config-schema.d.ts +107 -0
- package/dist/config-schema.js +53 -0
- package/dist/config-schema.js.map +1 -0
- package/dist/config.d.ts +8 -28
- package/dist/config.js +39 -60
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +3 -1
- package/dist/conversation-manager.d.ts +9 -4
- package/dist/conversation-manager.js +44 -61
- package/dist/conversation-manager.js.map +1 -1
- package/dist/index.js +31 -12
- package/dist/index.js.map +1 -1
- package/dist/launchd/agent.d.ts +9 -13
- package/dist/launchd/agent.js +33 -26
- package/dist/launchd/agent.js.map +1 -1
- package/dist/launchd/index.d.ts +3 -3
- package/dist/launchd/index.js +1 -1
- package/dist/launchd/index.js.map +1 -1
- package/dist/launchd/socket.d.ts +2 -1
- package/dist/providers/claude/provider.js +40 -64
- package/dist/providers/claude/provider.js.map +1 -1
- package/dist/providers/claude/streaming.d.ts +10 -1
- package/dist/providers/claude/streaming.js +7 -3
- package/dist/providers/claude/streaming.js.map +1 -1
- package/dist/providers/claude/tool-results.js +1 -1
- package/dist/providers/claude/tool-results.js.map +1 -1
- package/dist/providers/codex/provider.js +28 -60
- package/dist/providers/codex/provider.js.map +1 -1
- package/dist/providers/codex/streaming.d.ts +12 -3
- package/dist/providers/codex/streaming.js +6 -6
- package/dist/providers/codex/streaming.js.map +1 -1
- package/dist/providers/codex/tool-results.js +1 -1
- package/dist/providers/codex/tool-results.js.map +1 -1
- package/dist/providers/index.d.ts +5 -19
- package/dist/providers/index.js +25 -0
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/names.d.ts +4 -0
- package/dist/providers/names.js +7 -0
- package/dist/providers/names.js.map +1 -0
- package/dist/providers/openai/provider.js +5 -14
- package/dist/providers/openai/provider.js.map +1 -1
- package/dist/providers/shared/continuation.d.ts +10 -0
- package/dist/providers/shared/continuation.js +18 -0
- package/dist/providers/shared/continuation.js.map +1 -0
- package/dist/providers/shared/prompt-utils.d.ts +0 -11
- package/dist/providers/shared/prompt-utils.js +0 -11
- package/dist/providers/shared/prompt-utils.js.map +1 -1
- package/dist/providers/shared/session-config.d.ts +12 -3
- package/dist/providers/shared/session-config.js +24 -7
- package/dist/providers/shared/session-config.js.map +1 -1
- package/dist/providers/shared/streaming-core.d.ts +12 -2
- package/dist/providers/shared/streaming-core.js +183 -161
- package/dist/providers/shared/streaming-core.js.map +1 -1
- package/dist/providers/shared/streaming-orchestrator.d.ts +11 -0
- package/dist/providers/shared/streaming-orchestrator.js +11 -0
- package/dist/providers/shared/streaming-orchestrator.js.map +1 -0
- package/dist/providers/shared/user-agent-guard.d.ts +3 -0
- package/dist/providers/shared/user-agent-guard.js +17 -0
- package/dist/providers/shared/user-agent-guard.js.map +1 -0
- package/dist/settings-patcher/claude.d.ts +1 -2
- package/dist/settings-patcher/claude.js +35 -13
- package/dist/settings-patcher/claude.js.map +1 -1
- package/dist/settings-patcher/codex.d.ts +1 -20
- package/dist/settings-patcher/codex.js +58 -31
- package/dist/settings-patcher/codex.js.map +1 -1
- package/dist/settings-patcher/index.d.ts +5 -14
- package/dist/settings-patcher/index.js +26 -6
- package/dist/settings-patcher/index.js.map +1 -1
- package/dist/settings-patcher/types.d.ts +21 -0
- package/dist/settings-patcher/url-utils.d.ts +1 -0
- package/dist/settings-patcher/url-utils.js +6 -0
- package/dist/settings-patcher/url-utils.js.map +1 -0
- package/dist/shutdown.d.ts +16 -0
- package/dist/shutdown.js +53 -0
- package/dist/shutdown.js.map +1 -0
- package/dist/startup.d.ts +1 -1
- package/dist/startup.js +74 -133
- package/dist/startup.js.map +1 -1
- package/dist/tool-bridge/constants.d.ts +4 -2
- package/dist/tool-bridge/constants.js +4 -2
- package/dist/tool-bridge/constants.js.map +1 -1
- package/dist/tool-bridge/index.d.ts +2 -1
- package/dist/tool-bridge/index.js +5 -1
- package/dist/tool-bridge/index.js.map +1 -1
- package/dist/tool-bridge/routes.d.ts +2 -2
- package/dist/tool-bridge/routes.js +24 -22
- package/dist/tool-bridge/routes.js.map +1 -1
- package/dist/tool-bridge/session-lifecycle.js +6 -3
- package/dist/tool-bridge/session-lifecycle.js.map +1 -1
- package/dist/tool-bridge/state.d.ts +4 -25
- package/dist/tool-bridge/state.js +6 -65
- package/dist/tool-bridge/state.js.map +1 -1
- package/dist/tool-bridge/tool-router.d.ts +1 -0
- package/dist/tool-bridge/tool-router.js +26 -19
- package/dist/tool-bridge/tool-router.js.map +1 -1
- package/dist/utils/child-process.d.ts +2 -0
- package/dist/utils/child-process.js +8 -0
- package/dist/utils/child-process.js.map +1 -0
- package/dist/utils/type-guards.d.ts +2 -0
- package/dist/utils/type-guards.js +7 -0
- package/dist/utils/type-guards.js.map +1 -0
- package/package.json +2 -2
package/dist/startup.js
CHANGED
|
@@ -1,62 +1,44 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { providers } from "./providers/index.js";
|
|
7
|
-
import { patcherByProxy } from "./settings-patcher/index.js";
|
|
8
|
-
import { parsePort, parseLogLevel, parseProxy, parseIdleTimeout, validateAutoPatch, } from "./cli-validators.js";
|
|
1
|
+
import { CopilotService, createServer, Logger, Stats, bold, dim, createSpinner, } from "copilot-sdk-proxy";
|
|
2
|
+
import { loadConfig, loadAllProviderConfigs, resolveConfigPath } from "./config.js";
|
|
3
|
+
import { providers, createAutoProvider } from "./providers/index.js";
|
|
4
|
+
import { patchSettings } from "./settings-patcher/index.js";
|
|
5
|
+
import { parsePort, parseLogLevel, parseProxyMode, parseIdleTimeout, validateAutoPatch, } from "./cli-validators.js";
|
|
9
6
|
import { activateSocket } from "./launchd/index.js";
|
|
10
7
|
import { printProxyBanner } from "./banner.js";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
claude: "claude",
|
|
14
|
-
codex: "codex",
|
|
15
|
-
};
|
|
16
|
-
function findAgentBinary(proxy) {
|
|
17
|
-
const binaryName = AGENT_BINARY_NAMES[proxy];
|
|
18
|
-
if (!binaryName)
|
|
19
|
-
return null;
|
|
20
|
-
if (!existsSync(AGENTS_DIR))
|
|
21
|
-
return null;
|
|
22
|
-
let versions;
|
|
23
|
-
try {
|
|
24
|
-
versions = readdirSync(AGENTS_DIR);
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
for (const version of versions) {
|
|
30
|
-
const binaryPath = join(AGENTS_DIR, version, binaryName);
|
|
31
|
-
if (existsSync(binaryPath))
|
|
32
|
-
return binaryPath;
|
|
33
|
-
}
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
export async function startServer(options) {
|
|
8
|
+
import { registerShutdownHandlers } from "./shutdown.js";
|
|
9
|
+
function parseOptions(options) {
|
|
37
10
|
const logLevel = parseLogLevel(options.logLevel);
|
|
38
11
|
const logger = new Logger(logLevel);
|
|
39
12
|
const port = parsePort(options.port);
|
|
40
|
-
const
|
|
13
|
+
const proxyMode = options.proxy ? parseProxyMode(options.proxy) : "auto";
|
|
41
14
|
const idleTimeoutMinutes = options.idleTimeout ? parseIdleTimeout(options.idleTimeout) : 0;
|
|
42
15
|
const launchdMode = options.launchd === true;
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
16
|
+
const isAuto = proxyMode === "auto";
|
|
17
|
+
const shouldPatch = isAuto
|
|
18
|
+
? !launchdMode
|
|
19
|
+
: options.autoPatch === true && !launchdMode;
|
|
20
|
+
if (!isAuto && !launchdMode) {
|
|
21
|
+
validateAutoPatch(proxyMode, options.autoPatch === true);
|
|
46
22
|
}
|
|
47
|
-
const provider = providers[proxy];
|
|
48
23
|
const configPath = options.config ?? resolveConfigPath(options.cwd, process.cwd(), options.defaultConfigPath);
|
|
49
|
-
const config = await loadConfig(configPath, logger, proxy);
|
|
50
|
-
const cwd = options.cwd;
|
|
51
|
-
const service = new CopilotService({
|
|
52
|
-
logLevel,
|
|
53
|
-
logger,
|
|
54
|
-
cwd,
|
|
55
|
-
});
|
|
56
24
|
const quiet = logLevel === "none" || launchdMode;
|
|
25
|
+
return { port, proxyMode, logLevel, logger, quiet, launchdMode, shouldPatch, idleTimeoutMinutes, configPath, cwd: options.cwd };
|
|
26
|
+
}
|
|
27
|
+
async function loadProvider(parsed) {
|
|
28
|
+
const { proxyMode, configPath, logger } = parsed;
|
|
29
|
+
if (proxyMode === "auto") {
|
|
30
|
+
const allConfigs = await loadAllProviderConfigs(configPath, logger);
|
|
31
|
+
return { provider: createAutoProvider(allConfigs.providers), config: allConfigs.shared, allConfigs };
|
|
32
|
+
}
|
|
33
|
+
const config = await loadConfig(configPath, logger, proxyMode);
|
|
34
|
+
return { provider: providers[proxyMode], config };
|
|
35
|
+
}
|
|
36
|
+
async function initializeService(parsed, version) {
|
|
37
|
+
const { logLevel, logger, quiet, cwd } = parsed;
|
|
38
|
+
const service = new CopilotService({ logLevel, logger, cwd });
|
|
57
39
|
if (!quiet) {
|
|
58
40
|
console.log();
|
|
59
|
-
console.log(` ${bold("xcode-copilot-server")} ${dim(`v${
|
|
41
|
+
console.log(` ${bold("xcode-copilot-server")} ${dim(`v${version}`)}`);
|
|
60
42
|
console.log();
|
|
61
43
|
}
|
|
62
44
|
const bootSpinner = quiet ? null : createSpinner("Initialising Copilot SDK...");
|
|
@@ -66,34 +48,16 @@ export async function startServer(options) {
|
|
|
66
48
|
const auth = await service.getAuthStatus();
|
|
67
49
|
if (!auth.isAuthenticated) {
|
|
68
50
|
authSpinner?.fail("Not authenticated");
|
|
69
|
-
logger.error("Sign in with the Copilot CLI (copilot login) or GitHub CLI (gh auth login), or set a GITHUB_TOKEN environment variable.");
|
|
70
51
|
await service.stop();
|
|
71
|
-
|
|
52
|
+
throw new Error("Not authenticated. Sign in with the Copilot CLI (copilot login) or GitHub CLI (gh auth login), or set a GITHUB_TOKEN environment variable.");
|
|
72
53
|
}
|
|
73
54
|
const login = auth.login ?? "unknown";
|
|
74
55
|
const authType = auth.authType ?? "unknown";
|
|
75
56
|
authSpinner?.succeed(`Authenticated as ${bold(login)} ${dim(`(${authType})`)}`);
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
await patcher.patch({ port, logger });
|
|
82
|
-
patchSpinner?.succeed("Settings patched");
|
|
83
|
-
}
|
|
84
|
-
catch (err) {
|
|
85
|
-
patchSpinner?.fail(`Failed to patch settings: ${String(err)}`);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
const stats = new Stats();
|
|
90
|
-
const ctx = { service, logger, config, port, stats };
|
|
91
|
-
const app = await createServer(ctx, provider);
|
|
92
|
-
// Must register hooks before listen() because Fastify freezes the instance after that
|
|
93
|
-
let lastActivity = Date.now();
|
|
94
|
-
app.addHook("onResponse", () => {
|
|
95
|
-
lastActivity = Date.now();
|
|
96
|
-
});
|
|
57
|
+
return service;
|
|
58
|
+
}
|
|
59
|
+
async function bindAndListen(app, parsed) {
|
|
60
|
+
const { port, quiet, launchdMode, logger } = parsed;
|
|
97
61
|
const listenSpinner = quiet ? null : createSpinner(`Starting server on port ${String(port)}...`);
|
|
98
62
|
const prevPinoLevel = app.log.level;
|
|
99
63
|
app.log.level = "silent";
|
|
@@ -103,90 +67,67 @@ export async function startServer(options) {
|
|
|
103
67
|
if (fd === undefined) {
|
|
104
68
|
throw new Error("launch_activate_socket returned no file descriptors");
|
|
105
69
|
}
|
|
106
|
-
// TODO: Remove cast when Fastify types add fd support
|
|
107
|
-
// @ts-expect-error Fastify supports listen({ fd }) at runtime but the types don't include it yet
|
|
108
70
|
await app.listen({ fd });
|
|
109
71
|
logger.info(`Listening via launchd socket activation (fd ${String(fd)}, port ${String(port)})`);
|
|
110
72
|
}
|
|
111
73
|
else {
|
|
74
|
+
// 127.0.0.1 binding is the auth boundary. Only local processes can reach the server.
|
|
112
75
|
await app.listen({ port, host: "127.0.0.1" });
|
|
113
76
|
}
|
|
114
77
|
app.log.level = prevPinoLevel;
|
|
115
78
|
listenSpinner?.succeed(`Listening on ${bold(`http://localhost:${String(port)}`)}`);
|
|
79
|
+
}
|
|
80
|
+
function printBanner(parsed, provider, service, config, allConfigs) {
|
|
81
|
+
const { proxyMode, shouldPatch, quiet, configPath, logger } = parsed;
|
|
116
82
|
if (!quiet) {
|
|
117
|
-
const binaryName = AGENT_BINARY_NAMES[proxy];
|
|
118
83
|
printProxyBanner({
|
|
119
|
-
providerName: provider.name,
|
|
120
|
-
proxyFlag:
|
|
84
|
+
providerName: proxyMode === "auto" ? "Auto" : provider.name,
|
|
85
|
+
proxyFlag: proxyMode === "auto" ? "auto" : proxyMode,
|
|
121
86
|
routes: provider.routes,
|
|
122
87
|
cwd: service.cwd,
|
|
123
|
-
autoPatch,
|
|
124
|
-
|
|
125
|
-
agentBinaryName: binaryName,
|
|
126
|
-
agentsDir: AGENTS_DIR,
|
|
88
|
+
autoPatch: shouldPatch,
|
|
89
|
+
logger,
|
|
127
90
|
});
|
|
128
91
|
}
|
|
129
92
|
logger.debug(`Config loaded from ${configPath}`);
|
|
130
|
-
const mcpCount =
|
|
93
|
+
const mcpCount = allConfigs
|
|
94
|
+
? new Set(Object.values(allConfigs.providers).flatMap((c) => Object.keys(c.mcpServers))).size
|
|
95
|
+
: Object.keys(config.mcpServers).length;
|
|
131
96
|
const cliToolsSummary = config.allowedCliTools.includes("*")
|
|
132
97
|
? "all CLI tools allowed"
|
|
133
98
|
: `${String(config.allowedCliTools.length)} allowed CLI tool(s)`;
|
|
134
99
|
logger.debug(`${String(mcpCount)} MCP server(s), ${cliToolsSummary}`);
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
catch (err) {
|
|
148
|
-
logger.error(`Failed to restore settings: ${String(err)}`);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
100
|
+
}
|
|
101
|
+
export async function startServer(options) {
|
|
102
|
+
const parsed = parseOptions(options);
|
|
103
|
+
const { port, proxyMode, logger, shouldPatch, quiet } = parsed;
|
|
104
|
+
const { provider, config, allConfigs } = await loadProvider(parsed);
|
|
105
|
+
const service = await initializeService(parsed, options.version);
|
|
106
|
+
if (shouldPatch) {
|
|
107
|
+
const patchSpinner = quiet ? null : createSpinner("Patching settings...");
|
|
108
|
+
try {
|
|
109
|
+
await patchSettings(proxyMode, port, logger);
|
|
110
|
+
patchSpinner?.succeed("Settings patched");
|
|
151
111
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
logger.
|
|
155
|
-
});
|
|
156
|
-
const timeoutPromise = new Promise((resolve) => setTimeout(() => {
|
|
157
|
-
logger.warn("Copilot client didn't stop in time, forcing exit");
|
|
158
|
-
resolve();
|
|
159
|
-
}, 3000));
|
|
160
|
-
await Promise.race([stopPromise, timeoutPromise]);
|
|
161
|
-
if (!quiet) {
|
|
162
|
-
printUsageSummary(stats.snapshot());
|
|
112
|
+
catch (err) {
|
|
113
|
+
patchSpinner?.fail(`Failed to patch settings: ${String(err)}`);
|
|
114
|
+
logger.warn(`Settings patching failed (continuing without patch): ${String(err)}`);
|
|
163
115
|
}
|
|
164
|
-
process.exit(0);
|
|
165
|
-
};
|
|
166
|
-
let shuttingDown = false;
|
|
167
|
-
const onSignal = (signal) => {
|
|
168
|
-
if (shuttingDown)
|
|
169
|
-
return;
|
|
170
|
-
shuttingDown = true;
|
|
171
|
-
shutdown(signal).catch((err) => {
|
|
172
|
-
console.error("Shutdown error:", err);
|
|
173
|
-
process.exit(1);
|
|
174
|
-
});
|
|
175
|
-
};
|
|
176
|
-
process.on("SIGINT", () => { onSignal("SIGINT"); });
|
|
177
|
-
process.on("SIGTERM", () => { onSignal("SIGTERM"); });
|
|
178
|
-
if (idleTimeoutMinutes > 0) {
|
|
179
|
-
const idleMs = idleTimeoutMinutes * 60_000;
|
|
180
|
-
const checkInterval = Math.min(idleMs, 60_000);
|
|
181
|
-
const timer = setInterval(() => {
|
|
182
|
-
if (Date.now() - lastActivity >= idleMs) {
|
|
183
|
-
clearInterval(timer);
|
|
184
|
-
logger.info(`Idle for ${String(idleTimeoutMinutes)} minute(s), shutting down`);
|
|
185
|
-
onSignal("idle-timeout");
|
|
186
|
-
}
|
|
187
|
-
}, checkInterval);
|
|
188
|
-
// Don't let the timer alone keep the process alive
|
|
189
|
-
timer.unref();
|
|
190
116
|
}
|
|
117
|
+
const stats = new Stats();
|
|
118
|
+
const ctx = { service, logger, config, port, stats };
|
|
119
|
+
const app = await createServer(ctx, provider);
|
|
120
|
+
let lastActivity = Date.now();
|
|
121
|
+
app.addHook("onResponse", () => {
|
|
122
|
+
lastActivity = Date.now();
|
|
123
|
+
});
|
|
124
|
+
await bindAndListen(app, parsed);
|
|
125
|
+
printBanner(parsed, provider, service, config, allConfigs);
|
|
126
|
+
registerShutdownHandlers({
|
|
127
|
+
app, service, logger, stats,
|
|
128
|
+
shouldPatch, proxyMode, quiet,
|
|
129
|
+
lastActivityRef: () => lastActivity,
|
|
130
|
+
idleTimeoutMinutes: parsed.idleTimeoutMinutes,
|
|
131
|
+
});
|
|
191
132
|
}
|
|
192
133
|
//# sourceMappingURL=startup.js.map
|
package/dist/startup.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"startup.js","sourceRoot":"","sources":["../src/startup.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"startup.js","sourceRoot":"","sources":["../src/startup.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
export declare const
|
|
2
|
-
export declare const
|
|
1
|
+
export declare const JSONRPC_PARSE_ERROR = -32700;
|
|
2
|
+
export declare const JSONRPC_INVALID_PARAMS = -32602;
|
|
3
|
+
export declare const JSONRPC_METHOD_NOT_FOUND = -32601;
|
|
4
|
+
export declare const JSONRPC_INTERNAL_ERROR = -32603;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
export const
|
|
2
|
-
export const
|
|
1
|
+
export const JSONRPC_PARSE_ERROR = -32700;
|
|
2
|
+
export const JSONRPC_INVALID_PARAMS = -32602;
|
|
3
|
+
export const JSONRPC_METHOD_NOT_FOUND = -32601;
|
|
4
|
+
export const JSONRPC_INTERNAL_ERROR = -32603;
|
|
3
5
|
//# sourceMappingURL=constants.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/tool-bridge/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/tool-bridge/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,KAAK,CAAC;AAC1C,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,KAAK,CAAC;AAC7C,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,KAAK,CAAC;AAC/C,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,KAAK,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { FastifyInstance } from "fastify";
|
|
2
2
|
import type { Logger } from "copilot-sdk-proxy";
|
|
3
3
|
import { ConversationManager } from "../conversation-manager.js";
|
|
4
|
-
export { BRIDGE_SERVER_NAME, BRIDGE_TOOL_PREFIX } from "
|
|
4
|
+
export { BRIDGE_SERVER_NAME, BRIDGE_TOOL_PREFIX } from "../bridge-constants.js";
|
|
5
5
|
export declare function registerToolBridge(app: FastifyInstance, logger: Logger): ConversationManager;
|
|
6
|
+
export declare function resolveToolBridgeManager(app: FastifyInstance, existing: ConversationManager | undefined, logger: Logger): ConversationManager;
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { ConversationManager } from "../conversation-manager.js";
|
|
2
2
|
import { registerRoutes } from "./routes.js";
|
|
3
|
-
export { BRIDGE_SERVER_NAME, BRIDGE_TOOL_PREFIX } from "
|
|
3
|
+
export { BRIDGE_SERVER_NAME, BRIDGE_TOOL_PREFIX } from "../bridge-constants.js";
|
|
4
4
|
export function registerToolBridge(app, logger) {
|
|
5
5
|
const manager = new ConversationManager(logger);
|
|
6
6
|
registerRoutes(app, manager, logger);
|
|
7
7
|
return manager;
|
|
8
8
|
}
|
|
9
|
+
// Auto mode uses a shared manager; standalone mode creates one per provider.
|
|
10
|
+
export function resolveToolBridgeManager(app, existing, logger) {
|
|
11
|
+
return existing ?? registerToolBridge(app, logger);
|
|
12
|
+
}
|
|
9
13
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tool-bridge/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tool-bridge/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEhF,MAAM,UAAU,kBAAkB,CAAC,GAAoB,EAAE,MAAc;IACrE,MAAM,OAAO,GAAG,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAChD,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IACrC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,wBAAwB,CACtC,GAAoB,EACpB,QAAyC,EACzC,MAAc;IAEd,OAAO,QAAQ,IAAI,kBAAkB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AACrD,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { FastifyInstance } from "fastify";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ToolStateProvider } from "../conversation-manager.js";
|
|
3
3
|
import type { Logger } from "copilot-sdk-proxy";
|
|
4
|
-
export declare function registerRoutes(app: FastifyInstance,
|
|
4
|
+
export declare function registerRoutes(app: FastifyInstance, stateProvider: ToolStateProvider, logger: Logger): void;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { BRIDGE_SERVER_NAME } from "
|
|
2
|
+
import { BRIDGE_SERVER_NAME } from "../bridge-constants.js";
|
|
3
|
+
import { isRecord } from "../utils/type-guards.js";
|
|
4
|
+
import { JSONRPC_PARSE_ERROR, JSONRPC_INVALID_PARAMS, JSONRPC_METHOD_NOT_FOUND, JSONRPC_INTERNAL_ERROR, } from "./constants.js";
|
|
3
5
|
const JsonRpcRequestSchema = z.object({
|
|
4
6
|
jsonrpc: z.literal("2.0"),
|
|
5
7
|
id: z.union([z.number(), z.string()]).optional(),
|
|
@@ -14,17 +16,14 @@ function jsonRpcError(id, code, message) {
|
|
|
14
16
|
}
|
|
15
17
|
// Pinned to the version the Copilot SDK's MCP client actually speaks
|
|
16
18
|
const PROTOCOL_VERSION = "2024-11-05";
|
|
17
|
-
// Xcode
|
|
18
|
-
//
|
|
19
|
-
// the model as "xcode-bridge-mcp__xcode-tools__XcodeRead" which is ugly
|
|
20
|
-
// and wastes tokens.
|
|
19
|
+
// Strip Xcode's MCP prefix so the model sees clean tool names instead of
|
|
20
|
+
// double-prefixed ones like "xcode-bridge-mcp__xcode-tools__XcodeRead".
|
|
21
21
|
const MCP_TOOL_PREFIX = /^mcp__[^_]+__/;
|
|
22
22
|
function stripMCPToolPrefix(name) {
|
|
23
23
|
return name.replace(MCP_TOOL_PREFIX, "");
|
|
24
24
|
}
|
|
25
|
-
export function registerRoutes(app,
|
|
26
|
-
// The SDK opens
|
|
27
|
-
// messages. We don't push anything, so we just keep it open.
|
|
25
|
+
export function registerRoutes(app, stateProvider, logger) {
|
|
26
|
+
// The SDK opens this SSE stream after initialize. We don't push anything, just keep it open.
|
|
28
27
|
app.get("/mcp/:convId", (request, reply) => {
|
|
29
28
|
const { convId } = request.params;
|
|
30
29
|
logger.debug(`MCP ${convId}: SSE stream opened`);
|
|
@@ -41,12 +40,12 @@ export function registerRoutes(app, manager, logger) {
|
|
|
41
40
|
const { convId } = request.params;
|
|
42
41
|
const parsed = JsonRpcRequestSchema.safeParse(request.body);
|
|
43
42
|
if (!parsed.success) {
|
|
44
|
-
return reply.send(jsonRpcError(
|
|
43
|
+
return reply.send(jsonRpcError(null, JSONRPC_PARSE_ERROR, "Parse error"));
|
|
45
44
|
}
|
|
46
45
|
const msg = parsed.data;
|
|
47
46
|
logger.debug(`MCP ${convId}: method="${msg.method}", id=${String(msg.id)}`);
|
|
48
|
-
// JSON-RPC notifications have no id, so there's nothing to respond to
|
|
49
47
|
if (msg.id === undefined) {
|
|
48
|
+
logger.debug(`MCP ${convId}: notification method="${msg.method}", ignoring`);
|
|
50
49
|
return reply.status(202).send();
|
|
51
50
|
}
|
|
52
51
|
const { id, method, params } = msg;
|
|
@@ -58,12 +57,12 @@ export function registerRoutes(app, manager, logger) {
|
|
|
58
57
|
serverInfo: { name: BRIDGE_SERVER_NAME, version: "1.0.0" },
|
|
59
58
|
}));
|
|
60
59
|
case "tools/list": {
|
|
61
|
-
const state =
|
|
60
|
+
const state = stateProvider.getState(convId);
|
|
62
61
|
if (!state) {
|
|
63
62
|
logger.warn(`MCP ${convId} tools/list: conversation not found`);
|
|
64
|
-
return reply.send(jsonRpcError(id,
|
|
63
|
+
return reply.send(jsonRpcError(id, JSONRPC_INTERNAL_ERROR, "Conversation not found"));
|
|
65
64
|
}
|
|
66
|
-
const tools = state.getCachedTools().map((t) => ({
|
|
65
|
+
const tools = state.toolCache.getCachedTools().map((t) => ({
|
|
67
66
|
name: stripMCPToolPrefix(t.name),
|
|
68
67
|
description: t.description,
|
|
69
68
|
inputSchema: t.input_schema,
|
|
@@ -72,17 +71,19 @@ export function registerRoutes(app, manager, logger) {
|
|
|
72
71
|
return reply.send(jsonRpcResult(id, { tools }));
|
|
73
72
|
}
|
|
74
73
|
case "tools/call": {
|
|
75
|
-
const state =
|
|
74
|
+
const state = stateProvider.getState(convId);
|
|
76
75
|
if (!state) {
|
|
77
76
|
logger.warn(`MCP ${convId} tools/call: conversation not found`);
|
|
78
|
-
return reply.send(jsonRpcError(id,
|
|
77
|
+
return reply.send(jsonRpcError(id, JSONRPC_INTERNAL_ERROR, "Conversation not found"));
|
|
79
78
|
}
|
|
80
|
-
const
|
|
81
|
-
const
|
|
79
|
+
const rawName = params?.["name"];
|
|
80
|
+
const name = typeof rawName === "string" ? rawName : undefined;
|
|
81
|
+
const rawArgs = params?.["arguments"];
|
|
82
|
+
const args = isRecord(rawArgs) ? rawArgs : {};
|
|
82
83
|
if (!name) {
|
|
83
|
-
return reply.send(jsonRpcError(id,
|
|
84
|
+
return reply.send(jsonRpcError(id, JSONRPC_INVALID_PARAMS, "Missing tool name"));
|
|
84
85
|
}
|
|
85
|
-
const resolved = state.resolveToolName(name);
|
|
86
|
+
const resolved = state.toolCache.resolveToolName(name);
|
|
86
87
|
if (resolved !== name) {
|
|
87
88
|
logger.info(`MCP ${convId} tools/call: name="${name}" resolved to "${resolved}", args=${JSON.stringify(args)}`);
|
|
88
89
|
}
|
|
@@ -91,7 +92,7 @@ export function registerRoutes(app, manager, logger) {
|
|
|
91
92
|
}
|
|
92
93
|
try {
|
|
93
94
|
const result = await new Promise((resolve, reject) => {
|
|
94
|
-
state.registerMCPRequest(resolved, resolve, reject);
|
|
95
|
+
state.toolRouter.registerMCPRequest(resolved, resolve, reject);
|
|
95
96
|
});
|
|
96
97
|
logger.info(`MCP ${convId} tools/call resolved: name="${name}"`);
|
|
97
98
|
return await reply.send(jsonRpcResult(id, {
|
|
@@ -99,13 +100,14 @@ export function registerRoutes(app, manager, logger) {
|
|
|
99
100
|
}));
|
|
100
101
|
}
|
|
101
102
|
catch (err) {
|
|
103
|
+
logger.debug(`MCP ${convId} tools/call error details:`, err);
|
|
102
104
|
const message = err instanceof Error ? err.message : String(err);
|
|
103
105
|
logger.error(`MCP ${convId} tools/call error: ${message}`);
|
|
104
|
-
return reply.send(jsonRpcError(id,
|
|
106
|
+
return reply.send(jsonRpcError(id, JSONRPC_INTERNAL_ERROR, message));
|
|
105
107
|
}
|
|
106
108
|
}
|
|
107
109
|
default:
|
|
108
|
-
return reply.send(jsonRpcError(id,
|
|
110
|
+
return reply.send(jsonRpcError(id, JSONRPC_METHOD_NOT_FOUND, `Method not found: ${method}`));
|
|
109
111
|
}
|
|
110
112
|
});
|
|
111
113
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/tool-bridge/routes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/tool-bridge/routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,6 +13,9 @@ export class SessionLifecycle {
|
|
|
13
13
|
return this._hadError;
|
|
14
14
|
}
|
|
15
15
|
markSessionActive() {
|
|
16
|
+
// Clear leftover entries from abandoned tool cycles so they don't
|
|
17
|
+
// sit at the front of the FIFO queue and bind to wrong call IDs.
|
|
18
|
+
this.toolRouter.rejectAll("New session cycle");
|
|
16
19
|
this._sessionActive = true;
|
|
17
20
|
}
|
|
18
21
|
markSessionErrored() {
|
|
@@ -23,9 +26,9 @@ export class SessionLifecycle {
|
|
|
23
26
|
}
|
|
24
27
|
markSessionInactive() {
|
|
25
28
|
this._sessionActive = false;
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
+
// Don't reject expected entries here. handler-core's finally block
|
|
30
|
+
// calls this before the MCP tools/call request arrives, so rejecting
|
|
31
|
+
// would wipe entries the bridge still needs. cleanup() handles that.
|
|
29
32
|
this.fireSessionEnd();
|
|
30
33
|
}
|
|
31
34
|
cleanup() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-lifecycle.js","sourceRoot":"","sources":["../../src/tool-bridge/session-lifecycle.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,gBAAgB;IACV,UAAU,CAAa;IAChC,cAAc,GAAG,KAAK,CAAC;IACvB,SAAS,GAAG,KAAK,CAAC;IAClB,aAAa,GAAwB,IAAI,CAAC;IAElD,YAAY,UAAsB;QAChC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;IAC7B,CAAC;IAED,kBAAkB;QAChB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACxB,CAAC;IAED,YAAY,CAAC,QAAoB;QAC/B,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;IAChC,CAAC;IAED,mBAAmB;QACjB,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"session-lifecycle.js","sourceRoot":"","sources":["../../src/tool-bridge/session-lifecycle.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,gBAAgB;IACV,UAAU,CAAa;IAChC,cAAc,GAAG,KAAK,CAAC;IACvB,SAAS,GAAG,KAAK,CAAC;IAClB,aAAa,GAAwB,IAAI,CAAC;IAElD,YAAY,UAAsB;QAChC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,iBAAiB;QACf,kEAAkE;QAClE,iEAAiE;QACjE,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QAC/C,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;IAC7B,CAAC;IAED,kBAAkB;QAChB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACxB,CAAC;IAED,YAAY,CAAC,QAAoB;QAC/B,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;IAChC,CAAC;IAED,mBAAmB;QACjB,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;QAC5B,mEAAmE;QACnE,qEAAqE;QACrE,qEAAqE;QACrE,IAAI,CAAC,cAAc,EAAE,CAAC;IACxB,CAAC;IAED,OAAO;QACL,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;QAC5B,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAC7C,IAAI,CAAC,cAAc,EAAE,CAAC;IACxB,CAAC;IAEO,cAAc;QACpB,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,IAAI,CAAC,aAAa,EAAE,CAAC;YACrB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC5B,CAAC;IACH,CAAC;CACF"}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type { FastifyReply } from "fastify";
|
|
2
|
-
import type { AnthropicToolDefinition } from "copilot-sdk-proxy";
|
|
3
1
|
import { ToolCache } from "./tool-cache.js";
|
|
4
2
|
import { ToolRouter } from "./tool-router.js";
|
|
5
3
|
import { ReplyTracker } from "./reply-tracker.js";
|
|
@@ -7,28 +5,9 @@ import { SessionLifecycle } from "./session-lifecycle.js";
|
|
|
7
5
|
export declare class ToolBridgeState {
|
|
8
6
|
readonly toolCache: ToolCache;
|
|
9
7
|
readonly toolRouter: ToolRouter;
|
|
10
|
-
readonly
|
|
8
|
+
readonly replies: ReplyTracker;
|
|
11
9
|
readonly session: SessionLifecycle;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
normalizeArgs(toolName: string, args: Record<string, unknown>): Record<string, unknown>;
|
|
16
|
-
hasPendingToolCall(toolCallId: string): boolean;
|
|
17
|
-
hasExpectedTool(name: string): boolean;
|
|
18
|
-
registerExpected(toolCallId: string, toolName: string): void;
|
|
19
|
-
registerMCPRequest(name: string, resolve: (result: string) => void, reject: (err: Error) => void): void;
|
|
20
|
-
resolveToolCall(toolCallId: string, result: string): boolean;
|
|
21
|
-
get hasPending(): boolean;
|
|
22
|
-
get currentReply(): FastifyReply | null;
|
|
23
|
-
setReply(reply: FastifyReply): void;
|
|
24
|
-
clearReply(): void;
|
|
25
|
-
notifyStreamingDone(): void;
|
|
26
|
-
waitForStreamingDone(): Promise<void>;
|
|
27
|
-
get sessionActive(): boolean;
|
|
28
|
-
get hadError(): boolean;
|
|
29
|
-
markSessionActive(): void;
|
|
30
|
-
markSessionErrored(): void;
|
|
31
|
-
markSessionInactive(): void;
|
|
32
|
-
onSessionEnd(callback: () => void): void;
|
|
33
|
-
cleanup(): void;
|
|
10
|
+
private _filteredTools;
|
|
11
|
+
get filteredTools(): unknown[] | undefined;
|
|
12
|
+
setFilteredTools(tools: unknown[]): void;
|
|
34
13
|
}
|