oh-my-opencode 5.0.0-beta.80 → 5.0.0-beta.81

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.
Files changed (83) hide show
  1. package/dist/cli/index.js +6830 -3346
  2. package/dist/cli-node/index.js +6830 -3346
  3. package/dist/features/team-mode/tools/lifecycle-inline-spec.d.ts +1 -1
  4. package/dist/index.js +4304 -1671
  5. package/dist/oh-my-opencode.schema.json +3 -7
  6. package/dist/skills/frontend/SKILL.md +1 -0
  7. package/dist/skills/frontend/references/design/README.md +3 -2
  8. package/dist/skills/frontend/references/design/design-system-architecture.md +1 -0
  9. package/dist/skills/frontend/references/perfection/README.md +1 -0
  10. package/dist/skills/ultimate-browsing/engine/templates/package.json +1 -1
  11. package/dist/tui.js +2546 -1338
  12. package/package.json +31 -29
  13. package/packages/lsp-daemon/dist/cli.js +591 -555
  14. package/packages/lsp-daemon/dist/client.js +34 -5
  15. package/packages/lsp-daemon/dist/daemon-client.d.ts +2 -0
  16. package/packages/lsp-daemon/dist/daemon-client.js +20 -3
  17. package/packages/lsp-daemon/dist/ensure-daemon.js +17 -3
  18. package/packages/lsp-daemon/dist/index.js +34 -5
  19. package/packages/lsp-daemon/package.json +4 -3
  20. package/packages/lsp-tools-mcp/package.json +4 -3
  21. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  22. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +2537 -1310
  23. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  24. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  25. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  26. package/packages/omo-codex/plugin/components/comment-checker/package.json +5 -4
  27. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  28. package/packages/omo-codex/plugin/components/git-bash/package.json +2 -2
  29. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  30. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +5 -4
  31. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
  32. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +34 -5
  33. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  34. package/packages/omo-codex/plugin/components/lsp/package.json +5 -4
  35. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  36. package/packages/omo-codex/plugin/components/rules/package.json +5 -4
  37. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  38. package/packages/omo-codex/plugin/components/teammode/package.json +4 -3
  39. package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +4944 -2767
  40. package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +4944 -2767
  41. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  42. package/packages/omo-codex/plugin/components/telemetry/package.json +5 -4
  43. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  44. package/packages/omo-codex/plugin/components/ultrawork/package.json +5 -4
  45. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  46. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +5 -4
  47. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  48. package/packages/omo-codex/plugin/components/ulw-loop/package.json +5 -4
  49. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  50. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  51. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  52. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  53. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  54. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  55. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  56. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  57. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  58. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  59. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  60. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  61. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  62. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  63. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  64. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  65. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  66. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  67. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  68. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  69. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  70. package/packages/omo-codex/plugin/package-lock.json +481 -322
  71. package/packages/omo-codex/plugin/package.json +5 -1
  72. package/packages/omo-codex/plugin/shared/package.json +1 -1
  73. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +1 -0
  74. package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +3 -2
  75. package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +1 -0
  76. package/packages/omo-codex/plugin/skills/frontend/references/perfection/README.md +1 -0
  77. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/package.json +1 -1
  78. package/packages/omo-codex/scripts/install-dist/install-local.mjs +7594 -4136
  79. package/packages/shared-skills/skills/frontend/SKILL.md +1 -0
  80. package/packages/shared-skills/skills/frontend/references/design/README.md +3 -2
  81. package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +1 -0
  82. package/packages/shared-skills/skills/frontend/references/perfection/README.md +1 -0
  83. package/packages/shared-skills/skills/ultimate-browsing/engine/templates/package.json +1 -1
@@ -3,14 +3,450 @@
3
3
  // src/cli.ts
4
4
  import { argv, stderr } from "node:process";
5
5
 
6
- // src/proxy.ts
7
- import { existsSync as existsSync13, realpathSync as realpathSync6 } from "node:fs";
8
- import { basename as basename4, delimiter as delimiter4, dirname as dirname11, isAbsolute as isAbsolute6 } from "node:path";
6
+ // src/ownership.ts
7
+ import { randomUUID } from "node:crypto";
8
+ import { existsSync, lstatSync as lstatSync2, readFileSync as readFileSync3, statSync, unlinkSync as unlinkSync3 } from "node:fs";
9
+ import { dirname as dirname3 } from "node:path";
10
+
11
+ // src/lock.ts
12
+ import { closeSync, mkdirSync, openSync, readFileSync, unlinkSync, writeSync } from "node:fs";
13
+ import { dirname } from "node:path";
14
+ function isProcessAlive(pid) {
15
+ if (!Number.isInteger(pid) || pid <= 0)
16
+ return false;
17
+ try {
18
+ process.kill(pid, 0);
19
+ return true;
20
+ } catch (error) {
21
+ if (error instanceof Error)
22
+ return errorCode(error) === "EPERM";
23
+ throw error;
24
+ }
25
+ }
26
+ function readLockPid(lockPath) {
27
+ try {
28
+ const pid = Number.parseInt(readFileSync(lockPath, "utf8").trim(), 10);
29
+ return Number.isInteger(pid) ? pid : null;
30
+ } catch {
31
+ return null;
32
+ }
33
+ }
34
+ function tryAcquireLock(lockPath, ownerPid = process.pid) {
35
+ mkdirSync(dirname(lockPath), { recursive: true });
36
+ for (let attempt = 0;attempt < 2; attempt += 1) {
37
+ const handle = writeLockFile(lockPath, ownerPid);
38
+ if (handle)
39
+ return handle;
40
+ if (!reapStaleLock(lockPath))
41
+ return null;
42
+ }
43
+ return null;
44
+ }
45
+ function writeLockFile(lockPath, ownerPid) {
46
+ try {
47
+ const fd = openSync(lockPath, "wx", 384);
48
+ writeSync(fd, `${ownerPid}
49
+ `);
50
+ closeSync(fd);
51
+ return { release: () => unlinkQuietly(lockPath) };
52
+ } catch (error) {
53
+ if (errorCode(error) === "EEXIST")
54
+ return null;
55
+ throw error;
56
+ }
57
+ }
58
+ function reapStaleLock(lockPath) {
59
+ const pid = readLockPid(lockPath);
60
+ if (pid !== null && isProcessAlive(pid))
61
+ return false;
62
+ unlinkQuietly(lockPath);
63
+ return true;
64
+ }
65
+ function unlinkQuietly(path) {
66
+ try {
67
+ unlinkSync(path);
68
+ } catch (error) {
69
+ if (error instanceof Error)
70
+ return;
71
+ throw error;
72
+ }
73
+ }
74
+ function errorCode(error) {
75
+ if (!error || typeof error !== "object" || !("code" in error))
76
+ return;
77
+ const code = Reflect.get(error, "code");
78
+ return typeof code === "string" ? code : undefined;
79
+ }
80
+
81
+ // src/ipc-protocol.ts
82
+ import { randomBytes, timingSafeEqual } from "node:crypto";
83
+ import {
84
+ chmodSync,
85
+ closeSync as closeSync2,
86
+ constants,
87
+ fchmodSync,
88
+ fstatSync,
89
+ lstatSync,
90
+ mkdirSync as mkdirSync2,
91
+ openSync as openSync2,
92
+ readFileSync as readFileSync2,
93
+ unlinkSync as unlinkSync2,
94
+ writeSync as writeSync2
95
+ } from "node:fs";
96
+ import { dirname as dirname2 } from "node:path";
9
97
 
10
98
  // ../mcp-stdio-core/src/record.ts
11
99
  function isPlainRecord(value) {
12
100
  return typeof value === "object" && value !== null && !Array.isArray(value);
13
101
  }
102
+
103
+ // src/ipc-protocol.ts
104
+ var OMO_DAEMON_PROTOCOL_VERSION = 1;
105
+ var AUTH_ERROR_CODE = -32001;
106
+ var PROTOCOL_ERROR_CODE = -32002;
107
+ var AUTH_TOKEN_BYTES = 32;
108
+
109
+ class UnsafePrivateDirectoryError extends Error {
110
+ constructor(path, reason) {
111
+ super(`unsafe private directory ${path}: ${reason}`);
112
+ this.path = path;
113
+ this.reason = reason;
114
+ this.name = "UnsafePrivateDirectoryError";
115
+ this.code = "unsafe_private_directory";
116
+ }
117
+ }
118
+ function authEnvelope(token) {
119
+ return { protocolVersion: OMO_DAEMON_PROTOCOL_VERSION, token };
120
+ }
121
+ function readAuthToken(paths) {
122
+ try {
123
+ const token = readFileSync2(paths.auth, "utf8").trim();
124
+ return token.length > 0 ? token : null;
125
+ } catch (error) {
126
+ if (error instanceof Error)
127
+ return null;
128
+ throw error;
129
+ }
130
+ }
131
+ function readOrCreateAuthToken(paths) {
132
+ const existing = readAuthToken(paths);
133
+ if (existing)
134
+ return existing;
135
+ return createAuthToken(paths);
136
+ }
137
+ function rotateAuthToken(paths) {
138
+ try {
139
+ unlinkSync2(paths.auth);
140
+ } catch (error) {
141
+ if (!(error instanceof Error))
142
+ throw error;
143
+ }
144
+ return createAuthToken(paths);
145
+ }
146
+ function authenticateMessage(raw, expectedToken) {
147
+ const id = jsonRpcId(raw);
148
+ if (!isPlainRecord(raw))
149
+ return authError(id);
150
+ const params = raw["params"];
151
+ if (!isPlainRecord(params))
152
+ return authError(id);
153
+ const envelope = params["_omo"];
154
+ if (!isPlainRecord(envelope))
155
+ return authError(id);
156
+ const protocolVersion = envelope["protocolVersion"];
157
+ if (protocolVersion !== OMO_DAEMON_PROTOCOL_VERSION)
158
+ return protocolError(id);
159
+ const token = envelope["token"];
160
+ if (typeof token !== "string" || !tokenMatches(token, expectedToken))
161
+ return authError(id);
162
+ const cleanParams = { ...params };
163
+ delete cleanParams["_omo"];
164
+ return { input: { ...raw, params: cleanParams }, id, method: typeof raw["method"] === "string" ? raw["method"] : undefined };
165
+ }
166
+ function isAuthErrorResponse(message) {
167
+ if (!isPlainRecord(message))
168
+ return false;
169
+ const error = message["error"];
170
+ if (!isPlainRecord(error))
171
+ return false;
172
+ const data = error["data"];
173
+ return error["code"] === AUTH_ERROR_CODE && isPlainRecord(data) && data["code"] === "daemon_authentication_failed";
174
+ }
175
+ function writePrivateFile(path, data) {
176
+ const fd = openSync2(path, "w", 384);
177
+ try {
178
+ writeSync2(fd, data);
179
+ } finally {
180
+ closeSync2(fd);
181
+ }
182
+ setPrivateFileMode(path);
183
+ }
184
+ function ensurePrivateDirectory(path, options = {}) {
185
+ try {
186
+ mkdirSync2(path, { recursive: true, mode: 448 });
187
+ } catch (error) {
188
+ if (errorCode2(error) !== "EEXIST")
189
+ throw error;
190
+ }
191
+ if (process.platform === "win32")
192
+ return;
193
+ const before = validatePrivateDirectory(path, options);
194
+ const fd = openSync2(path, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
195
+ try {
196
+ fchmodSync(fd, 448);
197
+ const after = validatePrivateDirectory(path, options);
198
+ const openStats = fstatSync(fd);
199
+ if (!sameDirectory(before, after) || !sameDirectory(before, openStats)) {
200
+ throw new UnsafePrivateDirectoryError(path, "changed_during_chmod");
201
+ }
202
+ } finally {
203
+ closeSync2(fd);
204
+ }
205
+ }
206
+ function setPrivateFileMode(path) {
207
+ if (process.platform !== "win32")
208
+ chmodSync(path, 384);
209
+ }
210
+ function createAuthToken(paths) {
211
+ ensurePrivateDirectory(dirname2(paths.auth));
212
+ const token = randomBytes(AUTH_TOKEN_BYTES).toString("base64url");
213
+ let fd;
214
+ try {
215
+ fd = openSync2(paths.auth, "wx", 384);
216
+ } catch (error) {
217
+ if (errorCode2(error) === "EEXIST") {
218
+ const existing = readAuthToken(paths);
219
+ if (existing)
220
+ return existing;
221
+ }
222
+ throw error;
223
+ }
224
+ try {
225
+ writeSync2(fd, `${token}
226
+ `);
227
+ } finally {
228
+ closeSync2(fd);
229
+ }
230
+ setPrivateFileMode(paths.auth);
231
+ return token;
232
+ }
233
+ function errorCode2(error) {
234
+ if (!error || typeof error !== "object" || !("code" in error))
235
+ return;
236
+ const code = Reflect.get(error, "code");
237
+ return typeof code === "string" ? code : undefined;
238
+ }
239
+ function validatePrivateDirectory(path, options) {
240
+ const stats = options.lstat ? options.lstat(path) : lstatPrivateDirectory(path);
241
+ if (stats.isSymbolicLink())
242
+ throw new UnsafePrivateDirectoryError(path, "symlink");
243
+ if (!stats.isDirectory())
244
+ throw new UnsafePrivateDirectoryError(path, "not_directory");
245
+ const currentUid = options.currentUid ? options.currentUid() : process.getuid?.();
246
+ if (currentUid !== undefined && stats.uid !== currentUid) {
247
+ throw new UnsafePrivateDirectoryError(path, "wrong_owner");
248
+ }
249
+ return stats;
250
+ }
251
+ function lstatPrivateDirectory(path) {
252
+ return lstatSync(path);
253
+ }
254
+ function sameDirectory(a, b) {
255
+ return a.dev === b.dev && a.ino === b.ino;
256
+ }
257
+ function tokenMatches(candidate, expected) {
258
+ const candidateBytes = Buffer.from(candidate);
259
+ const expectedBytes = Buffer.from(expected);
260
+ return candidateBytes.length === expectedBytes.length && timingSafeEqual(candidateBytes, expectedBytes);
261
+ }
262
+ function jsonRpcId(raw) {
263
+ if (!isPlainRecord(raw))
264
+ return null;
265
+ const id = raw["id"];
266
+ return typeof id === "string" || typeof id === "number" || id === null ? id : null;
267
+ }
268
+ function authError(id) {
269
+ return {
270
+ jsonrpc: "2.0",
271
+ id,
272
+ error: { code: AUTH_ERROR_CODE, message: "daemon authentication failed", data: { code: "daemon_authentication_failed" } }
273
+ };
274
+ }
275
+ function protocolError(id) {
276
+ return {
277
+ jsonrpc: "2.0",
278
+ id,
279
+ error: { code: PROTOCOL_ERROR_CODE, message: "daemon protocol mismatch", data: { code: "daemon_protocol_mismatch" } }
280
+ };
281
+ }
282
+
283
+ // src/ownership.ts
284
+ class DaemonAlreadyRunningError extends Error {
285
+ constructor() {
286
+ super(...arguments);
287
+ this.name = "DaemonAlreadyRunningError";
288
+ this.code = "daemon_already_running";
289
+ }
290
+ }
291
+
292
+ class DaemonStartupDeferredError extends Error {
293
+ constructor(reason) {
294
+ super(`LSP daemon startup deferred: ${reason}`);
295
+ this.reason = reason;
296
+ this.name = "DaemonStartupDeferredError";
297
+ this.code = "daemon_startup_deferred";
298
+ }
299
+ }
300
+ async function acquireStartupLease(paths, pingOwner) {
301
+ ensureDaemonDirectories(paths);
302
+ const lock = tryAcquireLock(paths.lock);
303
+ if (!lock) {
304
+ const token = readAuthToken(paths);
305
+ if (token && await pingOwner(token))
306
+ throw new DaemonAlreadyRunningError("LSP daemon already running");
307
+ throw new DaemonStartupDeferredError("startup_lock_busy");
308
+ }
309
+ try {
310
+ const token = await validateExistingOwner(paths, pingOwner);
311
+ return { lock, token, owner: newOwner(paths) };
312
+ } catch (error) {
313
+ lock.release();
314
+ throw error;
315
+ }
316
+ }
317
+ function ensureDaemonDirectories(paths) {
318
+ ensurePrivateDirectory(paths.dir);
319
+ if (process.platform !== "win32")
320
+ ensurePrivateDirectory(dirname3(paths.socket));
321
+ }
322
+ function readDaemonOwner(paths) {
323
+ try {
324
+ return parseOwner(JSON.parse(readFileSync3(paths.owner, "utf8")));
325
+ } catch (error) {
326
+ if (error instanceof Error)
327
+ return null;
328
+ throw error;
329
+ }
330
+ }
331
+ function writeDaemonOwner(paths, owner) {
332
+ writePrivateFile(paths.pid, `${owner.pid}
333
+ `);
334
+ writePrivateFile(paths.endpoint, owner.endpoint.path);
335
+ writePrivateFile(paths.owner, `${JSON.stringify(owner)}
336
+ `);
337
+ }
338
+ function removeDaemonMetadataForOwner(paths, owner) {
339
+ const current = readDaemonOwner(paths);
340
+ if (!current || !sameOwner(current, owner))
341
+ return;
342
+ unlinkQuietly(paths.socket);
343
+ unlinkQuietly(paths.pid);
344
+ unlinkQuietly(paths.endpoint);
345
+ unlinkQuietly(paths.owner);
346
+ }
347
+ function endpointIdentity(endpointPath) {
348
+ if (process.platform === "win32")
349
+ return { kind: "windows", path: endpointPath };
350
+ try {
351
+ const stats = statSync(endpointPath);
352
+ return { kind: "unix", path: endpointPath, dev: stats.dev, ino: stats.ino };
353
+ } catch (error) {
354
+ if (error instanceof Error)
355
+ return { kind: "missing", path: endpointPath };
356
+ throw error;
357
+ }
358
+ }
359
+ function sameEndpoint(a, b) {
360
+ if (a.kind !== b.kind || a.path !== b.path)
361
+ return false;
362
+ switch (a.kind) {
363
+ case "unix":
364
+ return b.kind === "unix" && a.dev === b.dev && a.ino === b.ino;
365
+ case "windows":
366
+ return true;
367
+ case "missing":
368
+ return true;
369
+ }
370
+ }
371
+ function sameOwner(a, b) {
372
+ return a.pid === b.pid && a.nonce === b.nonce && sameEndpoint(a.endpoint, b.endpoint);
373
+ }
374
+ async function validateExistingOwner(paths, pingOwner) {
375
+ let token = readOrCreateAuthToken(paths);
376
+ for (let attempt = 0;attempt < 2; attempt += 1) {
377
+ const owner = readDaemonOwner(paths);
378
+ if (!owner)
379
+ return token;
380
+ const ping = await pingOwner(token);
381
+ if (ping && owner.nonce === ping.nonce && sameEndpoint(owner.endpoint, ping.endpoint)) {
382
+ throw new DaemonAlreadyRunningError("LSP daemon already running");
383
+ }
384
+ if (ping)
385
+ continue;
386
+ if (isProcessAlive(owner.pid))
387
+ throw new DaemonStartupDeferredError("owner_pid_live_unreachable");
388
+ const reread = readDaemonOwner(paths);
389
+ if (!reread || !sameOwner(reread, owner)) {
390
+ throw new DaemonStartupDeferredError("owner_changed_during_cleanup");
391
+ }
392
+ cleanupDeadOwner(paths, owner);
393
+ token = rotateAuthToken(paths);
394
+ return token;
395
+ }
396
+ throw new DaemonStartupDeferredError("reachable_owner_mismatch");
397
+ }
398
+ function cleanupDeadOwner(paths, owner) {
399
+ if (process.platform !== "win32" && existsSync(owner.endpoint.path)) {
400
+ const stat = lstatSync2(owner.endpoint.path);
401
+ if (stat.isSocket())
402
+ unlinkSync3(owner.endpoint.path);
403
+ }
404
+ unlinkQuietly(paths.pid);
405
+ unlinkQuietly(paths.endpoint);
406
+ unlinkQuietly(paths.owner);
407
+ }
408
+ function newOwner(paths) {
409
+ return {
410
+ pid: process.pid,
411
+ nonce: randomUUID(),
412
+ startedAt: new Date().toISOString(),
413
+ endpoint: endpointIdentity(paths.socket)
414
+ };
415
+ }
416
+ function parseOwner(value) {
417
+ if (!value || typeof value !== "object" || Array.isArray(value))
418
+ return null;
419
+ const pid = Reflect.get(value, "pid");
420
+ const nonce = Reflect.get(value, "nonce");
421
+ const startedAt = Reflect.get(value, "startedAt");
422
+ const endpoint = parseEndpoint(Reflect.get(value, "endpoint"));
423
+ if (typeof pid !== "number" || typeof nonce !== "string" || typeof startedAt !== "string" || !endpoint)
424
+ return null;
425
+ return { pid, nonce, startedAt, endpoint };
426
+ }
427
+ function parseEndpoint(value) {
428
+ if (!value || typeof value !== "object" || Array.isArray(value))
429
+ return null;
430
+ const kind = Reflect.get(value, "kind");
431
+ const path = Reflect.get(value, "path");
432
+ if (typeof path !== "string")
433
+ return null;
434
+ if (kind === undefined)
435
+ return endpointIdentity(path);
436
+ if (kind === "windows")
437
+ return { kind, path };
438
+ if (kind === "missing")
439
+ return { kind, path };
440
+ const dev = Reflect.get(value, "dev");
441
+ const ino = Reflect.get(value, "ino");
442
+ if (kind === "unix" && typeof dev === "number" && typeof ino === "number")
443
+ return { kind, path, dev, ino };
444
+ return null;
445
+ }
446
+
447
+ // src/proxy.ts
448
+ import { existsSync as existsSync14, realpathSync as realpathSync6 } from "node:fs";
449
+ import { basename as basename4, delimiter as delimiter4, dirname as dirname13, isAbsolute as isAbsolute6 } from "node:path";
14
450
  // ../mcp-stdio-core/src/responses.ts
15
451
  function successResponse(id, result) {
16
452
  return { jsonrpc: "2.0", id, result };
@@ -18,7 +454,7 @@ function successResponse(id, result) {
18
454
  function errorResponse(id, code, message, data) {
19
455
  return { jsonrpc: "2.0", id, error: data === undefined ? { code, message } : { code, message, data } };
20
456
  }
21
- function jsonRpcId(value) {
457
+ function jsonRpcId2(value) {
22
458
  return typeof value === "string" || typeof value === "number" || value === null ? value : null;
23
459
  }
24
460
  function messageFromError(error) {
@@ -169,7 +605,7 @@ function bufferFromChunk(chunk) {
169
605
  var DEFAULT_IDLE_TIMEOUT_MS = 10 * 60000;
170
606
  var DEFAULT_PARENT_POLL_INTERVAL_MS = 30000;
171
607
  var noopLog = () => {};
172
- function isProcessAlive(pid) {
608
+ function isProcessAlive2(pid) {
173
609
  try {
174
610
  process.kill(pid, 0);
175
611
  return true;
@@ -229,7 +665,7 @@ async function handleParseError(message, config, log) {
229
665
  }
230
666
  async function handleRequest(message, config, log) {
231
667
  const parsed = message.payload;
232
- const id = isPlainRecord(parsed) ? jsonRpcId(parsed["id"]) : null;
668
+ const id = isPlainRecord(parsed) ? jsonRpcId2(parsed["id"]) : null;
233
669
  const method = isPlainRecord(parsed) && typeof parsed["method"] === "string" ? parsed["method"] : null;
234
670
  log("request", { id: id === null ? null : String(id), method });
235
671
  let response;
@@ -278,7 +714,7 @@ function createParentWatchdog(config, onDeadParent) {
278
714
  if (pollIntervalMs <= 0)
279
715
  return { clear: () => {} };
280
716
  const parentPid = config.parentPid ?? process.ppid;
281
- const probeAlive = config.probeAlive ?? isProcessAlive;
717
+ const probeAlive = config.probeAlive ?? isProcessAlive2;
282
718
  let fired = false;
283
719
  const timer = setInterval(() => {
284
720
  if (fired)
@@ -320,14 +756,14 @@ function createIdleTimer(idleTimeoutMs, log, onTimeout) {
320
756
  };
321
757
  }
322
758
  // ../lsp-core/src/lsp/client-wrapper.ts
323
- import { existsSync as existsSync10, realpathSync as realpathSync5, statSync as statSync3 } from "node:fs";
324
- import { basename as basename3, dirname as dirname8, join as join5, resolve as resolve8 } from "node:path";
759
+ import { existsSync as existsSync11, realpathSync as realpathSync5, statSync as statSync4 } from "node:fs";
760
+ import { basename as basename3, dirname as dirname11, join as join5, resolve as resolve8 } from "node:path";
325
761
 
326
762
  // ../lsp-core/src/request-context.ts
327
763
  import { AsyncLocalStorage } from "node:async_hooks";
328
- import { existsSync, realpathSync, statSync } from "node:fs";
764
+ import { existsSync as existsSync2, realpathSync, statSync as statSync2 } from "node:fs";
329
765
  import { homedir } from "node:os";
330
- import { basename, delimiter, dirname, isAbsolute, join, relative, resolve } from "node:path";
766
+ import { basename, delimiter, dirname as dirname4, isAbsolute, join, relative, resolve } from "node:path";
331
767
 
332
768
  class LspRequestContextParseError extends Error {
333
769
  constructor(code, message) {
@@ -413,7 +849,7 @@ function translateHomeConfigEnv(value, home, fallback) {
413
849
  }
414
850
  function canonicalCwd(cwd) {
415
851
  const resolved = resolve(cwd);
416
- if (!existsSync(resolved) || !statSync(resolved).isDirectory()) {
852
+ if (!existsSync2(resolved) || !statSync2(resolved).isDirectory()) {
417
853
  throw new LspRequestContextParseError("invalid_cwd", `LSP request cwd must be an existing directory: ${cwd}`);
418
854
  }
419
855
  return realpathSync(resolved);
@@ -428,7 +864,7 @@ function canonicalizeExistingOrNearestAncestor(path) {
428
864
  } catch (error) {
429
865
  if (!isMissingPathError(error))
430
866
  throw error;
431
- const parent = dirname(current);
867
+ const parent = dirname4(current);
432
868
  if (parent === current)
433
869
  throw error;
434
870
  suffix.unshift(basename(current));
@@ -472,7 +908,7 @@ function isPathInside(parent, child) {
472
908
  return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute(relativePath);
473
909
  }
474
910
  function isMissingPathError(error) {
475
- const code = errorCode(error);
911
+ const code = errorCode3(error);
476
912
  return code === "ENOENT" || code === "ENOTDIR";
477
913
  }
478
914
  function rejectUnknownFields(value, allowed, scope) {
@@ -484,7 +920,7 @@ function rejectUnknownFields(value, allowed, scope) {
484
920
  function isRecord(value) {
485
921
  return typeof value === "object" && value !== null && !Array.isArray(value);
486
922
  }
487
- function errorCode(error) {
923
+ function errorCode3(error) {
488
924
  if (!error || typeof error !== "object" || !("code" in error))
489
925
  return;
490
926
  const code = Reflect.get(error, "code");
@@ -939,7 +1375,7 @@ function toError(error) {
939
1375
 
940
1376
  // ../lsp-core/src/lsp/process.ts
941
1377
  import { spawn, spawnSync } from "node:child_process";
942
- import { existsSync as existsSync2, statSync as statSync2 } from "node:fs";
1378
+ import { existsSync as existsSync3, statSync as statSync3 } from "node:fs";
943
1379
  import { delimiter as delimiter2, join as join2 } from "node:path";
944
1380
  function isMissingProcessError(error) {
945
1381
  if (!(error instanceof Error) || !("code" in error))
@@ -953,10 +1389,10 @@ function reportKillError(context, error) {
953
1389
  }
954
1390
  function validateCwd(cwd) {
955
1391
  try {
956
- if (!existsSync2(cwd)) {
1392
+ if (!existsSync3(cwd)) {
957
1393
  return { valid: false, error: `Working directory does not exist: ${cwd}` };
958
1394
  }
959
- const stats = statSync2(cwd);
1395
+ const stats = statSync3(cwd);
960
1396
  if (!stats.isDirectory()) {
961
1397
  return { valid: false, error: `Path is not a directory: ${cwd}` };
962
1398
  }
@@ -1041,7 +1477,7 @@ function resolveWindowsCommand(command, env) {
1041
1477
  for (const baseDirectory of baseDirectories) {
1042
1478
  for (const extension of extensions) {
1043
1479
  const candidate = baseDirectory ? join2(baseDirectory, `${command}${extension}`) : `${command}${extension}`;
1044
- if (existsSync2(candidate))
1480
+ if (existsSync3(candidate))
1045
1481
  return candidate;
1046
1482
  }
1047
1483
  }
@@ -1460,7 +1896,7 @@ class LspClientConnection extends LspClientTransport {
1460
1896
  }
1461
1897
 
1462
1898
  // ../lsp-core/src/lsp/workspace-document-state.ts
1463
- import { readFileSync, realpathSync as realpathSync2 } from "node:fs";
1899
+ import { readFileSync as readFileSync4, realpathSync as realpathSync2 } from "node:fs";
1464
1900
  import { relative as relative2, resolve as resolve2 } from "node:path";
1465
1901
  import { pathToFileURL as pathToFileURL2 } from "node:url";
1466
1902
 
@@ -1689,7 +2125,7 @@ class WorkspaceDocumentState {
1689
2125
  await existingOpen;
1690
2126
  return this.openFile(path);
1691
2127
  }
1692
- const text = readFileSync(path, "utf-8");
2128
+ const text = readFileSync4(path, "utf-8");
1693
2129
  const existing = this.openDocuments.get(path);
1694
2130
  if (!existing)
1695
2131
  return this.openDocumentSingleFlight(path, text);
@@ -1848,7 +2284,7 @@ class WorkspaceDocumentState {
1848
2284
  const state = this.openDocuments.get(mutation.path);
1849
2285
  if (state) {
1850
2286
  await this.closeDocument(state);
1851
- await this.openDocumentSingleFlight(mutation.path, readFileSync(mutation.path, "utf-8"));
2287
+ await this.openDocumentSingleFlight(mutation.path, readFileSync4(mutation.path, "utf-8"));
1852
2288
  } else {
1853
2289
  watched.push({ uri: pathToFileURL2(mutation.path).href, type: mutation.replaced ? 2 : 1 });
1854
2290
  }
@@ -1860,7 +2296,7 @@ class WorkspaceDocumentState {
1860
2296
  await this.closeDocument(state);
1861
2297
  for (const state of moved) {
1862
2298
  const path = movedPath(state.path, mutation.oldPath, mutation.newPath);
1863
- await this.openDocumentSingleFlight(path, readFileSync(path, "utf-8"));
2299
+ await this.openDocumentSingleFlight(path, readFileSync4(path, "utf-8"));
1864
2300
  }
1865
2301
  if (moved.length === 0) {
1866
2302
  watched.push({ uri: pathToFileURL2(mutation.oldPath).href, type: 3 });
@@ -1936,11 +2372,11 @@ function workspaceApplyEditConcurrentFailureReason(phase) {
1936
2372
  }
1937
2373
 
1938
2374
  // ../lsp-core/src/lsp/workspace-edit-commit.ts
1939
- import { existsSync as existsSync4, lstatSync as lstatSync2, renameSync, rmSync, writeFileSync } from "node:fs";
2375
+ import { existsSync as existsSync5, lstatSync as lstatSync4, renameSync, rmSync, writeFileSync } from "node:fs";
1940
2376
 
1941
2377
  // ../lsp-core/src/lsp/workspace-edit-path.ts
1942
- import { existsSync as existsSync3, lstatSync, readFileSync as readFileSync2, readdirSync, realpathSync as realpathSync3 } from "node:fs";
1943
- import { dirname as dirname2, isAbsolute as isAbsolute2, relative as relative3, resolve as resolve3 } from "node:path";
2378
+ import { existsSync as existsSync4, lstatSync as lstatSync3, readFileSync as readFileSync5, readdirSync, realpathSync as realpathSync3 } from "node:fs";
2379
+ import { dirname as dirname5, isAbsolute as isAbsolute2, relative as relative3, resolve as resolve3 } from "node:path";
1944
2380
  import { fileURLToPath } from "node:url";
1945
2381
 
1946
2382
  class WorkspaceEditPathError extends Error {
@@ -1957,8 +2393,8 @@ function isPathInsideWorkspace(filePath, workspaceRoot) {
1957
2393
  }
1958
2394
  function canonicalizeMissingPath(filePath) {
1959
2395
  let ancestor = filePath;
1960
- while (!existsSync3(ancestor)) {
1961
- const parent = dirname2(ancestor);
2396
+ while (!existsSync4(ancestor)) {
2397
+ const parent = dirname5(ancestor);
1962
2398
  if (parent === ancestor)
1963
2399
  throw new WorkspaceEditPathError(filePath, "no existing ancestor");
1964
2400
  ancestor = parent;
@@ -1968,14 +2404,14 @@ function canonicalizeMissingPath(filePath) {
1968
2404
  function canonicalWorkspaceRoot(workspaceRoot) {
1969
2405
  try {
1970
2406
  const canonical = realpathSync3(resolve3(workspaceRoot));
1971
- if (!lstatSync(canonical).isDirectory()) {
2407
+ if (!lstatSync3(canonical).isDirectory()) {
1972
2408
  return { success: false, error: `workspace root is not a directory: ${workspaceRoot}` };
1973
2409
  }
1974
2410
  return {
1975
2411
  success: true,
1976
2412
  path: canonical,
1977
2413
  requestedPath: resolve3(workspaceRoot),
1978
- followedSymbolicLink: existsSync3(resolve3(workspaceRoot)) && lstatSync(resolve3(workspaceRoot)).isSymbolicLink()
2414
+ followedSymbolicLink: existsSync4(resolve3(workspaceRoot)) && lstatSync3(resolve3(workspaceRoot)).isSymbolicLink()
1979
2415
  };
1980
2416
  } catch (error) {
1981
2417
  const detail = error instanceof Error ? error.message : String(error);
@@ -1995,7 +2431,7 @@ function uriToCanonicalWorkspacePath(uri, workspaceRoot) {
1995
2431
  return { success: false, error: `non-file URI ${uri}: ${detail}` };
1996
2432
  }
1997
2433
  try {
1998
- const canonical = existsSync3(requestedPath) ? realpathSync3(requestedPath) : canonicalizeMissingPath(requestedPath);
2434
+ const canonical = existsSync4(requestedPath) ? realpathSync3(requestedPath) : canonicalizeMissingPath(requestedPath);
1999
2435
  if (!isPathInsideWorkspace(canonical, workspaceRoot)) {
2000
2436
  return { success: false, error: `${requestedPath}: outside workspace ${workspaceRoot}` };
2001
2437
  }
@@ -2003,7 +2439,7 @@ function uriToCanonicalWorkspacePath(uri, workspaceRoot) {
2003
2439
  success: true,
2004
2440
  path: canonical,
2005
2441
  requestedPath,
2006
- followedSymbolicLink: existsSync3(requestedPath) && lstatSync(requestedPath).isSymbolicLink()
2442
+ followedSymbolicLink: existsSync4(requestedPath) && lstatSync3(requestedPath).isSymbolicLink()
2007
2443
  };
2008
2444
  } catch (error) {
2009
2445
  const detail = error instanceof Error ? error.message : String(error);
@@ -2011,11 +2447,11 @@ function uriToCanonicalWorkspacePath(uri, workspaceRoot) {
2011
2447
  }
2012
2448
  }
2013
2449
  function snapshotPath(path, includeChildren) {
2014
- if (!existsSync3(path))
2450
+ if (!existsSync4(path))
2015
2451
  return { kind: "missing" };
2016
- const stats = lstatSync(path);
2452
+ const stats = lstatSync3(path);
2017
2453
  if (stats.isFile())
2018
- return { kind: "file", content: readFileSync2(path, "utf-8") };
2454
+ return { kind: "file", content: readFileSync5(path, "utf-8") };
2019
2455
  if (stats.isDirectory()) {
2020
2456
  return includeChildren ? { kind: "directory", children: readdirSync(path).sort() } : { kind: "directory" };
2021
2457
  }
@@ -2131,7 +2567,7 @@ function commitOperation(context, operation) {
2131
2567
  }
2132
2568
  if (operation.kind === "rename") {
2133
2569
  if (operation.replaceDestination) {
2134
- const targetKind = existsSync4(operation.newPath) && lstatSync2(operation.newPath).isDirectory() ? "directory" : "file";
2570
+ const targetKind = existsSync5(operation.newPath) && lstatSync4(operation.newPath).isDirectory() ? "directory" : "file";
2135
2571
  io.remove(operation.newPath, targetKind === "directory");
2136
2572
  accumulator.mutations.push({ kind: "delete", path: operation.newPath, targetKind });
2137
2573
  addModifiedPath(accumulator.filesModified, reportedPath(plan, operation.newPath));
@@ -2495,7 +2931,7 @@ function parseDocumentChange(input) {
2495
2931
  }
2496
2932
 
2497
2933
  // ../lsp-core/src/lsp/workspace-edit-simulation.ts
2498
- import { dirname as dirname3, relative as relative4, resolve as resolve4 } from "node:path";
2934
+ import { dirname as dirname6, relative as relative4, resolve as resolve4 } from "node:path";
2499
2935
 
2500
2936
  // ../lsp-core/src/lsp/workspace-edit-text.ts
2501
2937
  function comparePosition(left, right) {
@@ -2619,7 +3055,7 @@ function virtualDirectoryHasChildren(virtual, path) {
2619
3055
  return false;
2620
3056
  }
2621
3057
  function requireVirtualParent(virtual, path, changeIndex) {
2622
- if (virtual.get(dirname3(path))?.kind !== "directory") {
3058
+ if (virtual.get(dirname6(path))?.kind !== "directory") {
2623
3059
  throw new WorkspaceEditValidationError(changeIndex, `parent directory does not exist for ${path}`);
2624
3060
  }
2625
3061
  }
@@ -2739,8 +3175,8 @@ function simulateDelete(operation, virtual) {
2739
3175
  }
2740
3176
 
2741
3177
  // ../lsp-core/src/lsp/workspace-edit-snapshot.ts
2742
- import { existsSync as existsSync5, lstatSync as lstatSync3, readdirSync as readdirSync2 } from "node:fs";
2743
- import { dirname as dirname4, resolve as resolve5 } from "node:path";
3178
+ import { existsSync as existsSync6, lstatSync as lstatSync5, readdirSync as readdirSync2 } from "node:fs";
3179
+ import { dirname as dirname7, resolve as resolve5 } from "node:path";
2744
3180
  class WorkspaceSnapshotBuilder {
2745
3181
  constructor(workspaceRoot) {
2746
3182
  this.workspaceRoot = workspaceRoot;
@@ -2774,9 +3210,9 @@ class WorkspaceSnapshotBuilder {
2774
3210
  }
2775
3211
  if (candidate === this.workspaceRoot)
2776
3212
  break;
2777
- candidate = dirname4(candidate);
3213
+ candidate = dirname7(candidate);
2778
3214
  }
2779
- if (!includeChildren || !existsSync5(path) || !lstatSync3(path).isDirectory())
3215
+ if (!includeChildren || !existsSync6(path) || !lstatSync5(path).isDirectory())
2780
3216
  return;
2781
3217
  for (const child of readdirSync2(path))
2782
3218
  this.add(resolve5(path, child), true);
@@ -3641,8 +4077,8 @@ async function disposeDefaultLspManager() {
3641
4077
  }
3642
4078
 
3643
4079
  // ../lsp-core/src/lsp/outside-context-workspace.ts
3644
- import { existsSync as existsSync6, realpathSync as realpathSync4 } from "node:fs";
3645
- import { dirname as dirname5, join as join3 } from "node:path";
4080
+ import { existsSync as existsSync7, realpathSync as realpathSync4 } from "node:fs";
4081
+ import { dirname as dirname8, join as join3 } from "node:path";
3646
4082
 
3647
4083
  // ../lsp-core/src/lsp/workspace-markers.ts
3648
4084
  var GIT_WORKSPACE_MARKER = ".git";
@@ -3666,10 +4102,10 @@ function findWorkspaceRootOutsideContext(directory) {
3666
4102
  function nearestMarkedAncestor(directory) {
3667
4103
  let current = directory;
3668
4104
  for (;; ) {
3669
- if (existsSync6(current) && WORKSPACE_MARKERS.some((marker) => existsSync6(join3(current, marker)))) {
4105
+ if (existsSync7(current) && WORKSPACE_MARKERS.some((marker) => existsSync7(join3(current, marker)))) {
3670
4106
  return realpathSync4(current);
3671
4107
  }
3672
- const parent = dirname5(current);
4108
+ const parent = dirname8(current);
3673
4109
  if (parent === current)
3674
4110
  return;
3675
4111
  current = parent;
@@ -3677,8 +4113,8 @@ function nearestMarkedAncestor(directory) {
3677
4113
  }
3678
4114
  function nearestExistingAncestor(directory) {
3679
4115
  let current = directory;
3680
- while (!existsSync6(current)) {
3681
- const parent = dirname5(current);
4116
+ while (!existsSync7(current)) {
4117
+ const parent = dirname8(current);
3682
4118
  if (parent === current)
3683
4119
  return current;
3684
4120
  current = parent;
@@ -3854,17 +4290,17 @@ var BUILTIN_SERVERS = {
3854
4290
  };
3855
4291
 
3856
4292
  // ../lsp-core/src/lsp/server-install-state.ts
3857
- import { existsSync as existsSync7, mkdirSync, readFileSync as readFileSync3, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
3858
- import { dirname as dirname6 } from "node:path";
4293
+ import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync6, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
4294
+ import { dirname as dirname9 } from "node:path";
3859
4295
  function getInstallDecisionsPath() {
3860
4296
  return lspRequestContext().installDecisionsPath;
3861
4297
  }
3862
4298
  function loadInstallDecisions() {
3863
4299
  const path = getInstallDecisionsPath();
3864
- if (!existsSync7(path))
4300
+ if (!existsSync8(path))
3865
4301
  return {};
3866
4302
  try {
3867
- const parsed = JSON.parse(readFileSync3(path, "utf8"));
4303
+ const parsed = JSON.parse(readFileSync6(path, "utf8"));
3868
4304
  return isInstallDecisions(parsed) ? parsed : {};
3869
4305
  } catch {
3870
4306
  return {};
@@ -3883,7 +4319,7 @@ function isInstallDecision(value) {
3883
4319
  }
3884
4320
  function writeInstallDecisions(decisions) {
3885
4321
  const path = getInstallDecisionsPath();
3886
- mkdirSync(dirname6(path), { recursive: true });
4322
+ mkdirSync3(dirname9(path), { recursive: true });
3887
4323
  const tmpPath = `${path}.tmp`;
3888
4324
  writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
3889
4325
  `, "utf8");
@@ -3902,7 +4338,7 @@ function isRecord5(value) {
3902
4338
  }
3903
4339
 
3904
4340
  // ../lsp-core/src/lsp/config-loader.ts
3905
- import { existsSync as existsSync8, readFileSync as readFileSync4 } from "node:fs";
4341
+ import { existsSync as existsSync9, readFileSync as readFileSync7 } from "node:fs";
3906
4342
  function getProjectConfigPaths() {
3907
4343
  return lspRequestContext().projectConfigPaths;
3908
4344
  }
@@ -3910,10 +4346,10 @@ function getUserConfigPath() {
3910
4346
  return lspRequestContext().userConfigPath;
3911
4347
  }
3912
4348
  function loadJsonFile(path) {
3913
- if (!existsSync8(path))
4349
+ if (!existsSync9(path))
3914
4350
  return null;
3915
4351
  try {
3916
- const parsed = JSON.parse(readFileSync4(path, "utf-8"));
4352
+ const parsed = JSON.parse(readFileSync7(path, "utf-8"));
3917
4353
  return isConfigJson(parsed) ? parsed : null;
3918
4354
  } catch {
3919
4355
  return null;
@@ -4098,8 +4534,8 @@ function getDisabledServerIds() {
4098
4534
  }
4099
4535
 
4100
4536
  // ../lsp-core/src/lsp/server-installation.ts
4101
- import { existsSync as existsSync9 } from "node:fs";
4102
- import { delimiter as delimiter3, dirname as dirname7, isAbsolute as isAbsolute3, join as join4, resolve as resolve7 } from "node:path";
4537
+ import { existsSync as existsSync10 } from "node:fs";
4538
+ import { delimiter as delimiter3, dirname as dirname10, isAbsolute as isAbsolute3, join as join4, resolve as resolve7 } from "node:path";
4103
4539
  var LOCAL_BIN_RULES = [
4104
4540
  {
4105
4541
  markers: ["package.json", "bun.lock", "bun.lockb", "package-lock.json", "yarn.lock", "pnpm-lock.yaml"],
@@ -4139,7 +4575,7 @@ var resolutionCache = new Map;
4139
4575
  var probeCount = 0;
4140
4576
  function probe(path) {
4141
4577
  probeCount += 1;
4142
- return existsSync9(path);
4578
+ return existsSync10(path);
4143
4579
  }
4144
4580
  function executableSuffixes(platform, pathExt) {
4145
4581
  if (platform !== "win32")
@@ -4173,7 +4609,7 @@ function resolveLocal(command, workingDirectory, suffixes, stopAt) {
4173
4609
  return null;
4174
4610
  if (boundary !== undefined && current === boundary)
4175
4611
  return null;
4176
- const parent = dirname7(current);
4612
+ const parent = dirname10(current);
4177
4613
  if (parent === current)
4178
4614
  return null;
4179
4615
  current = parent;
@@ -4328,7 +4764,7 @@ function getAllServers() {
4328
4764
  // ../lsp-core/src/lsp/client-wrapper.ts
4329
4765
  function isDirectoryPath(filePath) {
4330
4766
  try {
4331
- return statSync3(filePath).isDirectory();
4767
+ return statSync4(filePath).isDirectory();
4332
4768
  } catch {
4333
4769
  return false;
4334
4770
  }
@@ -4338,7 +4774,7 @@ function findWorkspaceRoot(filePath) {
4338
4774
  const abs = resolveReadablePathInsideContext(filePath);
4339
4775
  let dir = abs;
4340
4776
  if (!isDirectoryPath(dir)) {
4341
- dir = dirname8(dir);
4777
+ dir = dirname11(dir);
4342
4778
  }
4343
4779
  if (!isPathInside(cwd, abs))
4344
4780
  return findWorkspaceRootOutsideContext(dir);
@@ -4347,7 +4783,7 @@ function findWorkspaceRoot(filePath) {
4347
4783
  while (isPathInside(cwd, dir)) {
4348
4784
  const canonicalDir = existingDirectoryInsideContext(dir, cwd);
4349
4785
  if (canonicalDir !== undefined) {
4350
- if (existsSync10(join5(dir, GIT_WORKSPACE_MARKER))) {
4786
+ if (existsSync11(join5(dir, GIT_WORKSPACE_MARKER))) {
4351
4787
  return canonicalDir;
4352
4788
  }
4353
4789
  if (nearestPackageRoot === undefined && hasProjectWorkspaceMarker(dir)) {
@@ -4356,12 +4792,12 @@ function findWorkspaceRoot(filePath) {
4356
4792
  }
4357
4793
  if (dir === cwd)
4358
4794
  break;
4359
- dir = dirname8(dir);
4795
+ dir = dirname11(dir);
4360
4796
  }
4361
4797
  return nearestPackageRoot ?? fallbackRoot;
4362
4798
  }
4363
4799
  function hasProjectWorkspaceMarker(directory) {
4364
- return PROJECT_WORKSPACE_MARKERS.some((marker) => existsSync10(join5(directory, marker)));
4800
+ return PROJECT_WORKSPACE_MARKERS.some((marker) => existsSync11(join5(directory, marker)));
4365
4801
  }
4366
4802
  function resolveReadablePathInsideContext(filePath) {
4367
4803
  const cwd = contextCwd();
@@ -4386,12 +4822,12 @@ function rebaseThroughCanonicalAncestor(path, cwd) {
4386
4822
  let current = path;
4387
4823
  const suffix = [];
4388
4824
  while (true) {
4389
- if (existsSync10(current)) {
4825
+ if (existsSync11(current)) {
4390
4826
  const canonical = realpathSync5(current);
4391
4827
  if (isPathInside(cwd, canonical))
4392
4828
  return suffix.length === 0 ? canonical : join5(canonical, ...suffix);
4393
4829
  }
4394
- const parent = dirname8(current);
4830
+ const parent = dirname11(current);
4395
4831
  if (parent === current)
4396
4832
  return;
4397
4833
  suffix.unshift(basename3(current));
@@ -4399,10 +4835,10 @@ function rebaseThroughCanonicalAncestor(path, cwd) {
4399
4835
  }
4400
4836
  }
4401
4837
  function existingDirectoryInsideContext(directory, cwd) {
4402
- if (!existsSync10(directory))
4838
+ if (!existsSync11(directory))
4403
4839
  return;
4404
4840
  const canonical = realpathSync5(directory);
4405
- if (!statSync3(canonical).isDirectory())
4841
+ if (!statSync4(canonical).isDirectory())
4406
4842
  return;
4407
4843
  return isPathInside(cwd, canonical) ? canonical : undefined;
4408
4844
  }
@@ -4414,7 +4850,7 @@ function nearestExistingDirectoryInsideContext(directory, cwd) {
4414
4850
  return canonical;
4415
4851
  if (current === cwd)
4416
4852
  return;
4417
- current = dirname8(current);
4853
+ current = dirname11(current);
4418
4854
  }
4419
4855
  return;
4420
4856
  }
@@ -4544,7 +4980,7 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
4544
4980
  }
4545
4981
 
4546
4982
  // ../lsp-core/src/lsp/directory-diagnostics.ts
4547
- import { existsSync as existsSync11, lstatSync as lstatSync4, readdirSync as readdirSync3 } from "node:fs";
4983
+ import { existsSync as existsSync12, lstatSync as lstatSync6, readdirSync as readdirSync3 } from "node:fs";
4548
4984
  import { join as join6, resolve as resolve9 } from "node:path";
4549
4985
 
4550
4986
  // ../lsp-core/src/lsp/formatters.ts
@@ -4678,7 +5114,7 @@ function collectFilesWithExtension(dir, extension, maxFiles) {
4678
5114
  const fullPath = join6(currentDir, entry);
4679
5115
  let stat;
4680
5116
  try {
4681
- stat = lstatSync4(fullPath);
5117
+ stat = lstatSync6(fullPath);
4682
5118
  } catch {
4683
5119
  continue;
4684
5120
  }
@@ -4701,7 +5137,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
4701
5137
  throw new LspInvalidPathError(`Extension must start with a dot (e.g., ".ts", not "${extension}"). Use ".${extension}" instead.`);
4702
5138
  }
4703
5139
  const absDir = resolve9(options.workspaceRoot ?? contextCwd(), directory);
4704
- if (!existsSync11(absDir)) {
5140
+ if (!existsSync12(absDir)) {
4705
5141
  throw new LspInvalidPathError(`Directory does not exist: ${absDir}`);
4706
5142
  }
4707
5143
  const serverResult = options.server === undefined ? findServerForExtension(extension) : { status: "found", server: options.server };
@@ -4787,7 +5223,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
4787
5223
  }
4788
5224
 
4789
5225
  // ../lsp-core/src/lsp/infer-extension.ts
4790
- import { lstatSync as lstatSync5, readdirSync as readdirSync4 } from "node:fs";
5226
+ import { lstatSync as lstatSync7, readdirSync as readdirSync4 } from "node:fs";
4791
5227
  import { join as join7 } from "node:path";
4792
5228
  var SKIP_DIRECTORIES2 = new Set(["node_modules", ".git", "dist", "build", ".next", "out"]);
4793
5229
  var MAX_SCAN_ENTRIES = 500;
@@ -4809,7 +5245,7 @@ function inferExtensionFromDirectory(directory) {
4809
5245
  const fullPath = join7(dir, entry);
4810
5246
  let stat;
4811
5247
  try {
4812
- stat = lstatSync5(fullPath);
5248
+ stat = lstatSync7(fullPath);
4813
5249
  } catch {
4814
5250
  continue;
4815
5251
  }
@@ -5058,7 +5494,7 @@ async function executeLspDiagnostics(params, signal) {
5058
5494
  }
5059
5495
  }
5060
5496
  // ../lsp-core/src/lsp/format-document.ts
5061
- import { readFileSync as readFileSync5, renameSync as renameSync3, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
5497
+ import { readFileSync as readFileSync8, renameSync as renameSync3, unlinkSync as unlinkSync4, writeFileSync as writeFileSync3 } from "node:fs";
5062
5498
  var DEFAULT_FORMATTING_OPTIONS = {
5063
5499
  tabSize: 4,
5064
5500
  insertSpaces: false,
@@ -5073,7 +5509,7 @@ async function formatDocumentWithClient(client, filePath, options = {}) {
5073
5509
  return { status: "unavailable", reason: "capability_not_advertised" };
5074
5510
  if (edits.length === 0)
5075
5511
  return UNCHANGED;
5076
- const before = readFileSync5(filePath, "utf-8");
5512
+ const before = readFileSync8(filePath, "utf-8");
5077
5513
  const normalized = normalizeTextEdits(before, edits, 0);
5078
5514
  if (normalized.text === before)
5079
5515
  return UNCHANGED;
@@ -5101,7 +5537,7 @@ function writeAtomically(filePath, content) {
5101
5537
  renameSync3(tempPath, filePath);
5102
5538
  } catch (error) {
5103
5539
  try {
5104
- unlinkSync(tempPath);
5540
+ unlinkSync4(tempPath);
5105
5541
  } catch {}
5106
5542
  throw error;
5107
5543
  }
@@ -5528,7 +5964,7 @@ async function handleLspMcpRequest(input, options = {}) {
5528
5964
  if (!isPlainRecord(input)) {
5529
5965
  return errorResponse(null, -32600, "Invalid Request");
5530
5966
  }
5531
- const id = jsonRpcId(input["id"]);
5967
+ const id = jsonRpcId2(input["id"]);
5532
5968
  const method = input["method"];
5533
5969
  if (method === "notifications/initialized")
5534
5970
  return;
@@ -5589,6 +6025,7 @@ function requestedProtocolVersion(params) {
5589
6025
  import { connect } from "node:net";
5590
6026
  import { homedir as homedir3 } from "node:os";
5591
6027
  import { join as join8 } from "node:path";
6028
+ import { setTimeout as delay } from "node:timers/promises";
5592
6029
 
5593
6030
  // src/daemon-request-error.ts
5594
6031
  class DaemonRequestError extends Error {
@@ -5646,225 +6083,30 @@ function daemonTimedOutResult(paths, timeoutMs) {
5646
6083
  `Logs: ${paths.log}`
5647
6084
  ].join(`
5648
6085
  `);
5649
- return { content: [{ type: "text", text }], isError: true };
5650
- }
5651
- function daemonUnreachableResult(paths, error) {
5652
- const text = [
5653
- `LSP daemon unreachable: ${errorText(error)}.`,
5654
- "The MCP server is a thin proxy and never runs language servers in-process.",
5655
- `Socket: ${paths.socket}`,
5656
- `Logs: ${paths.log}`,
5657
- "The daemon is auto-started on demand and will be retried on the next request."
5658
- ].join(`
5659
- `);
5660
- return { content: [{ type: "text", text }], isError: true };
5661
- }
5662
- function errorText(error) {
5663
- return error instanceof Error ? error.message : String(error);
5664
- }
5665
-
5666
- // src/ensure-daemon.ts
5667
- import { spawn as spawn2 } from "node:child_process";
5668
- import { closeSync as closeSync2, existsSync as existsSync12, mkdirSync as mkdirSync3, openSync as openSync2, writeSync as writeSync2 } from "node:fs";
5669
- import { Socket } from "node:net";
5670
- import { dirname as dirname10, isAbsolute as isAbsolute5 } from "node:path";
5671
- import { argv0, execPath } from "node:process";
5672
-
5673
- // src/ipc-protocol.ts
5674
- import { randomBytes, timingSafeEqual } from "node:crypto";
5675
- import {
5676
- chmodSync,
5677
- closeSync,
5678
- constants,
5679
- fchmodSync,
5680
- fstatSync,
5681
- lstatSync as lstatSync6,
5682
- mkdirSync as mkdirSync2,
5683
- openSync,
5684
- readFileSync as readFileSync6,
5685
- unlinkSync as unlinkSync2,
5686
- writeSync
5687
- } from "node:fs";
5688
- import { dirname as dirname9 } from "node:path";
5689
- var OMO_DAEMON_PROTOCOL_VERSION = 1;
5690
- var AUTH_ERROR_CODE = -32001;
5691
- var PROTOCOL_ERROR_CODE = -32002;
5692
- var AUTH_TOKEN_BYTES = 32;
5693
-
5694
- class UnsafePrivateDirectoryError extends Error {
5695
- constructor(path, reason) {
5696
- super(`unsafe private directory ${path}: ${reason}`);
5697
- this.path = path;
5698
- this.reason = reason;
5699
- this.name = "UnsafePrivateDirectoryError";
5700
- this.code = "unsafe_private_directory";
5701
- }
5702
- }
5703
- function authEnvelope(token) {
5704
- return { protocolVersion: OMO_DAEMON_PROTOCOL_VERSION, token };
5705
- }
5706
- function readAuthToken(paths) {
5707
- try {
5708
- const token = readFileSync6(paths.auth, "utf8").trim();
5709
- return token.length > 0 ? token : null;
5710
- } catch (error) {
5711
- if (error instanceof Error)
5712
- return null;
5713
- throw error;
5714
- }
5715
- }
5716
- function readOrCreateAuthToken(paths) {
5717
- const existing = readAuthToken(paths);
5718
- if (existing)
5719
- return existing;
5720
- return createAuthToken(paths);
5721
- }
5722
- function rotateAuthToken(paths) {
5723
- try {
5724
- unlinkSync2(paths.auth);
5725
- } catch (error) {
5726
- if (!(error instanceof Error))
5727
- throw error;
5728
- }
5729
- return createAuthToken(paths);
5730
- }
5731
- function authenticateMessage(raw, expectedToken) {
5732
- const id = jsonRpcId2(raw);
5733
- if (!isPlainRecord(raw))
5734
- return authError(id);
5735
- const params = raw["params"];
5736
- if (!isPlainRecord(params))
5737
- return authError(id);
5738
- const envelope = params["_omo"];
5739
- if (!isPlainRecord(envelope))
5740
- return authError(id);
5741
- const protocolVersion = envelope["protocolVersion"];
5742
- if (protocolVersion !== OMO_DAEMON_PROTOCOL_VERSION)
5743
- return protocolError(id);
5744
- const token = envelope["token"];
5745
- if (typeof token !== "string" || !tokenMatches(token, expectedToken))
5746
- return authError(id);
5747
- const cleanParams = { ...params };
5748
- delete cleanParams["_omo"];
5749
- return { input: { ...raw, params: cleanParams }, id, method: typeof raw["method"] === "string" ? raw["method"] : undefined };
5750
- }
5751
- function isAuthErrorResponse(message) {
5752
- if (!isPlainRecord(message))
5753
- return false;
5754
- const error = message["error"];
5755
- if (!isPlainRecord(error))
5756
- return false;
5757
- const data = error["data"];
5758
- return error["code"] === AUTH_ERROR_CODE && isPlainRecord(data) && data["code"] === "daemon_authentication_failed";
5759
- }
5760
- function writePrivateFile(path, data) {
5761
- const fd = openSync(path, "w", 384);
5762
- try {
5763
- writeSync(fd, data);
5764
- } finally {
5765
- closeSync(fd);
5766
- }
5767
- setPrivateFileMode(path);
5768
- }
5769
- function ensurePrivateDirectory(path, options = {}) {
5770
- try {
5771
- mkdirSync2(path, { recursive: true, mode: 448 });
5772
- } catch (error) {
5773
- if (errorCode2(error) !== "EEXIST")
5774
- throw error;
5775
- }
5776
- if (process.platform === "win32")
5777
- return;
5778
- const before = validatePrivateDirectory(path, options);
5779
- const fd = openSync(path, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
5780
- try {
5781
- fchmodSync(fd, 448);
5782
- const after = validatePrivateDirectory(path, options);
5783
- const openStats = fstatSync(fd);
5784
- if (!sameDirectory(before, after) || !sameDirectory(before, openStats)) {
5785
- throw new UnsafePrivateDirectoryError(path, "changed_during_chmod");
5786
- }
5787
- } finally {
5788
- closeSync(fd);
5789
- }
5790
- }
5791
- function setPrivateFileMode(path) {
5792
- if (process.platform !== "win32")
5793
- chmodSync(path, 384);
5794
- }
5795
- function createAuthToken(paths) {
5796
- ensurePrivateDirectory(dirname9(paths.auth));
5797
- const token = randomBytes(AUTH_TOKEN_BYTES).toString("base64url");
5798
- let fd;
5799
- try {
5800
- fd = openSync(paths.auth, "wx", 384);
5801
- } catch (error) {
5802
- if (errorCode2(error) === "EEXIST") {
5803
- const existing = readAuthToken(paths);
5804
- if (existing)
5805
- return existing;
5806
- }
5807
- throw error;
5808
- }
5809
- try {
5810
- writeSync(fd, `${token}
5811
- `);
5812
- } finally {
5813
- closeSync(fd);
5814
- }
5815
- setPrivateFileMode(paths.auth);
5816
- return token;
5817
- }
5818
- function errorCode2(error) {
5819
- if (!error || typeof error !== "object" || !("code" in error))
5820
- return;
5821
- const code = Reflect.get(error, "code");
5822
- return typeof code === "string" ? code : undefined;
5823
- }
5824
- function validatePrivateDirectory(path, options) {
5825
- const stats = options.lstat ? options.lstat(path) : lstatPrivateDirectory(path);
5826
- if (stats.isSymbolicLink())
5827
- throw new UnsafePrivateDirectoryError(path, "symlink");
5828
- if (!stats.isDirectory())
5829
- throw new UnsafePrivateDirectoryError(path, "not_directory");
5830
- const currentUid = options.currentUid ? options.currentUid() : process.getuid?.();
5831
- if (currentUid !== undefined && stats.uid !== currentUid) {
5832
- throw new UnsafePrivateDirectoryError(path, "wrong_owner");
5833
- }
5834
- return stats;
5835
- }
5836
- function lstatPrivateDirectory(path) {
5837
- return lstatSync6(path);
5838
- }
5839
- function sameDirectory(a, b) {
5840
- return a.dev === b.dev && a.ino === b.ino;
5841
- }
5842
- function tokenMatches(candidate, expected) {
5843
- const candidateBytes = Buffer.from(candidate);
5844
- const expectedBytes = Buffer.from(expected);
5845
- return candidateBytes.length === expectedBytes.length && timingSafeEqual(candidateBytes, expectedBytes);
5846
- }
5847
- function jsonRpcId2(raw) {
5848
- if (!isPlainRecord(raw))
5849
- return null;
5850
- const id = raw["id"];
5851
- return typeof id === "string" || typeof id === "number" || id === null ? id : null;
5852
- }
5853
- function authError(id) {
5854
- return {
5855
- jsonrpc: "2.0",
5856
- id,
5857
- error: { code: AUTH_ERROR_CODE, message: "daemon authentication failed", data: { code: "daemon_authentication_failed" } }
5858
- };
6086
+ return { content: [{ type: "text", text }], isError: true };
5859
6087
  }
5860
- function protocolError(id) {
5861
- return {
5862
- jsonrpc: "2.0",
5863
- id,
5864
- error: { code: PROTOCOL_ERROR_CODE, message: "daemon protocol mismatch", data: { code: "daemon_protocol_mismatch" } }
5865
- };
6088
+ function daemonUnreachableResult(paths, error) {
6089
+ const text = [
6090
+ `LSP daemon unreachable: ${errorText(error)}.`,
6091
+ "The MCP server is a thin proxy and never runs language servers in-process.",
6092
+ `Socket: ${paths.socket}`,
6093
+ `Logs: ${paths.log}`,
6094
+ "The daemon is auto-started on demand and will be retried on the next request."
6095
+ ].join(`
6096
+ `);
6097
+ return { content: [{ type: "text", text }], isError: true };
6098
+ }
6099
+ function errorText(error) {
6100
+ return error instanceof Error ? error.message : String(error);
5866
6101
  }
5867
6102
 
6103
+ // src/ensure-daemon.ts
6104
+ import { spawn as spawn2 } from "node:child_process";
6105
+ import { closeSync as closeSync3, existsSync as existsSync13, mkdirSync as mkdirSync4, openSync as openSync3, writeSync as writeSync3 } from "node:fs";
6106
+ import { Socket } from "node:net";
6107
+ import { dirname as dirname12, isAbsolute as isAbsolute5 } from "node:path";
6108
+ import { argv0, execPath } from "node:process";
6109
+
5868
6110
  // src/paths.ts
5869
6111
  import { createHash as createHash2 } from "node:crypto";
5870
6112
  import { createRequire } from "node:module";
@@ -5873,7 +6115,7 @@ import * as path from "node:path";
5873
6115
  import { fileURLToPath as fileURLToPath3 } from "node:url";
5874
6116
 
5875
6117
  // src/runtime-contract.ts
5876
- import { statSync as statSync4 } from "node:fs";
6118
+ import { statSync as statSync5 } from "node:fs";
5877
6119
  import { isAbsolute as isAbsolute4 } from "node:path";
5878
6120
  var OMO_LSP_DAEMON_DIR = "OMO_LSP_DAEMON_DIR";
5879
6121
  var OMO_LSP_DAEMON_CLI = "OMO_LSP_DAEMON_CLI";
@@ -5921,7 +6163,7 @@ function resolveDaemonRuntime(env, defaults) {
5921
6163
  }
5922
6164
  let cliStats;
5923
6165
  try {
5924
- cliStats = statSync4(cliOverride);
6166
+ cliStats = statSync5(cliOverride);
5925
6167
  } catch (error) {
5926
6168
  if (!(error instanceof Error))
5927
6169
  throw error;
@@ -6055,9 +6297,11 @@ function createLineDecoder(onMessage, onParseError) {
6055
6297
  }
6056
6298
 
6057
6299
  // src/ensure-daemon.ts
6058
- var PROBE_TIMEOUT_MS = 500;
6300
+ var PROBE_TIMEOUT_MS = 2000;
6059
6301
  var DEFAULT_READY_TIMEOUT_MS = 5000;
6060
6302
  var DEFAULT_POLL_INTERVAL_MS = 100;
6303
+ var FAILED_SPAWN_COOLDOWN_MS = 5000;
6304
+ var failedSpawnUntil = new Map;
6061
6305
 
6062
6306
  class DaemonUnreachableError extends Error {
6063
6307
  constructor(socketPath) {
@@ -6070,11 +6314,22 @@ async function ensureDaemonRunning(paths, deps = defaultEnsureDaemonDeps(), opti
6070
6314
  const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
6071
6315
  const signal = options.signal;
6072
6316
  throwIfAborted(signal);
6073
- if (await awaitWithSignal2(deps.probe(paths, signal), signal))
6317
+ if (await awaitWithSignal2(deps.probe(paths, signal), signal)) {
6318
+ failedSpawnUntil.delete(paths.socket);
6074
6319
  return;
6320
+ }
6075
6321
  throwIfAborted(signal);
6322
+ const retryAt = failedSpawnUntil.get(paths.socket);
6323
+ if (retryAt !== undefined && deps.now() < retryAt)
6324
+ throw new DaemonUnreachableError(paths.socket);
6325
+ failedSpawnUntil.delete(paths.socket);
6076
6326
  deps.spawnDaemon(paths);
6077
- await waitUntilReachable(paths, deps, readyTimeoutMs, pollIntervalMs, signal);
6327
+ try {
6328
+ await waitUntilReachable(paths, deps, readyTimeoutMs, pollIntervalMs, signal);
6329
+ } catch (error) {
6330
+ failedSpawnUntil.set(paths.socket, deps.now() + FAILED_SPAWN_COOLDOWN_MS);
6331
+ throw error;
6332
+ }
6078
6333
  }
6079
6334
  async function waitUntilReachable(paths, deps, readyTimeoutMs, pollIntervalMs, signal) {
6080
6335
  const deadline = deps.now() + readyTimeoutMs;
@@ -6130,8 +6385,8 @@ function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
6130
6385
  });
6131
6386
  }
6132
6387
  function spawnDaemonProcess(paths, deps = {}) {
6133
- mkdirSync3(dirname10(paths.log), { recursive: true });
6134
- const logFd = openSync2(paths.log, "a");
6388
+ mkdirSync4(dirname12(paths.log), { recursive: true });
6389
+ const logFd = openSync3(paths.log, "a");
6135
6390
  try {
6136
6391
  const spawnDaemonChild = deps.spawn ?? spawn2;
6137
6392
  const executable = deps.resolveExecutable?.() ?? resolveDaemonNodeExecutable();
@@ -6141,19 +6396,19 @@ function spawnDaemonProcess(paths, deps = {}) {
6141
6396
  windowsHide: true,
6142
6397
  env: { ...process.env, BUN_BE_BUN: "1" }
6143
6398
  });
6144
- child.once("spawn", () => closeSync2(logFd));
6399
+ child.once("spawn", () => closeSync3(logFd));
6145
6400
  child.once("error", (error) => {
6146
- writeSync2(logFd, `[lsp-daemon] failed to spawn daemon: ${error.message}
6401
+ writeSync3(logFd, `[lsp-daemon] failed to spawn daemon: ${error.message}
6147
6402
  `);
6148
- closeSync2(logFd);
6403
+ closeSync3(logFd);
6149
6404
  });
6150
6405
  child.unref();
6151
6406
  } catch (error) {
6152
- closeSync2(logFd);
6407
+ closeSync3(logFd);
6153
6408
  throw error;
6154
6409
  }
6155
6410
  }
6156
- function resolveDaemonNodeExecutable(cachedExecPath = execPath, originalArgv0 = argv0, pathExists = existsSync12) {
6411
+ function resolveDaemonNodeExecutable(cachedExecPath = execPath, originalArgv0 = argv0, pathExists = existsSync13) {
6157
6412
  if (pathExists(cachedExecPath))
6158
6413
  return cachedExecPath;
6159
6414
  if (isAbsolute5(originalArgv0) && pathExists(originalArgv0))
@@ -6337,6 +6592,7 @@ function parseContext(value) {
6337
6592
 
6338
6593
  // src/daemon-client.ts
6339
6594
  var DEFAULT_REQUEST_TIMEOUT_MS = 30000;
6595
+ var STARTUP_BACKOFF_MS = [0, 100, 300];
6340
6596
  var nextProxyRequestId = 1;
6341
6597
  async function callToolViaDaemon(name, args, options) {
6342
6598
  const context = requireContext(options.context);
@@ -6344,17 +6600,31 @@ async function callToolViaDaemon(name, args, options) {
6344
6600
  const ensure = options.ensure ?? ((ensurePaths, signal) => ensureDaemonRunning(ensurePaths, undefined, signal === undefined ? {} : { signal }));
6345
6601
  const timeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
6346
6602
  const requestArgs = withContext(args, context);
6603
+ const probe = options.probe ?? ((probePaths, signal) => probeDaemon(probePaths, undefined, signal));
6604
+ const sleep = options.sleep ?? ((ms, signal) => delay(ms, undefined, { signal }));
6347
6605
  let lastError;
6348
6606
  let authRefreshUsed = false;
6349
- for (let attempt = 0;attempt < 3; attempt += 1) {
6607
+ for (const [attempt, backoffMs] of STARTUP_BACKOFF_MS.entries()) {
6350
6608
  try {
6351
- await ensureDaemonAvailable(paths, ensure, options.signal);
6609
+ if (backoffMs > 0)
6610
+ await sleep(backoffMs, options.signal);
6611
+ if (options.signal?.aborted)
6612
+ throw new DaemonRequestCancelledError(false);
6613
+ if (attempt === 0) {
6614
+ await ensureDaemonAvailable(paths, ensure, options.signal);
6615
+ } else if (!await probe(paths, options.signal)) {
6616
+ throw new DaemonUnreachableError(paths.socket);
6617
+ }
6352
6618
  const token = readAuthToken(paths);
6353
6619
  if (!token)
6354
6620
  throw new DaemonRequestError("daemon auth token missing", false);
6355
6621
  const sendOptions = options.signal === undefined ? { timeoutMs } : { timeoutMs, signal: options.signal };
6356
6622
  return await sendToolCall(paths, token, name, requestArgs, sendOptions);
6357
6623
  } catch (error) {
6624
+ if (options.signal?.aborted) {
6625
+ lastError = new DaemonRequestCancelledError(false);
6626
+ break;
6627
+ }
6358
6628
  lastError = error;
6359
6629
  if (error instanceof DaemonAuthenticationRejectedError && !authRefreshUsed) {
6360
6630
  authRefreshUsed = true;
@@ -6610,7 +6880,7 @@ function asToolCall(parsed) {
6610
6880
  if (!isPlainRecord(params) || typeof params["name"] !== "string")
6611
6881
  return null;
6612
6882
  const args = params["arguments"];
6613
- return { id: jsonRpcId(parsed["id"]), name: params["name"], args: isPlainRecord(args) ? args : {} };
6883
+ return { id: jsonRpcId2(parsed["id"]), name: params["name"], args: isPlainRecord(args) ? args : {} };
6614
6884
  }
6615
6885
  function inferOpenCodeProjectCwd(projectConfigEnv) {
6616
6886
  if (!projectConfigEnv)
@@ -6636,263 +6906,24 @@ function canonicalizePathList(value) {
6636
6906
  return value.split(delimiter4).map((entry) => canonicalizePath(entry) ?? entry).join(delimiter4);
6637
6907
  }
6638
6908
  function canonicalizePath(value) {
6639
- if (value === undefined || !isAbsolute6(value) || !existsSync13(value))
6909
+ if (value === undefined || !isAbsolute6(value) || !existsSync14(value))
6640
6910
  return value;
6641
6911
  return realpathSync6(value);
6642
6912
  }
6643
6913
  function projectRootFromOpenCodeConfigPath(path) {
6644
6914
  if (basename4(path) !== "lsp.json" && basename4(path) !== "lsp-client.json")
6645
6915
  return;
6646
- const configDir = dirname11(path);
6916
+ const configDir = dirname13(path);
6647
6917
  const configDirName = basename4(configDir);
6648
6918
  if (configDirName !== ".opencode" && configDirName !== ".omo")
6649
6919
  return;
6650
- return dirname11(configDir);
6920
+ return dirname13(configDir);
6651
6921
  }
6652
6922
 
6653
6923
  // src/daemon-server.ts
6654
6924
  import { chmodSync as chmodSync2 } from "node:fs";
6655
6925
  import { createServer as createServer2 } from "node:net";
6656
6926
 
6657
- // src/ownership.ts
6658
- import { randomUUID } from "node:crypto";
6659
- import { existsSync as existsSync14, lstatSync as lstatSync7, readFileSync as readFileSync8, statSync as statSync5, unlinkSync as unlinkSync4 } from "node:fs";
6660
- import { dirname as dirname13 } from "node:path";
6661
-
6662
- // src/lock.ts
6663
- import { closeSync as closeSync3, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as readFileSync7, unlinkSync as unlinkSync3, writeSync as writeSync3 } from "node:fs";
6664
- import { dirname as dirname12 } from "node:path";
6665
- function isProcessAlive2(pid) {
6666
- if (!Number.isInteger(pid) || pid <= 0)
6667
- return false;
6668
- try {
6669
- process.kill(pid, 0);
6670
- return true;
6671
- } catch (error) {
6672
- if (error instanceof Error)
6673
- return errorCode3(error) === "EPERM";
6674
- throw error;
6675
- }
6676
- }
6677
- function readLockPid(lockPath) {
6678
- try {
6679
- const pid = Number.parseInt(readFileSync7(lockPath, "utf8").trim(), 10);
6680
- return Number.isInteger(pid) ? pid : null;
6681
- } catch {
6682
- return null;
6683
- }
6684
- }
6685
- function tryAcquireLock(lockPath, ownerPid = process.pid) {
6686
- mkdirSync4(dirname12(lockPath), { recursive: true });
6687
- for (let attempt = 0;attempt < 2; attempt += 1) {
6688
- const handle = writeLockFile(lockPath, ownerPid);
6689
- if (handle)
6690
- return handle;
6691
- if (!reapStaleLock(lockPath))
6692
- return null;
6693
- }
6694
- return null;
6695
- }
6696
- function writeLockFile(lockPath, ownerPid) {
6697
- try {
6698
- const fd = openSync3(lockPath, "wx", 384);
6699
- writeSync3(fd, `${ownerPid}
6700
- `);
6701
- closeSync3(fd);
6702
- return { release: () => unlinkQuietly(lockPath) };
6703
- } catch (error) {
6704
- if (errorCode3(error) === "EEXIST")
6705
- return null;
6706
- throw error;
6707
- }
6708
- }
6709
- function reapStaleLock(lockPath) {
6710
- const pid = readLockPid(lockPath);
6711
- if (pid !== null && isProcessAlive2(pid))
6712
- return false;
6713
- unlinkQuietly(lockPath);
6714
- return true;
6715
- }
6716
- function unlinkQuietly(path) {
6717
- try {
6718
- unlinkSync3(path);
6719
- } catch (error) {
6720
- if (error instanceof Error)
6721
- return;
6722
- throw error;
6723
- }
6724
- }
6725
- function errorCode3(error) {
6726
- if (!error || typeof error !== "object" || !("code" in error))
6727
- return;
6728
- const code = Reflect.get(error, "code");
6729
- return typeof code === "string" ? code : undefined;
6730
- }
6731
-
6732
- // src/ownership.ts
6733
- class DaemonAlreadyRunningError extends Error {
6734
- constructor() {
6735
- super(...arguments);
6736
- this.name = "DaemonAlreadyRunningError";
6737
- this.code = "daemon_already_running";
6738
- }
6739
- }
6740
-
6741
- class DaemonStartupDeferredError extends Error {
6742
- constructor(reason) {
6743
- super(`LSP daemon startup deferred: ${reason}`);
6744
- this.reason = reason;
6745
- this.name = "DaemonStartupDeferredError";
6746
- this.code = "daemon_startup_deferred";
6747
- }
6748
- }
6749
- async function acquireStartupLease(paths, pingOwner) {
6750
- ensureDaemonDirectories(paths);
6751
- const lock = tryAcquireLock(paths.lock);
6752
- if (!lock) {
6753
- const token = readAuthToken(paths);
6754
- if (token && await pingOwner(token))
6755
- throw new DaemonAlreadyRunningError("LSP daemon already running");
6756
- throw new DaemonStartupDeferredError("startup_lock_busy");
6757
- }
6758
- try {
6759
- const token = await validateExistingOwner(paths, pingOwner);
6760
- return { lock, token, owner: newOwner(paths) };
6761
- } catch (error) {
6762
- lock.release();
6763
- throw error;
6764
- }
6765
- }
6766
- function ensureDaemonDirectories(paths) {
6767
- ensurePrivateDirectory(paths.dir);
6768
- if (process.platform !== "win32")
6769
- ensurePrivateDirectory(dirname13(paths.socket));
6770
- }
6771
- function readDaemonOwner(paths) {
6772
- try {
6773
- return parseOwner(JSON.parse(readFileSync8(paths.owner, "utf8")));
6774
- } catch (error) {
6775
- if (error instanceof Error)
6776
- return null;
6777
- throw error;
6778
- }
6779
- }
6780
- function writeDaemonOwner(paths, owner) {
6781
- writePrivateFile(paths.pid, `${owner.pid}
6782
- `);
6783
- writePrivateFile(paths.endpoint, owner.endpoint.path);
6784
- writePrivateFile(paths.owner, `${JSON.stringify(owner)}
6785
- `);
6786
- }
6787
- function removeDaemonMetadataForOwner(paths, owner) {
6788
- const current = readDaemonOwner(paths);
6789
- if (!current || !sameOwner(current, owner))
6790
- return;
6791
- unlinkQuietly(paths.socket);
6792
- unlinkQuietly(paths.pid);
6793
- unlinkQuietly(paths.endpoint);
6794
- unlinkQuietly(paths.owner);
6795
- }
6796
- function endpointIdentity(endpointPath) {
6797
- if (process.platform === "win32")
6798
- return { kind: "windows", path: endpointPath };
6799
- try {
6800
- const stats = statSync5(endpointPath);
6801
- return { kind: "unix", path: endpointPath, dev: stats.dev, ino: stats.ino };
6802
- } catch (error) {
6803
- if (error instanceof Error)
6804
- return { kind: "missing", path: endpointPath };
6805
- throw error;
6806
- }
6807
- }
6808
- function sameEndpoint(a, b) {
6809
- if (a.kind !== b.kind || a.path !== b.path)
6810
- return false;
6811
- switch (a.kind) {
6812
- case "unix":
6813
- return b.kind === "unix" && a.dev === b.dev && a.ino === b.ino;
6814
- case "windows":
6815
- return true;
6816
- case "missing":
6817
- return true;
6818
- }
6819
- }
6820
- function sameOwner(a, b) {
6821
- return a.pid === b.pid && a.nonce === b.nonce && sameEndpoint(a.endpoint, b.endpoint);
6822
- }
6823
- async function validateExistingOwner(paths, pingOwner) {
6824
- let token = readOrCreateAuthToken(paths);
6825
- for (let attempt = 0;attempt < 2; attempt += 1) {
6826
- const owner = readDaemonOwner(paths);
6827
- if (!owner)
6828
- return token;
6829
- const ping = await pingOwner(token);
6830
- if (ping && owner.nonce === ping.nonce && sameEndpoint(owner.endpoint, ping.endpoint)) {
6831
- throw new DaemonAlreadyRunningError("LSP daemon already running");
6832
- }
6833
- if (ping)
6834
- continue;
6835
- if (isProcessAlive2(owner.pid))
6836
- throw new DaemonStartupDeferredError("owner_pid_live_unreachable");
6837
- const reread = readDaemonOwner(paths);
6838
- if (!reread || !sameOwner(reread, owner)) {
6839
- throw new DaemonStartupDeferredError("owner_changed_during_cleanup");
6840
- }
6841
- cleanupDeadOwner(paths, owner);
6842
- token = rotateAuthToken(paths);
6843
- return token;
6844
- }
6845
- throw new DaemonStartupDeferredError("reachable_owner_mismatch");
6846
- }
6847
- function cleanupDeadOwner(paths, owner) {
6848
- if (process.platform !== "win32" && existsSync14(owner.endpoint.path)) {
6849
- const stat = lstatSync7(owner.endpoint.path);
6850
- if (stat.isSocket())
6851
- unlinkSync4(owner.endpoint.path);
6852
- }
6853
- unlinkQuietly(paths.pid);
6854
- unlinkQuietly(paths.endpoint);
6855
- unlinkQuietly(paths.owner);
6856
- }
6857
- function newOwner(paths) {
6858
- return {
6859
- pid: process.pid,
6860
- nonce: randomUUID(),
6861
- startedAt: new Date().toISOString(),
6862
- endpoint: endpointIdentity(paths.socket)
6863
- };
6864
- }
6865
- function parseOwner(value) {
6866
- if (!value || typeof value !== "object" || Array.isArray(value))
6867
- return null;
6868
- const pid = Reflect.get(value, "pid");
6869
- const nonce = Reflect.get(value, "nonce");
6870
- const startedAt = Reflect.get(value, "startedAt");
6871
- const endpoint = parseEndpoint(Reflect.get(value, "endpoint"));
6872
- if (typeof pid !== "number" || typeof nonce !== "string" || typeof startedAt !== "string" || !endpoint)
6873
- return null;
6874
- return { pid, nonce, startedAt, endpoint };
6875
- }
6876
- function parseEndpoint(value) {
6877
- if (!value || typeof value !== "object" || Array.isArray(value))
6878
- return null;
6879
- const kind = Reflect.get(value, "kind");
6880
- const path = Reflect.get(value, "path");
6881
- if (typeof path !== "string")
6882
- return null;
6883
- if (kind === undefined)
6884
- return endpointIdentity(path);
6885
- if (kind === "windows")
6886
- return { kind, path };
6887
- if (kind === "missing")
6888
- return { kind, path };
6889
- const dev = Reflect.get(value, "dev");
6890
- const ino = Reflect.get(value, "ino");
6891
- if (kind === "unix" && typeof dev === "number" && typeof ino === "number")
6892
- return { kind, path, dev, ino };
6893
- return null;
6894
- }
6895
-
6896
6927
  // src/version-reap.ts
6897
6928
  import { execFile } from "node:child_process";
6898
6929
  import { readdir, readFile, rm } from "node:fs/promises";
@@ -6919,7 +6950,7 @@ async function attestDaemonCliProcess(pid, platform, deps = {}) {
6919
6950
  async function reapStaleDaemonVersions(ownPaths, deps = {}) {
6920
6951
  const baseDir = dirname14(ownPaths.dir);
6921
6952
  const platform = deps.platform ?? process.platform;
6922
- const isAlive = deps.isAlive ?? isProcessAlive2;
6953
+ const isAlive = deps.isAlive ?? isProcessAlive;
6923
6954
  const attest = deps.attest ?? ((pid) => attestDaemonCliProcess(pid, platform));
6924
6955
  const sendSignal = deps.sendSignal ?? defaultSendSignal;
6925
6956
  const waitForExit = deps.waitForExit ?? defaultWaitForExit;
@@ -7059,7 +7090,7 @@ function defaultSendSignal(pid, signal) {
7059
7090
  async function defaultWaitForExit(pid, timeoutMs) {
7060
7091
  const deadline = Date.now() + timeoutMs;
7061
7092
  for (;; ) {
7062
- if (!isProcessAlive2(pid))
7093
+ if (!isProcessAlive(pid))
7063
7094
  return true;
7064
7095
  if (Date.now() >= deadline)
7065
7096
  return false;
@@ -7229,7 +7260,12 @@ async function main() {
7229
7260
  process.exitCode = 2;
7230
7261
  }
7231
7262
  main().catch((error) => {
7232
- stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}
7263
+ if (error instanceof DaemonStartupDeferredError) {
7264
+ stderr.write(`[lsp-daemon] startup deferred: ${error.reason}
7265
+ `);
7266
+ } else {
7267
+ stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}
7233
7268
  `);
7269
+ }
7234
7270
  process.exitCode = 1;
7235
7271
  });