xcode-copilot-server 2.0.1 → 2.1.0

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/README.md CHANGED
@@ -39,12 +39,15 @@ npx xcode-copilot-server
39
39
  xcode-copilot-server [options]
40
40
 
41
41
  Options:
42
- --port <number> Port to listen on (default: 8080)
43
- --proxy <provider> API format to expose: openai, anthropic (default: openai)
44
- --log-level <level> Log verbosity: none, error, warning, info, debug, all (default: info)
45
- --config <path> Path to config file (default: bundled config.json5)
46
- --cwd <path> Working directory for Copilot sessions (default: process cwd)
47
- --help Show help
42
+ --port <number> Port to listen on (default: 8080)
43
+ --proxy <provider> API format to expose: openai, anthropic (default: openai)
44
+ --log-level <level> Log verbosity: none, error, warning, info, debug, all (default: info)
45
+ --config <path> Path to config file (auto-detected from --cwd, then process cwd, else bundled)
46
+ --cwd <path> Working directory for Copilot sessions (default: process cwd)
47
+ --auto-patch Auto-patch settings.json on start, restore on exit (anthropic mode)
48
+ --patch-settings Patch settings.json to point to this server, then exit
49
+ --restore-settings Restore settings.json from backup, then exit
50
+ --help Show help
48
51
  ```
49
52
 
50
53
  The `--proxy` flag determines which API the server exposes:
@@ -70,7 +73,15 @@ To enable tool calling, select the provider and enable "Allow tools" under "Adva
70
73
 
71
74
  1. Open Xcode and go to Settings > Intelligence > Anthropic > Claude Agent
72
75
  2. Enable Claude Agent and sign in with an API key (the key can be any random text, since the calls are proxied through the server)
73
- 3. Create a `settings.json` file at `~/Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig/`:
76
+ 3. Start the server with `--auto-patch` to automatically configure `settings.json`:
77
+
78
+ ```bash
79
+ xcode-copilot-server --proxy anthropic --auto-patch
80
+ ```
81
+
82
+ This creates (or updates) `settings.json` at `~/Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig/` to point to the server, and restores the original file when the server shuts down. If `settings.json` already exists, a backup is saved as `settings.json.backup` and restored on exit.
83
+
84
+ Alternatively, you can manage `settings.json` yourself. Create it manually at the path above:
74
85
 
75
86
  ```json
76
87
  {
@@ -81,9 +92,13 @@ To enable tool calling, select the provider and enable "Allow tools" under "Adva
81
92
  }
82
93
  ```
83
94
 
84
- Set the port to match your `--port` flag (default 8080). The auth token can be any non-empty string.
95
+ Set the port to match your `--port` flag (default 8080). The auth token can be any non-empty string. Then start the server without `--auto-patch`:
96
+
97
+ ```bash
98
+ xcode-copilot-server --proxy anthropic
99
+ ```
85
100
 
86
- 4. Start the server: `xcode-copilot-server --proxy anthropic`
101
+ You can also use `--patch-settings` and `--restore-settings` as one-shot commands to patch or restore `settings.json` without starting the server.
87
102
 
88
103
  The tool bridge is enabled by default in Anthropic mode (`toolBridge: true` in the config). It intercepts tool calls from the Copilot session and forwards them to Xcode, so Claude Agent can read files, search code, and make edits through the IDE.
89
104
 
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ import { loadConfig, resolveConfigPath } from "./config.js";
6
6
  import { createServer } from "./server.js";
7
7
  import { Logger, LEVEL_PRIORITY } from "./logger.js";
8
8
  import { providers } from "./providers/index.js";
9
+ import { patchSettings, restoreSettings } from "./settings-patcher.js";
9
10
  const PACKAGE_ROOT = dirname(import.meta.dirname);
10
11
  const DEFAULT_CONFIG_PATH = join(PACKAGE_ROOT, "config.json5");
11
12
  const VALID_LOG_LEVELS = Object.keys(LEVEL_PRIORITY);
@@ -19,12 +20,15 @@ function isProxy(value) {
19
20
  const USAGE = `Usage: xcode-copilot-server [options]
20
21
 
21
22
  Options:
22
- --port <number> Port to listen on (default: 8080)
23
- --proxy <provider> API format to expose: ${VALID_PROXIES.join(", ")} (default: openai)
24
- --log-level <level> Log verbosity: ${VALID_LOG_LEVELS.join(", ")} (default: info)
25
- --config <path> Path to config file (auto-detected from --cwd, then process cwd, else bundled)
26
- --cwd <path> Working directory for Copilot sessions (default: process cwd)
27
- --help Show this help message`;
23
+ --port <number> Port to listen on (default: 8080)
24
+ --proxy <provider> API format to expose: ${VALID_PROXIES.join(", ")} (default: openai)
25
+ --log-level <level> Log verbosity: ${VALID_LOG_LEVELS.join(", ")} (default: info)
26
+ --config <path> Path to config file (auto-detected from --cwd, then process cwd, else bundled)
27
+ --cwd <path> Working directory for Copilot sessions (default: process cwd)
28
+ --auto-patch Auto-patch settings.json on start, restore on exit (anthropic mode)
29
+ --patch-settings Patch settings.json to point to this server, then exit
30
+ --restore-settings Restore settings.json from backup, then exit
31
+ --help Show this help message`;
28
32
  function parseCliArgs() {
29
33
  try {
30
34
  return parseArgs({
@@ -34,6 +38,9 @@ function parseCliArgs() {
34
38
  "log-level": { type: "string", default: "info" },
35
39
  config: { type: "string" },
36
40
  cwd: { type: "string" },
41
+ "auto-patch": { type: "boolean", default: false },
42
+ "patch-settings": { type: "boolean", default: false },
43
+ "restore-settings": { type: "boolean", default: false },
37
44
  help: { type: "boolean", default: false },
38
45
  },
39
46
  strict: true,
@@ -52,24 +59,32 @@ async function main() {
52
59
  console.log(USAGE);
53
60
  process.exit(0);
54
61
  }
62
+ const rawLevel = values["log-level"];
63
+ if (!isLogLevel(rawLevel)) {
64
+ console.error(`Invalid log level "${rawLevel}". Valid: ${VALID_LOG_LEVELS.join(", ")}`);
65
+ process.exit(1);
66
+ }
67
+ const logLevel = rawLevel;
68
+ const logger = new Logger(logLevel);
55
69
  const port = parseInt(values.port, 10);
56
70
  if (isNaN(port) || port < 1 || port > 65535) {
57
71
  console.error(`Invalid port "${values.port}". Must be 1-65535.`);
58
72
  process.exit(1);
59
73
  }
74
+ if (values["patch-settings"]) {
75
+ await patchSettings({ port, logger });
76
+ process.exit(0);
77
+ }
78
+ if (values["restore-settings"]) {
79
+ await restoreSettings({ logger });
80
+ process.exit(0);
81
+ }
60
82
  const proxy = values.proxy;
61
83
  if (!isProxy(proxy)) {
62
84
  console.error(`Invalid proxy "${proxy}". Valid: ${VALID_PROXIES.join(", ")}`);
63
85
  process.exit(1);
64
86
  }
65
87
  const provider = providers[proxy];
66
- const rawLevel = values["log-level"];
67
- if (!isLogLevel(rawLevel)) {
68
- console.error(`Invalid log level "${rawLevel}". Valid: ${VALID_LOG_LEVELS.join(", ")}`);
69
- process.exit(1);
70
- }
71
- const logLevel = rawLevel;
72
- const logger = new Logger(logLevel);
73
88
  const configPath = values.config ?? resolveConfigPath(values.cwd, process.cwd(), DEFAULT_CONFIG_PATH);
74
89
  const config = await loadConfig(configPath, logger, proxy);
75
90
  const cwd = values.cwd;
@@ -88,6 +103,10 @@ async function main() {
88
103
  process.exit(1);
89
104
  }
90
105
  logger.info(`Authenticated as ${auth.login ?? "unknown"} (${auth.authType ?? "unknown"})`);
106
+ const autoPatch = values["auto-patch"];
107
+ if (autoPatch) {
108
+ await patchSettings({ port, logger });
109
+ }
91
110
  const ctx = { service, logger, config, port };
92
111
  const app = await createServer(ctx, provider);
93
112
  await app.listen({ port, host: "127.0.0.1" });
@@ -97,6 +116,14 @@ async function main() {
97
116
  logger.info(`Current working directory: ${service.cwd}`);
98
117
  const shutdown = async (signal) => {
99
118
  logger.info(`Got ${signal}, shutting down...`);
119
+ if (autoPatch) {
120
+ try {
121
+ await restoreSettings({ logger });
122
+ }
123
+ catch (err) {
124
+ logger.error(`Failed to restore settings.json: ${String(err)}`);
125
+ }
126
+ }
100
127
  await app.close();
101
128
  const stopPromise = service.stop().then(() => {
102
129
  logger.info("Clean shutdown complete");
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,cAAc,EAAiB,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,SAAS,EAAkB,MAAM,sBAAsB,CAAC;AAEjE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEvE,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAClD,MAAM,mBAAmB,GAAG,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;AAE/D,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,cAAc,CAAe,CAAC;AACnE,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AAE7C,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK,IAAI,cAAc,CAAC;AACjC,CAAC;AAED,SAAS,OAAO,CAAC,KAAa;IAC5B,OAAO,KAAK,IAAI,SAAS,CAAC;AAC5B,CAAC;AAED,MAAM,KAAK,GAAG;;;;iDAImC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;0CAC/B,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;gDAMrB,CAAC;AAEjD,SAAS,YAAY;IACnB,IAAI,CAAC;QACH,OAAO,SAAS,CAAC;YACf,OAAO,EAAE;gBACP,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE;gBACzC,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE;gBAC5C,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE;gBAChD,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC1B,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACvB,YAAY,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;gBACjD,gBAAgB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;gBACrD,kBAAkB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;gBACvD,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;aAC1C;YACD,MAAM,EAAE,IAAI;YACZ,gBAAgB,EAAE,KAAK;SACxB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;QACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,EAAE,MAAM,EAAE,GAAG,YAAY,EAAE,CAAC;IAElC,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;IACrC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,KAAK,CACX,sBAAsB,QAAQ,aAAa,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACzE,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,QAAQ,GAAG,QAAQ,CAAC;IAC1B,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC;IAEpC,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACvC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QAC5C,OAAO,CAAC,KAAK,CAAC,iBAAiB,MAAM,CAAC,IAAI,qBAAqB,CAAC,CAAC;QACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAC7B,MAAM,aAAa,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,MAAM,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC/B,MAAM,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IAC3B,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CACX,kBAAkB,KAAK,aAAa,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC/D,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAElC,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,IAAI,iBAAiB,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,mBAAmB,CAAC,CAAC;IACtG,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IAC3D,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;IAEvB,MAAM,OAAO,GAAG,IAAI,cAAc,CAAC;QACjC,QAAQ;QACR,MAAM;QACN,GAAG;KACJ,CAAC,CAAC;IAEH,MAAM,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IACzC,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACtB,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAEjC,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC;IAC3C,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;QAC1B,MAAM,CAAC,KAAK,CACV,4IAA4I,CAC7I,CAAC;QACF,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,oBAAoB,IAAI,CAAC,KAAK,IAAI,SAAS,KAAK,IAAI,CAAC,QAAQ,IAAI,SAAS,GAAG,CAAC,CAAC;IAE3F,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IACvC,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,aAAa,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IACxC,CAAC;IAED,MAAM,GAAG,GAAe,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC1D,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC9C,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IAE9C,MAAM,CAAC,IAAI,CAAC,iCAAiC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7D,MAAM,CAAC,IAAI,CAAC,aAAa,QAAQ,CAAC,IAAI,aAAa,KAAK,GAAG,CAAC,CAAC;IAC7D,MAAM,CAAC,IAAI,CAAC,WAAW,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACrD,MAAM,CAAC,IAAI,CAAC,8BAA8B,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAEzD,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAE,EAAE;QACxC,MAAM,CAAC,IAAI,CAAC,OAAO,MAAM,oBAAoB,CAAC,CAAC;QAE/C,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,CAAC;gBACH,MAAM,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;YACpC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,KAAK,CAAC,oCAAoC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAClE,CAAC;QACH,CAAC;QAED,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;QAElB,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;YAC3C,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QACH,MAAM,cAAc,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CACnD,UAAU,CAAC,GAAG,EAAE;YACd,MAAM,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;YAChE,OAAO,EAAE,CAAC;QACZ,CAAC,EAAE,IAAI,CAAC,CACT,CAAC;QAEF,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { Logger } from "./logger.js";
2
+ export interface SettingsPaths {
3
+ dir: string;
4
+ file: string;
5
+ backup: string;
6
+ }
7
+ export interface Settings {
8
+ env?: Record<string, string>;
9
+ [key: string]: unknown;
10
+ }
11
+ export interface PatchResult {
12
+ patched: boolean;
13
+ port?: number;
14
+ }
15
+ interface BaseOptions {
16
+ logger: Logger;
17
+ paths?: SettingsPaths;
18
+ }
19
+ export interface PatchOptions extends BaseOptions {
20
+ port: number;
21
+ authToken?: string;
22
+ }
23
+ export type RestoreOptions = BaseOptions;
24
+ export type DetectOptions = BaseOptions;
25
+ export declare function defaultSettingsPaths(): SettingsPaths;
26
+ export declare function detectPatchState(options: DetectOptions): Promise<PatchResult>;
27
+ export declare function patchSettings(options: PatchOptions): Promise<void>;
28
+ export declare function restoreSettings(options: RestoreOptions): Promise<void>;
29
+ export {};
@@ -0,0 +1,79 @@
1
+ import { existsSync } from "node:fs";
2
+ import { readFile, writeFile, rename, unlink, mkdir, copyFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { homedir } from "node:os";
5
+ export function defaultSettingsPaths() {
6
+ const dir = join(homedir(), "Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig");
7
+ return {
8
+ dir,
9
+ file: join(dir, "settings.json"),
10
+ backup: join(dir, "settings.json.backup"),
11
+ };
12
+ }
13
+ function isSettings(value) {
14
+ return typeof value === "object" && value !== null && !Array.isArray(value);
15
+ }
16
+ async function readSettingsFile(path) {
17
+ if (!existsSync(path))
18
+ return null;
19
+ const content = await readFile(path, "utf-8");
20
+ const parsed = JSON.parse(content);
21
+ return isSettings(parsed) ? parsed : null;
22
+ }
23
+ export async function detectPatchState(options) {
24
+ const { logger } = options;
25
+ const p = options.paths ?? defaultSettingsPaths();
26
+ if (!existsSync(p.backup)) {
27
+ return { patched: false };
28
+ }
29
+ try {
30
+ const settings = await readSettingsFile(p.file);
31
+ const url = settings?.env?.ANTHROPIC_BASE_URL;
32
+ if (url) {
33
+ const match = /localhost:(\d+)/.exec(url);
34
+ if (match?.[1]) {
35
+ return { patched: true, port: parseInt(match[1], 10) };
36
+ }
37
+ }
38
+ }
39
+ catch (err) {
40
+ logger.warn(`Could not read settings.json to extract port: ${String(err)}`);
41
+ }
42
+ return { patched: true };
43
+ }
44
+ export async function patchSettings(options) {
45
+ const { logger } = options;
46
+ const p = options.paths ?? defaultSettingsPaths();
47
+ await mkdir(p.dir, { recursive: true });
48
+ // Only back up once so crash recovery doesn't overwrite the original.
49
+ if (existsSync(p.file) && !existsSync(p.backup)) {
50
+ await copyFile(p.file, p.backup);
51
+ logger.info("Backed up settings.json");
52
+ }
53
+ let settings = {};
54
+ try {
55
+ settings = await readSettingsFile(p.file) ?? {};
56
+ }
57
+ catch (err) {
58
+ logger.warn(`Could not read settings.json, starting fresh: ${String(err)}`);
59
+ }
60
+ settings.env = {
61
+ ...settings.env,
62
+ ANTHROPIC_BASE_URL: `http://localhost:${String(options.port)}`,
63
+ ANTHROPIC_AUTH_TOKEN: options.authToken ?? "12345",
64
+ };
65
+ await writeFile(p.file, JSON.stringify(settings, null, 2) + "\n", "utf-8");
66
+ logger.info(`Patched settings.json to point to http://localhost:${String(options.port)}`);
67
+ }
68
+ export async function restoreSettings(options) {
69
+ const { logger } = options;
70
+ const p = options.paths ?? defaultSettingsPaths();
71
+ if (existsSync(p.file)) {
72
+ await unlink(p.file);
73
+ }
74
+ if (existsSync(p.backup)) {
75
+ await rename(p.backup, p.file);
76
+ logger.info("Restored settings.json from backup");
77
+ }
78
+ }
79
+ //# sourceMappingURL=settings-patcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-patcher.js","sourceRoot":"","sources":["../src/settings-patcher.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xcode-copilot-server",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "OpenAI-compatible proxy API server for Xcode, powered by GitHub Copilot",
5
5
  "type": "module",
6
6
  "license": "MIT",