xcode-copilot-server 3.4.0 → 3.4.2
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/config.json5 +2 -4
- package/dist/banner.d.ts +4 -4
- package/dist/banner.js +45 -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 +0 -1
- package/dist/cli-validators.js +2 -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 +3 -28
- package/dist/config.js +23 -62
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +1 -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 +9 -2
- package/dist/index.js.map +1 -1
- package/dist/launchd/agent.d.ts +5 -9
- package/dist/launchd/agent.js +13 -12
- 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 +4 -23
- package/dist/providers/index.js +1 -1
- 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 +2 -15
- package/dist/settings-patcher/index.js +15 -36
- 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.js +65 -139
- 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 -2
- package/dist/tool-bridge/index.js +6 -5
- 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 -3
- package/scripts/mcpbridge-proxy.mjs +0 -73
|
@@ -5,73 +5,14 @@ import { SessionLifecycle } from "./session-lifecycle.js";
|
|
|
5
5
|
export class ToolBridgeState {
|
|
6
6
|
toolCache = new ToolCache();
|
|
7
7
|
toolRouter = new ToolRouter();
|
|
8
|
-
|
|
8
|
+
replies = new ReplyTracker();
|
|
9
9
|
session = new SessionLifecycle(this.toolRouter);
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
_filteredTools;
|
|
11
|
+
get filteredTools() {
|
|
12
|
+
return this._filteredTools;
|
|
12
13
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
resolveToolName(name) {
|
|
17
|
-
return this.toolCache.resolveToolName(name);
|
|
18
|
-
}
|
|
19
|
-
normalizeArgs(toolName, args) {
|
|
20
|
-
return this.toolCache.normalizeArgs(toolName, args);
|
|
21
|
-
}
|
|
22
|
-
hasPendingToolCall(toolCallId) {
|
|
23
|
-
return this.toolRouter.hasPendingToolCall(toolCallId);
|
|
24
|
-
}
|
|
25
|
-
hasExpectedTool(name) {
|
|
26
|
-
return this.toolRouter.hasExpectedTool(name);
|
|
27
|
-
}
|
|
28
|
-
registerExpected(toolCallId, toolName) {
|
|
29
|
-
this.toolRouter.registerExpected(toolCallId, toolName);
|
|
30
|
-
}
|
|
31
|
-
registerMCPRequest(name, resolve, reject) {
|
|
32
|
-
this.toolRouter.registerMCPRequest(name, resolve, reject);
|
|
33
|
-
}
|
|
34
|
-
resolveToolCall(toolCallId, result) {
|
|
35
|
-
return this.toolRouter.resolveToolCall(toolCallId, result);
|
|
36
|
-
}
|
|
37
|
-
get hasPending() {
|
|
38
|
-
return this.toolRouter.hasPending;
|
|
39
|
-
}
|
|
40
|
-
get currentReply() {
|
|
41
|
-
return this.replyTracker.currentReply;
|
|
42
|
-
}
|
|
43
|
-
setReply(reply) {
|
|
44
|
-
this.replyTracker.setReply(reply);
|
|
45
|
-
}
|
|
46
|
-
clearReply() {
|
|
47
|
-
this.replyTracker.clearReply();
|
|
48
|
-
}
|
|
49
|
-
notifyStreamingDone() {
|
|
50
|
-
this.replyTracker.notifyStreamingDone();
|
|
51
|
-
}
|
|
52
|
-
waitForStreamingDone() {
|
|
53
|
-
return this.replyTracker.waitForStreamingDone();
|
|
54
|
-
}
|
|
55
|
-
get sessionActive() {
|
|
56
|
-
return this.session.sessionActive;
|
|
57
|
-
}
|
|
58
|
-
get hadError() {
|
|
59
|
-
return this.session.hadError;
|
|
60
|
-
}
|
|
61
|
-
markSessionActive() {
|
|
62
|
-
this.session.markSessionActive();
|
|
63
|
-
}
|
|
64
|
-
markSessionErrored() {
|
|
65
|
-
this.session.markSessionErrored();
|
|
66
|
-
}
|
|
67
|
-
markSessionInactive() {
|
|
68
|
-
this.session.markSessionInactive();
|
|
69
|
-
}
|
|
70
|
-
onSessionEnd(callback) {
|
|
71
|
-
this.session.onSessionEnd(callback);
|
|
72
|
-
}
|
|
73
|
-
cleanup() {
|
|
74
|
-
this.session.cleanup();
|
|
14
|
+
setFilteredTools(tools) {
|
|
15
|
+
this._filteredTools = tools;
|
|
75
16
|
}
|
|
76
17
|
}
|
|
77
18
|
//# sourceMappingURL=state.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/tool-bridge/state.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/tool-bridge/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,MAAM,OAAO,eAAe;IACjB,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;IAC5B,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC;IAC9B,OAAO,GAAG,IAAI,YAAY,EAAE,CAAC;IAC7B,OAAO,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACjD,cAAc,CAAwB;IAE9C,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAED,gBAAgB,CAAC,KAAgB;QAC/B,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;IAC9B,CAAC;CACF"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
const
|
|
1
|
+
const MINUTES = 60_000;
|
|
2
|
+
const TOOL_TIMEOUT_MS = 5 * MINUTES;
|
|
3
|
+
// streaming-core registers expected entries when the model emits tool requests.
|
|
4
|
+
// MCP route handlers promote them to pending when the SDK connects. Ordering is
|
|
5
|
+
// guaranteed: the client sees the tool_use block before it can POST to /mcp/:convId.
|
|
2
6
|
export class ToolRouter {
|
|
3
7
|
expectedByName = new Map();
|
|
8
|
+
// Reverse lookup: toolCallId to toolName for O(1) expected-entry removal
|
|
9
|
+
expectedByCallId = new Map();
|
|
4
10
|
pendingByCallId = new Map();
|
|
5
11
|
hasPendingToolCall(toolCallId) {
|
|
6
|
-
|
|
7
|
-
return true;
|
|
8
|
-
for (const [, queue] of this.expectedByName) {
|
|
9
|
-
if (queue.includes(toolCallId))
|
|
10
|
-
return true;
|
|
11
|
-
}
|
|
12
|
-
return false;
|
|
12
|
+
return this.pendingByCallId.has(toolCallId) || this.expectedByCallId.has(toolCallId);
|
|
13
13
|
}
|
|
14
14
|
hasExpectedTool(name) {
|
|
15
15
|
const queue = this.expectedByName.get(name);
|
|
@@ -23,6 +23,7 @@ export class ToolRouter {
|
|
|
23
23
|
else {
|
|
24
24
|
this.expectedByName.set(toolName, [toolCallId]);
|
|
25
25
|
}
|
|
26
|
+
this.expectedByCallId.set(toolCallId, toolName);
|
|
26
27
|
}
|
|
27
28
|
registerMCPRequest(name, resolve, reject) {
|
|
28
29
|
const queue = this.expectedByName.get(name);
|
|
@@ -33,8 +34,11 @@ export class ToolRouter {
|
|
|
33
34
|
const toolCallId = queue.shift();
|
|
34
35
|
if (queue.length === 0)
|
|
35
36
|
this.expectedByName.delete(name);
|
|
36
|
-
if (!toolCallId)
|
|
37
|
+
if (!toolCallId) {
|
|
38
|
+
reject(new Error(`Internal: expected toolCallId was falsy for "${name}"`));
|
|
37
39
|
return;
|
|
40
|
+
}
|
|
41
|
+
this.expectedByCallId.delete(toolCallId);
|
|
38
42
|
this.addPending(toolCallId, resolve, reject);
|
|
39
43
|
}
|
|
40
44
|
resolveToolCall(toolCallId, result) {
|
|
@@ -45,18 +49,20 @@ export class ToolRouter {
|
|
|
45
49
|
pending.resolve(result);
|
|
46
50
|
return true;
|
|
47
51
|
}
|
|
48
|
-
// The CLI
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
if (
|
|
55
|
-
queue.
|
|
52
|
+
// The CLI can resolve a tool without hitting the MCP endpoint (e.g. the tool
|
|
53
|
+
// name wasn't in tools/list). Clean up the stale expected entry.
|
|
54
|
+
const expectedName = this.expectedByCallId.get(toolCallId);
|
|
55
|
+
if (expectedName !== undefined) {
|
|
56
|
+
this.expectedByCallId.delete(toolCallId);
|
|
57
|
+
const queue = this.expectedByName.get(expectedName);
|
|
58
|
+
if (queue) {
|
|
59
|
+
const idx = queue.indexOf(toolCallId);
|
|
60
|
+
if (idx !== -1)
|
|
61
|
+
queue.splice(idx, 1);
|
|
56
62
|
if (queue.length === 0)
|
|
57
|
-
this.expectedByName.delete(
|
|
58
|
-
return true;
|
|
63
|
+
this.expectedByName.delete(expectedName);
|
|
59
64
|
}
|
|
65
|
+
return true;
|
|
60
66
|
}
|
|
61
67
|
return false;
|
|
62
68
|
}
|
|
@@ -65,6 +71,7 @@ export class ToolRouter {
|
|
|
65
71
|
}
|
|
66
72
|
rejectAll(reason) {
|
|
67
73
|
this.expectedByName.clear();
|
|
74
|
+
this.expectedByCallId.clear();
|
|
68
75
|
for (const [, pending] of this.pendingByCallId) {
|
|
69
76
|
clearTimeout(pending.timeout);
|
|
70
77
|
pending.reject(new Error(reason));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-router.js","sourceRoot":"","sources":["../../src/tool-bridge/tool-router.ts"],"names":[],"mappings":"AAAA,MAAM,
|
|
1
|
+
{"version":3,"file":"tool-router.js","sourceRoot":"","sources":["../../src/tool-bridge/tool-router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { execFile as execFileCb } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
const execFileAsync = promisify(execFileCb);
|
|
4
|
+
export async function defaultExec(cmd, args) {
|
|
5
|
+
const { stdout } = await execFileAsync(cmd, args);
|
|
6
|
+
return stdout;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=child-process.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"child-process.js","sourceRoot":"","sources":["../../src/utils/child-process.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,aAAa,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;AAI5C,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW,EAAE,IAAc;IAC3D,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAClD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export function isRecord(value) {
|
|
2
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3
|
+
}
|
|
4
|
+
export function isErrnoException(err) {
|
|
5
|
+
return err instanceof Error && "code" in err && typeof err.code === "string";
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=type-guards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-guards.js","sourceRoot":"","sources":["../../src/utils/type-guards.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAY;IAC3C,OAAO,GAAG,YAAY,KAAK,IAAI,MAAM,IAAI,GAAG,IAAI,OAAQ,GAAyB,CAAC,IAAI,KAAK,QAAQ,CAAC;AACtG,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xcode-copilot-server",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.2",
|
|
4
4
|
"description": "OpenAI-compatible proxy API server for Xcode, powered by GitHub Copilot",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -16,8 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"dist/",
|
|
19
|
-
"config.json5"
|
|
20
|
-
"scripts/"
|
|
19
|
+
"config.json5"
|
|
21
20
|
],
|
|
22
21
|
"scripts": {
|
|
23
22
|
"build": "tsc",
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* MCP stdio proxy for Apple's `xcrun mcpbridge`.
|
|
5
|
-
*
|
|
6
|
-
* mcpbridge declares output schemas on its tools but returns
|
|
7
|
-
* results via the `content` field (text array) without the corresponding
|
|
8
|
-
* `structuredContent` field that the MCP spec requires. The Copilot CLI
|
|
9
|
-
* enforces this strictly and rejects the response with error -32600.
|
|
10
|
-
*
|
|
11
|
-
* So, intercept every JSON-RPC response from mcpbridge. When a response
|
|
12
|
-
* carries `content` but no `structuredContent`, synthesise it from the
|
|
13
|
-
* first text content item — parsing as JSON when possible, falling back
|
|
14
|
-
* to a `{ text }` wrapper otherwise.
|
|
15
|
-
*
|
|
16
|
-
* Source: https://rudrank.com/exploring-xcode-using-mcp-tools-cursor-external-clients
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import { spawn, execFile } from "node:child_process";
|
|
20
|
-
import { createInterface } from "node:readline";
|
|
21
|
-
import { promisify } from "node:util";
|
|
22
|
-
|
|
23
|
-
const execFileAsync = promisify(execFile);
|
|
24
|
-
|
|
25
|
-
function patchIfNeeded(msg) {
|
|
26
|
-
const result = msg.result;
|
|
27
|
-
if (!result || typeof result !== "object") return;
|
|
28
|
-
if (!Array.isArray(result.content) || result.content.length === 0) return;
|
|
29
|
-
if (result.structuredContent !== undefined) return;
|
|
30
|
-
|
|
31
|
-
const textItem = result.content.find((c) => c.type === "text");
|
|
32
|
-
if (!textItem?.text) return;
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
result.structuredContent = JSON.parse(textItem.text);
|
|
36
|
-
} catch {
|
|
37
|
-
result.structuredContent = { text: textItem.text };
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
await execFileAsync("xcrun", ["--find", "mcpbridge"]);
|
|
43
|
-
} catch (err) {
|
|
44
|
-
console.error(
|
|
45
|
-
"Error: xcrun mcpbridge not found. This requires Xcode 26.3 or later."
|
|
46
|
-
);
|
|
47
|
-
console.error(
|
|
48
|
-
"Please install Xcode 26.3+ or remove the 'xcode' MCP server from config.json5"
|
|
49
|
-
);
|
|
50
|
-
process.exit(1);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const bridge = spawn("xcrun", ["mcpbridge", ...process.argv.slice(2)], {
|
|
54
|
-
stdio: ["pipe", "pipe", "inherit"],
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
process.stdin.pipe(bridge.stdin);
|
|
58
|
-
|
|
59
|
-
const reader = createInterface({ input: bridge.stdout, crlfDelay: Infinity });
|
|
60
|
-
|
|
61
|
-
reader.on("line", (line) => {
|
|
62
|
-
try {
|
|
63
|
-
const msg = JSON.parse(line);
|
|
64
|
-
patchIfNeeded(msg);
|
|
65
|
-
process.stdout.write(JSON.stringify(msg) + "\n");
|
|
66
|
-
} catch {
|
|
67
|
-
process.stdout.write(line + "\n");
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
bridge.on("exit", (code) => process.exit(code ?? 0));
|
|
72
|
-
process.on("SIGTERM", () => bridge.kill("SIGTERM"));
|
|
73
|
-
process.on("SIGINT", () => bridge.kill("SIGINT"));
|