lazycodex-ai 5.0.0-beta.31 → 5.0.0-beta.32

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 (145) hide show
  1. package/dist/cli/index.js +136 -44
  2. package/dist/cli-node/index.js +136 -44
  3. package/package.json +2 -2
  4. package/packages/lsp-daemon/dist/cli.js +41 -16
  5. package/packages/lsp-daemon/dist/client.js +41 -16
  6. package/packages/lsp-daemon/dist/index.js +41 -16
  7. package/packages/lsp-tools-mcp/dist/cli.js +41 -16
  8. package/packages/lsp-tools-mcp/dist/lsp/manager.js +41 -16
  9. package/packages/lsp-tools-mcp/dist/mcp.js +41 -16
  10. package/packages/lsp-tools-mcp/dist/tools.js +41 -16
  11. package/packages/lsp-tools-mcp/package.json +1 -1
  12. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  13. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  14. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  15. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +3 -17
  16. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +3 -17
  17. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  18. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  19. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  20. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  21. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  22. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  23. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  24. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
  25. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +39 -16
  26. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  27. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  28. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  29. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  30. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  31. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  32. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  33. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  34. package/packages/omo-codex/plugin/components/ultrawork/AGENTS.md +5 -4
  35. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +489 -4
  36. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  37. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -2
  38. package/packages/omo-codex/plugin/components/ultrawork/scripts/sync-directive.mjs +30 -14
  39. package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +4 -0
  40. package/packages/omo-codex/plugin/components/ultrawork/src/directive.ts +5 -2
  41. package/packages/omo-codex/plugin/components/ultrawork/test/directive-source.test.ts +14 -8
  42. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +12 -1
  43. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +2 -2
  44. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  45. package/packages/omo-codex/plugin/components/ulw-loop/AGENTS.md +4 -2
  46. package/packages/omo-codex/plugin/components/ulw-loop/README.md +1 -0
  47. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-continuation.js +9 -0
  48. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-reconciliation.d.ts +14 -0
  49. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-reconciliation.js +10 -1
  50. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-template.d.ts +8 -0
  51. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-template.js +113 -0
  52. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +7 -5
  53. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-commands.js +2 -1
  54. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.d.ts +1 -1
  55. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.js +1 -0
  56. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.js +2 -0
  57. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +775 -312
  58. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +18 -0
  59. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-snapshot.d.ts +13 -0
  60. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-snapshot.js +14 -0
  61. package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +17 -9
  62. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.js +17 -2
  63. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-missing-recovery.d.ts +13 -0
  64. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-missing-recovery.js +19 -0
  65. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-aggregate.d.ts +2 -0
  66. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-aggregate.js +53 -0
  67. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-artifacts.d.ts +9 -0
  68. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-artifacts.js +85 -0
  69. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-fields.js +1 -1
  70. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.js +41 -99
  71. package/packages/omo-codex/plugin/components/ulw-loop/dist/review-blockers.js +4 -2
  72. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.js +184 -14
  73. package/packages/omo-codex/plugin/components/ulw-loop/dist/status-next-actions.d.ts +6 -0
  74. package/packages/omo-codex/plugin/components/ulw-loop/dist/status-next-actions.js +33 -0
  75. package/packages/omo-codex/plugin/components/ulw-loop/dist/surface.d.ts +3 -0
  76. package/packages/omo-codex/plugin/components/ulw-loop/dist/surface.js +15 -0
  77. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  78. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  79. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +17 -0
  80. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-continuation.ts +7 -0
  81. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-reconciliation.ts +25 -1
  82. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-template.ts +127 -0
  83. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +8 -12
  84. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-commands.ts +2 -1
  85. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-output.ts +1 -0
  86. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-subcommands.ts +2 -0
  87. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +18 -0
  88. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-snapshot.ts +23 -0
  89. package/packages/omo-codex/plugin/components/ulw-loop/src/domain-types.ts +19 -9
  90. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-io.ts +18 -3
  91. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-missing-recovery.ts +27 -0
  92. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-aggregate.ts +57 -0
  93. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-artifacts.ts +103 -0
  94. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-fields.ts +1 -1
  95. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate.ts +50 -116
  96. package/packages/omo-codex/plugin/components/ulw-loop/src/review-blockers.ts +4 -2
  97. package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-guard.ts +186 -12
  98. package/packages/omo-codex/plugin/components/ulw-loop/src/status-next-actions.ts +36 -0
  99. package/packages/omo-codex/plugin/components/ulw-loop/src/surface.ts +22 -0
  100. package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-final.test.ts +66 -3
  101. package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-template.test.ts +92 -0
  102. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-status-next-actions.test.ts +183 -0
  103. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-instruction.test.ts +13 -3
  104. package/packages/omo-codex/plugin/components/ulw-loop/test/guided-recovery.test.ts +105 -0
  105. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-aggregate.test.ts +101 -0
  106. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-roles.test.ts +16 -15
  107. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-senpi-surface.test.ts +131 -0
  108. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate.test.ts +5 -0
  109. package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-guard.test.ts +300 -3
  110. package/packages/omo-codex/plugin/components/ulw-loop/test/ultrawork-directive.test.ts +9 -3
  111. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  112. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  113. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  114. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  115. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  116. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  117. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  118. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  119. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  120. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  121. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  122. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  123. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  124. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  125. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  126. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  127. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  128. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  129. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-ulw-execute-continuation.json +1 -1
  130. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  131. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  132. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  133. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  134. package/packages/omo-codex/plugin/package-lock.json +13 -13
  135. package/packages/omo-codex/plugin/package.json +1 -1
  136. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +31 -2
  137. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +9 -2
  138. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +17 -0
  139. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +11 -1
  140. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +13 -0
  141. package/packages/omo-codex/plugin/test/ultrawork-skill-pointer.test.mjs +5 -2
  142. package/packages/omo-codex/scripts/install-dist/install-local.mjs +2 -2
  143. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +9 -2
  144. package/packages/omo-codex/plugin/components/ultrawork/directive.md +0 -483
  145. package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +0 -490
@@ -17,6 +17,13 @@ import { pathToFileURL as pathToFileURL3 } from "node:url";
17
17
  // ../lsp-core/src/lsp/connection.ts
18
18
  import { pathToFileURL } from "node:url";
19
19
 
20
+ // ../lsp-core/src/lsp/timer-provider.ts
21
+ var realTimerProvider = {
22
+ now: () => Date.now(),
23
+ setTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
24
+ clearTimeout: (handle) => clearTimeout(handle)
25
+ };
26
+
20
27
  // ../lsp-core/src/lsp/constants.ts
21
28
  var DEFAULT_MAX_REFERENCES = 200;
22
29
  var DEFAULT_MAX_SYMBOLS = 200;
@@ -633,6 +640,7 @@ class LspClientTransport {
633
640
  this.documentFormattingSupported = false;
634
641
  this.requestTimeoutMs = timeouts.requestTimeoutMs ?? REQUEST_TIMEOUT_MS;
635
642
  this.initializeTimeoutMs = timeouts.initializeTimeoutMs ?? INIT_TIMEOUT_MS;
643
+ this.timerProvider = timeouts.timerProvider ?? realTimerProvider;
636
644
  }
637
645
  pid() {
638
646
  return this.proc?.pid;
@@ -733,7 +741,7 @@ class LspClientTransport {
733
741
  const options = args[1];
734
742
  const timeoutMs = options?.timeoutMs ?? this.requestTimeoutMs;
735
743
  const timeoutController = new AbortController;
736
- const timeoutHandle = setTimeout(() => {
744
+ const timeoutHandle = this.timerProvider.setTimeout(() => {
737
745
  const stderrTail = this.stderrBuffer.slice(-5).join(`
738
746
  `);
739
747
  timeoutController.abort(new LspRequestTimeoutError(method, stderrTail || undefined));
@@ -752,7 +760,7 @@ class LspClientTransport {
752
760
  }
753
761
  throw error;
754
762
  } finally {
755
- clearTimeout(timeoutHandle);
763
+ this.timerProvider.clearTimeout(timeoutHandle);
756
764
  combinedSignal.dispose();
757
765
  }
758
766
  }
@@ -1143,6 +1151,17 @@ function canonicalPath(filePath) {
1143
1151
  return absolute;
1144
1152
  }
1145
1153
  }
1154
+ function normalizeDocumentUri(uri) {
1155
+ let decoded = uri;
1156
+ try {
1157
+ decoded = decodeURIComponent(uri);
1158
+ } catch {
1159
+ decoded = uri;
1160
+ }
1161
+ if (process.platform !== "win32")
1162
+ return decoded;
1163
+ return decoded.replace(/^(file:\/\/\/)([a-z]):/, (_match, prefix, drive) => `${prefix}${drive.toUpperCase()}:`);
1164
+ }
1146
1165
  function isSameOrDescendant(candidate, parent) {
1147
1166
  const suffix = relative(parent, candidate);
1148
1167
  return suffix === "" || !suffix.startsWith("..") && suffix !== "..";
@@ -1159,7 +1178,12 @@ class WorkspaceDocumentState {
1159
1178
  this.openDocuments = new Map;
1160
1179
  this.openByUri = new Map;
1161
1180
  this.openPromises = new Map;
1162
- this.now = options.now ?? (() => Date.now());
1181
+ this.timerProvider = options.timerProvider ?? {
1182
+ now: options.now ?? (() => Date.now()),
1183
+ setTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
1184
+ clearTimeout: (handle) => clearTimeout(handle)
1185
+ };
1186
+ this.now = () => this.timerProvider.now();
1163
1187
  this.versionlessPublishQuiescenceMs = options.versionlessPublishQuiescenceMs ?? DEFAULT_VERSIONLESS_PUBLISH_QUIESCENCE_MS;
1164
1188
  }
1165
1189
  async openFile(filePath) {
@@ -1181,7 +1205,7 @@ class WorkspaceDocumentState {
1181
1205
  return this.openDocuments.get(canonicalPath(filePath))?.version;
1182
1206
  }
1183
1207
  getStoredDiagnostics(uri) {
1184
- const state = this.openByUri.get(uri);
1208
+ const state = this.openByUri.get(normalizeDocumentUri(uri));
1185
1209
  if (!state)
1186
1210
  return [];
1187
1211
  return state.lastPublish?.diagnostics ?? state.pullCache?.diagnostics ?? [];
@@ -1203,13 +1227,13 @@ class WorkspaceDocumentState {
1203
1227
  return state !== undefined && state.uri === snapshot.uri && state.version === snapshot.version && state.generation === snapshot.documentGeneration;
1204
1228
  }
1205
1229
  getPullCache(snapshot) {
1206
- const state = this.openByUri.get(snapshot.uri);
1230
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1207
1231
  if (!state?.pullCache || state.pullCache.documentVersion !== snapshot.version)
1208
1232
  return null;
1209
1233
  return state.pullCache;
1210
1234
  }
1211
1235
  recordPullDiagnostics(snapshot, report) {
1212
- const state = this.openByUri.get(snapshot.uri);
1236
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1213
1237
  if (!state)
1214
1238
  return;
1215
1239
  state.pullCache = {
@@ -1219,7 +1243,7 @@ class WorkspaceDocumentState {
1219
1243
  };
1220
1244
  }
1221
1245
  recordPublishedDiagnostics(params) {
1222
- const state = this.openByUri.get(params.uri);
1246
+ const state = this.openByUri.get(normalizeDocumentUri(params.uri));
1223
1247
  if (!state)
1224
1248
  return;
1225
1249
  state.publishGeneration += 1;
@@ -1233,7 +1257,7 @@ class WorkspaceDocumentState {
1233
1257
  this.notifyWaiters(state);
1234
1258
  }
1235
1259
  resolvePushDiagnostics(snapshot) {
1236
- const state = this.openByUri.get(snapshot.uri);
1260
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1237
1261
  if (!state?.lastPublish)
1238
1262
  return { status: "missing" };
1239
1263
  const publish = state.lastPublish;
@@ -1247,7 +1271,7 @@ class WorkspaceDocumentState {
1247
1271
  return waitMs === 0 ? { status: "ready", diagnostics: publish.diagnostics } : { status: "wait", waitMs };
1248
1272
  }
1249
1273
  waitForDiagnosticsActivity(snapshot, timeoutMs) {
1250
- const state = this.openByUri.get(snapshot.uri);
1274
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1251
1275
  if (!state || timeoutMs <= 0)
1252
1276
  return Promise.resolve();
1253
1277
  return new Promise((resolveActivity) => {
@@ -1256,11 +1280,11 @@ class WorkspaceDocumentState {
1256
1280
  if (settled)
1257
1281
  return;
1258
1282
  settled = true;
1259
- clearTimeout(timer);
1283
+ this.timerProvider.clearTimeout(timer);
1260
1284
  state.waiters.delete(finish);
1261
1285
  resolveActivity();
1262
1286
  };
1263
- const timer = setTimeout(finish, timeoutMs);
1287
+ const timer = this.timerProvider.setTimeout(finish, timeoutMs);
1264
1288
  if (typeof timer.unref === "function")
1265
1289
  timer.unref();
1266
1290
  state.waiters.add(finish);
@@ -1368,7 +1392,7 @@ class WorkspaceDocumentState {
1368
1392
  waiters: new Set
1369
1393
  };
1370
1394
  this.openDocuments.set(path, state);
1371
- this.openByUri.set(state.uri, state);
1395
+ this.openByUri.set(normalizeDocumentUri(state.uri), state);
1372
1396
  this.notifyWaiters(state);
1373
1397
  await this.sendNotification("textDocument/didOpen", {
1374
1398
  textDocument: { uri: state.uri, languageId: state.languageId, version: state.version, text }
@@ -1393,7 +1417,7 @@ class WorkspaceDocumentState {
1393
1417
  }
1394
1418
  async closeDocument(state) {
1395
1419
  this.openDocuments.delete(state.path);
1396
- this.openByUri.delete(state.uri);
1420
+ this.openByUri.delete(normalizeDocumentUri(state.uri));
1397
1421
  this.clearDiagnostics(state.uri);
1398
1422
  this.notifyWaiters(state);
1399
1423
  await this.sendNotification("textDocument/didClose", { textDocument: { uri: state.uri } });
@@ -2480,6 +2504,7 @@ class LspClient extends LspClientConnection {
2480
2504
  this.diagnosticPullErrors = [];
2481
2505
  this.diagnosticsFreshnessTimeoutMs = options.diagnosticsFreshnessTimeoutMs ?? DIAGNOSTICS_FRESHNESS_TIMEOUT_MS;
2482
2506
  this.documents = new WorkspaceDocumentState((method, params) => this.sendNotification(method, params), (uri) => this.diagnosticsStore.delete(uri), {
2507
+ timerProvider: this.timerProvider,
2483
2508
  versionlessPublishQuiescenceMs: options.versionlessPublishQuiescenceMs ?? VERSIONLESS_PUBLISH_QUIESCENCE_MS
2484
2509
  });
2485
2510
  this.workspaceMutations = new WorkspaceMutationController(root, this.documents);
@@ -2583,7 +2608,7 @@ class LspClient extends LspClientConnection {
2583
2608
  const absPath = this.resolveWorkspacePath(filePath);
2584
2609
  const uri = pathToFileURL3(absPath).href;
2585
2610
  await this.openFile(absPath);
2586
- const deadlineAt = Date.now() + this.diagnosticsFreshnessTimeoutMs;
2611
+ const deadlineAt = this.timerProvider.now() + this.diagnosticsFreshnessTimeoutMs;
2587
2612
  for (;; ) {
2588
2613
  signal?.throwIfAborted();
2589
2614
  const snapshot = this.documents.captureDiagnosticSnapshot(absPath);
@@ -2596,7 +2621,7 @@ class LspClient extends LspClientConnection {
2596
2621
  if (!pushFallbackOnly) {
2597
2622
  const cached = this.documents.getPullCache(snapshot);
2598
2623
  try {
2599
- const remainingMs2 = deadlineAt - Date.now();
2624
+ const remainingMs2 = deadlineAt - this.timerProvider.now();
2600
2625
  if (remainingMs2 <= 0)
2601
2626
  return this.freshnessTimeout(absPath);
2602
2627
  const result = await this.sendRequest("textDocument/diagnostic", {
@@ -2631,7 +2656,7 @@ class LspClient extends LspClientConnection {
2631
2656
  }
2632
2657
  if (!pushFallbackOnly)
2633
2658
  continue;
2634
- const remainingMs = deadlineAt - Date.now();
2659
+ const remainingMs = deadlineAt - this.timerProvider.now();
2635
2660
  if (remainingMs <= 0) {
2636
2661
  if (!this.isDiagnosticPullSupported() && snapshot.publishGeneration === 0) {
2637
2662
  const cached = this.documents.getPullCache(snapshot);
@@ -15,6 +15,13 @@ import { pathToFileURL as pathToFileURL3 } from "node:url";
15
15
  // ../lsp-core/src/lsp/connection.ts
16
16
  import { pathToFileURL } from "node:url";
17
17
 
18
+ // ../lsp-core/src/lsp/timer-provider.ts
19
+ var realTimerProvider = {
20
+ now: () => Date.now(),
21
+ setTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
22
+ clearTimeout: (handle) => clearTimeout(handle)
23
+ };
24
+
18
25
  // ../lsp-core/src/lsp/constants.ts
19
26
  var DEFAULT_MAX_REFERENCES = 200;
20
27
  var DEFAULT_MAX_SYMBOLS = 200;
@@ -631,6 +638,7 @@ class LspClientTransport {
631
638
  this.documentFormattingSupported = false;
632
639
  this.requestTimeoutMs = timeouts.requestTimeoutMs ?? REQUEST_TIMEOUT_MS;
633
640
  this.initializeTimeoutMs = timeouts.initializeTimeoutMs ?? INIT_TIMEOUT_MS;
641
+ this.timerProvider = timeouts.timerProvider ?? realTimerProvider;
634
642
  }
635
643
  pid() {
636
644
  return this.proc?.pid;
@@ -731,7 +739,7 @@ class LspClientTransport {
731
739
  const options = args[1];
732
740
  const timeoutMs = options?.timeoutMs ?? this.requestTimeoutMs;
733
741
  const timeoutController = new AbortController;
734
- const timeoutHandle = setTimeout(() => {
742
+ const timeoutHandle = this.timerProvider.setTimeout(() => {
735
743
  const stderrTail = this.stderrBuffer.slice(-5).join(`
736
744
  `);
737
745
  timeoutController.abort(new LspRequestTimeoutError(method, stderrTail || undefined));
@@ -750,7 +758,7 @@ class LspClientTransport {
750
758
  }
751
759
  throw error;
752
760
  } finally {
753
- clearTimeout(timeoutHandle);
761
+ this.timerProvider.clearTimeout(timeoutHandle);
754
762
  combinedSignal.dispose();
755
763
  }
756
764
  }
@@ -1141,6 +1149,17 @@ function canonicalPath(filePath) {
1141
1149
  return absolute;
1142
1150
  }
1143
1151
  }
1152
+ function normalizeDocumentUri(uri) {
1153
+ let decoded = uri;
1154
+ try {
1155
+ decoded = decodeURIComponent(uri);
1156
+ } catch {
1157
+ decoded = uri;
1158
+ }
1159
+ if (process.platform !== "win32")
1160
+ return decoded;
1161
+ return decoded.replace(/^(file:\/\/\/)([a-z]):/, (_match, prefix, drive) => `${prefix}${drive.toUpperCase()}:`);
1162
+ }
1144
1163
  function isSameOrDescendant(candidate, parent) {
1145
1164
  const suffix = relative(parent, candidate);
1146
1165
  return suffix === "" || !suffix.startsWith("..") && suffix !== "..";
@@ -1157,7 +1176,12 @@ class WorkspaceDocumentState {
1157
1176
  this.openDocuments = new Map;
1158
1177
  this.openByUri = new Map;
1159
1178
  this.openPromises = new Map;
1160
- this.now = options.now ?? (() => Date.now());
1179
+ this.timerProvider = options.timerProvider ?? {
1180
+ now: options.now ?? (() => Date.now()),
1181
+ setTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
1182
+ clearTimeout: (handle) => clearTimeout(handle)
1183
+ };
1184
+ this.now = () => this.timerProvider.now();
1161
1185
  this.versionlessPublishQuiescenceMs = options.versionlessPublishQuiescenceMs ?? DEFAULT_VERSIONLESS_PUBLISH_QUIESCENCE_MS;
1162
1186
  }
1163
1187
  async openFile(filePath) {
@@ -1179,7 +1203,7 @@ class WorkspaceDocumentState {
1179
1203
  return this.openDocuments.get(canonicalPath(filePath))?.version;
1180
1204
  }
1181
1205
  getStoredDiagnostics(uri) {
1182
- const state = this.openByUri.get(uri);
1206
+ const state = this.openByUri.get(normalizeDocumentUri(uri));
1183
1207
  if (!state)
1184
1208
  return [];
1185
1209
  return state.lastPublish?.diagnostics ?? state.pullCache?.diagnostics ?? [];
@@ -1201,13 +1225,13 @@ class WorkspaceDocumentState {
1201
1225
  return state !== undefined && state.uri === snapshot.uri && state.version === snapshot.version && state.generation === snapshot.documentGeneration;
1202
1226
  }
1203
1227
  getPullCache(snapshot) {
1204
- const state = this.openByUri.get(snapshot.uri);
1228
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1205
1229
  if (!state?.pullCache || state.pullCache.documentVersion !== snapshot.version)
1206
1230
  return null;
1207
1231
  return state.pullCache;
1208
1232
  }
1209
1233
  recordPullDiagnostics(snapshot, report) {
1210
- const state = this.openByUri.get(snapshot.uri);
1234
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1211
1235
  if (!state)
1212
1236
  return;
1213
1237
  state.pullCache = {
@@ -1217,7 +1241,7 @@ class WorkspaceDocumentState {
1217
1241
  };
1218
1242
  }
1219
1243
  recordPublishedDiagnostics(params) {
1220
- const state = this.openByUri.get(params.uri);
1244
+ const state = this.openByUri.get(normalizeDocumentUri(params.uri));
1221
1245
  if (!state)
1222
1246
  return;
1223
1247
  state.publishGeneration += 1;
@@ -1231,7 +1255,7 @@ class WorkspaceDocumentState {
1231
1255
  this.notifyWaiters(state);
1232
1256
  }
1233
1257
  resolvePushDiagnostics(snapshot) {
1234
- const state = this.openByUri.get(snapshot.uri);
1258
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1235
1259
  if (!state?.lastPublish)
1236
1260
  return { status: "missing" };
1237
1261
  const publish = state.lastPublish;
@@ -1245,7 +1269,7 @@ class WorkspaceDocumentState {
1245
1269
  return waitMs === 0 ? { status: "ready", diagnostics: publish.diagnostics } : { status: "wait", waitMs };
1246
1270
  }
1247
1271
  waitForDiagnosticsActivity(snapshot, timeoutMs) {
1248
- const state = this.openByUri.get(snapshot.uri);
1272
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1249
1273
  if (!state || timeoutMs <= 0)
1250
1274
  return Promise.resolve();
1251
1275
  return new Promise((resolveActivity) => {
@@ -1254,11 +1278,11 @@ class WorkspaceDocumentState {
1254
1278
  if (settled)
1255
1279
  return;
1256
1280
  settled = true;
1257
- clearTimeout(timer);
1281
+ this.timerProvider.clearTimeout(timer);
1258
1282
  state.waiters.delete(finish);
1259
1283
  resolveActivity();
1260
1284
  };
1261
- const timer = setTimeout(finish, timeoutMs);
1285
+ const timer = this.timerProvider.setTimeout(finish, timeoutMs);
1262
1286
  if (typeof timer.unref === "function")
1263
1287
  timer.unref();
1264
1288
  state.waiters.add(finish);
@@ -1366,7 +1390,7 @@ class WorkspaceDocumentState {
1366
1390
  waiters: new Set
1367
1391
  };
1368
1392
  this.openDocuments.set(path, state);
1369
- this.openByUri.set(state.uri, state);
1393
+ this.openByUri.set(normalizeDocumentUri(state.uri), state);
1370
1394
  this.notifyWaiters(state);
1371
1395
  await this.sendNotification("textDocument/didOpen", {
1372
1396
  textDocument: { uri: state.uri, languageId: state.languageId, version: state.version, text }
@@ -1391,7 +1415,7 @@ class WorkspaceDocumentState {
1391
1415
  }
1392
1416
  async closeDocument(state) {
1393
1417
  this.openDocuments.delete(state.path);
1394
- this.openByUri.delete(state.uri);
1418
+ this.openByUri.delete(normalizeDocumentUri(state.uri));
1395
1419
  this.clearDiagnostics(state.uri);
1396
1420
  this.notifyWaiters(state);
1397
1421
  await this.sendNotification("textDocument/didClose", { textDocument: { uri: state.uri } });
@@ -2478,6 +2502,7 @@ class LspClient extends LspClientConnection {
2478
2502
  this.diagnosticPullErrors = [];
2479
2503
  this.diagnosticsFreshnessTimeoutMs = options.diagnosticsFreshnessTimeoutMs ?? DIAGNOSTICS_FRESHNESS_TIMEOUT_MS;
2480
2504
  this.documents = new WorkspaceDocumentState((method, params) => this.sendNotification(method, params), (uri) => this.diagnosticsStore.delete(uri), {
2505
+ timerProvider: this.timerProvider,
2481
2506
  versionlessPublishQuiescenceMs: options.versionlessPublishQuiescenceMs ?? VERSIONLESS_PUBLISH_QUIESCENCE_MS
2482
2507
  });
2483
2508
  this.workspaceMutations = new WorkspaceMutationController(root, this.documents);
@@ -2581,7 +2606,7 @@ class LspClient extends LspClientConnection {
2581
2606
  const absPath = this.resolveWorkspacePath(filePath);
2582
2607
  const uri = pathToFileURL3(absPath).href;
2583
2608
  await this.openFile(absPath);
2584
- const deadlineAt = Date.now() + this.diagnosticsFreshnessTimeoutMs;
2609
+ const deadlineAt = this.timerProvider.now() + this.diagnosticsFreshnessTimeoutMs;
2585
2610
  for (;; ) {
2586
2611
  signal?.throwIfAborted();
2587
2612
  const snapshot = this.documents.captureDiagnosticSnapshot(absPath);
@@ -2594,7 +2619,7 @@ class LspClient extends LspClientConnection {
2594
2619
  if (!pushFallbackOnly) {
2595
2620
  const cached = this.documents.getPullCache(snapshot);
2596
2621
  try {
2597
- const remainingMs2 = deadlineAt - Date.now();
2622
+ const remainingMs2 = deadlineAt - this.timerProvider.now();
2598
2623
  if (remainingMs2 <= 0)
2599
2624
  return this.freshnessTimeout(absPath);
2600
2625
  const result = await this.sendRequest("textDocument/diagnostic", {
@@ -2629,7 +2654,7 @@ class LspClient extends LspClientConnection {
2629
2654
  }
2630
2655
  if (!pushFallbackOnly)
2631
2656
  continue;
2632
- const remainingMs = deadlineAt - Date.now();
2657
+ const remainingMs = deadlineAt - this.timerProvider.now();
2633
2658
  if (remainingMs <= 0) {
2634
2659
  if (!this.isDiagnosticPullSupported() && snapshot.publishGeneration === 0) {
2635
2660
  const cached = this.documents.getPullCache(snapshot);
@@ -596,6 +596,13 @@ import { pathToFileURL as pathToFileURL3 } from "node:url";
596
596
  // ../lsp-core/src/lsp/connection.ts
597
597
  import { pathToFileURL } from "node:url";
598
598
 
599
+ // ../lsp-core/src/lsp/timer-provider.ts
600
+ var realTimerProvider = {
601
+ now: () => Date.now(),
602
+ setTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
603
+ clearTimeout: (handle) => clearTimeout(handle)
604
+ };
605
+
599
606
  // ../lsp-core/src/lsp/constants.ts
600
607
  var DEFAULT_MAX_REFERENCES = 200;
601
608
  var DEFAULT_MAX_SYMBOLS = 200;
@@ -1135,6 +1142,7 @@ class LspClientTransport {
1135
1142
  this.documentFormattingSupported = false;
1136
1143
  this.requestTimeoutMs = timeouts.requestTimeoutMs ?? REQUEST_TIMEOUT_MS;
1137
1144
  this.initializeTimeoutMs = timeouts.initializeTimeoutMs ?? INIT_TIMEOUT_MS;
1145
+ this.timerProvider = timeouts.timerProvider ?? realTimerProvider;
1138
1146
  }
1139
1147
  pid() {
1140
1148
  return this.proc?.pid;
@@ -1235,7 +1243,7 @@ class LspClientTransport {
1235
1243
  const options = args[1];
1236
1244
  const timeoutMs = options?.timeoutMs ?? this.requestTimeoutMs;
1237
1245
  const timeoutController = new AbortController;
1238
- const timeoutHandle = setTimeout(() => {
1246
+ const timeoutHandle = this.timerProvider.setTimeout(() => {
1239
1247
  const stderrTail = this.stderrBuffer.slice(-5).join(`
1240
1248
  `);
1241
1249
  timeoutController.abort(new LspRequestTimeoutError(method, stderrTail || undefined));
@@ -1254,7 +1262,7 @@ class LspClientTransport {
1254
1262
  }
1255
1263
  throw error;
1256
1264
  } finally {
1257
- clearTimeout(timeoutHandle);
1265
+ this.timerProvider.clearTimeout(timeoutHandle);
1258
1266
  combinedSignal.dispose();
1259
1267
  }
1260
1268
  }
@@ -1635,6 +1643,17 @@ function canonicalPath(filePath) {
1635
1643
  return absolute;
1636
1644
  }
1637
1645
  }
1646
+ function normalizeDocumentUri(uri) {
1647
+ let decoded = uri;
1648
+ try {
1649
+ decoded = decodeURIComponent(uri);
1650
+ } catch {
1651
+ decoded = uri;
1652
+ }
1653
+ if (process.platform !== "win32")
1654
+ return decoded;
1655
+ return decoded.replace(/^(file:\/\/\/)([a-z]):/, (_match, prefix, drive) => `${prefix}${drive.toUpperCase()}:`);
1656
+ }
1638
1657
  function isSameOrDescendant(candidate, parent) {
1639
1658
  const suffix = relative2(parent, candidate);
1640
1659
  return suffix === "" || !suffix.startsWith("..") && suffix !== "..";
@@ -1651,7 +1670,12 @@ class WorkspaceDocumentState {
1651
1670
  this.openDocuments = new Map;
1652
1671
  this.openByUri = new Map;
1653
1672
  this.openPromises = new Map;
1654
- this.now = options.now ?? (() => Date.now());
1673
+ this.timerProvider = options.timerProvider ?? {
1674
+ now: options.now ?? (() => Date.now()),
1675
+ setTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
1676
+ clearTimeout: (handle) => clearTimeout(handle)
1677
+ };
1678
+ this.now = () => this.timerProvider.now();
1655
1679
  this.versionlessPublishQuiescenceMs = options.versionlessPublishQuiescenceMs ?? DEFAULT_VERSIONLESS_PUBLISH_QUIESCENCE_MS;
1656
1680
  }
1657
1681
  async openFile(filePath) {
@@ -1673,7 +1697,7 @@ class WorkspaceDocumentState {
1673
1697
  return this.openDocuments.get(canonicalPath(filePath))?.version;
1674
1698
  }
1675
1699
  getStoredDiagnostics(uri) {
1676
- const state = this.openByUri.get(uri);
1700
+ const state = this.openByUri.get(normalizeDocumentUri(uri));
1677
1701
  if (!state)
1678
1702
  return [];
1679
1703
  return state.lastPublish?.diagnostics ?? state.pullCache?.diagnostics ?? [];
@@ -1695,13 +1719,13 @@ class WorkspaceDocumentState {
1695
1719
  return state !== undefined && state.uri === snapshot.uri && state.version === snapshot.version && state.generation === snapshot.documentGeneration;
1696
1720
  }
1697
1721
  getPullCache(snapshot) {
1698
- const state = this.openByUri.get(snapshot.uri);
1722
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1699
1723
  if (!state?.pullCache || state.pullCache.documentVersion !== snapshot.version)
1700
1724
  return null;
1701
1725
  return state.pullCache;
1702
1726
  }
1703
1727
  recordPullDiagnostics(snapshot, report) {
1704
- const state = this.openByUri.get(snapshot.uri);
1728
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1705
1729
  if (!state)
1706
1730
  return;
1707
1731
  state.pullCache = {
@@ -1711,7 +1735,7 @@ class WorkspaceDocumentState {
1711
1735
  };
1712
1736
  }
1713
1737
  recordPublishedDiagnostics(params) {
1714
- const state = this.openByUri.get(params.uri);
1738
+ const state = this.openByUri.get(normalizeDocumentUri(params.uri));
1715
1739
  if (!state)
1716
1740
  return;
1717
1741
  state.publishGeneration += 1;
@@ -1725,7 +1749,7 @@ class WorkspaceDocumentState {
1725
1749
  this.notifyWaiters(state);
1726
1750
  }
1727
1751
  resolvePushDiagnostics(snapshot) {
1728
- const state = this.openByUri.get(snapshot.uri);
1752
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1729
1753
  if (!state?.lastPublish)
1730
1754
  return { status: "missing" };
1731
1755
  const publish = state.lastPublish;
@@ -1739,7 +1763,7 @@ class WorkspaceDocumentState {
1739
1763
  return waitMs === 0 ? { status: "ready", diagnostics: publish.diagnostics } : { status: "wait", waitMs };
1740
1764
  }
1741
1765
  waitForDiagnosticsActivity(snapshot, timeoutMs) {
1742
- const state = this.openByUri.get(snapshot.uri);
1766
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1743
1767
  if (!state || timeoutMs <= 0)
1744
1768
  return Promise.resolve();
1745
1769
  return new Promise((resolveActivity) => {
@@ -1748,11 +1772,11 @@ class WorkspaceDocumentState {
1748
1772
  if (settled)
1749
1773
  return;
1750
1774
  settled = true;
1751
- clearTimeout(timer);
1775
+ this.timerProvider.clearTimeout(timer);
1752
1776
  state.waiters.delete(finish);
1753
1777
  resolveActivity();
1754
1778
  };
1755
- const timer = setTimeout(finish, timeoutMs);
1779
+ const timer = this.timerProvider.setTimeout(finish, timeoutMs);
1756
1780
  if (typeof timer.unref === "function")
1757
1781
  timer.unref();
1758
1782
  state.waiters.add(finish);
@@ -1860,7 +1884,7 @@ class WorkspaceDocumentState {
1860
1884
  waiters: new Set
1861
1885
  };
1862
1886
  this.openDocuments.set(path, state);
1863
- this.openByUri.set(state.uri, state);
1887
+ this.openByUri.set(normalizeDocumentUri(state.uri), state);
1864
1888
  this.notifyWaiters(state);
1865
1889
  await this.sendNotification("textDocument/didOpen", {
1866
1890
  textDocument: { uri: state.uri, languageId: state.languageId, version: state.version, text }
@@ -1885,7 +1909,7 @@ class WorkspaceDocumentState {
1885
1909
  }
1886
1910
  async closeDocument(state) {
1887
1911
  this.openDocuments.delete(state.path);
1888
- this.openByUri.delete(state.uri);
1912
+ this.openByUri.delete(normalizeDocumentUri(state.uri));
1889
1913
  this.clearDiagnostics(state.uri);
1890
1914
  this.notifyWaiters(state);
1891
1915
  await this.sendNotification("textDocument/didClose", { textDocument: { uri: state.uri } });
@@ -2972,6 +2996,7 @@ class LspClient extends LspClientConnection {
2972
2996
  this.diagnosticPullErrors = [];
2973
2997
  this.diagnosticsFreshnessTimeoutMs = options.diagnosticsFreshnessTimeoutMs ?? DIAGNOSTICS_FRESHNESS_TIMEOUT_MS;
2974
2998
  this.documents = new WorkspaceDocumentState((method, params) => this.sendNotification(method, params), (uri) => this.diagnosticsStore.delete(uri), {
2999
+ timerProvider: this.timerProvider,
2975
3000
  versionlessPublishQuiescenceMs: options.versionlessPublishQuiescenceMs ?? VERSIONLESS_PUBLISH_QUIESCENCE_MS
2976
3001
  });
2977
3002
  this.workspaceMutations = new WorkspaceMutationController(root, this.documents);
@@ -3075,7 +3100,7 @@ class LspClient extends LspClientConnection {
3075
3100
  const absPath = this.resolveWorkspacePath(filePath);
3076
3101
  const uri = pathToFileURL3(absPath).href;
3077
3102
  await this.openFile(absPath);
3078
- const deadlineAt = Date.now() + this.diagnosticsFreshnessTimeoutMs;
3103
+ const deadlineAt = this.timerProvider.now() + this.diagnosticsFreshnessTimeoutMs;
3079
3104
  for (;; ) {
3080
3105
  signal?.throwIfAborted();
3081
3106
  const snapshot = this.documents.captureDiagnosticSnapshot(absPath);
@@ -3088,7 +3113,7 @@ class LspClient extends LspClientConnection {
3088
3113
  if (!pushFallbackOnly) {
3089
3114
  const cached = this.documents.getPullCache(snapshot);
3090
3115
  try {
3091
- const remainingMs2 = deadlineAt - Date.now();
3116
+ const remainingMs2 = deadlineAt - this.timerProvider.now();
3092
3117
  if (remainingMs2 <= 0)
3093
3118
  return this.freshnessTimeout(absPath);
3094
3119
  const result = await this.sendRequest("textDocument/diagnostic", {
@@ -3123,7 +3148,7 @@ class LspClient extends LspClientConnection {
3123
3148
  }
3124
3149
  if (!pushFallbackOnly)
3125
3150
  continue;
3126
- const remainingMs = deadlineAt - Date.now();
3151
+ const remainingMs = deadlineAt - this.timerProvider.now();
3127
3152
  if (remainingMs <= 0) {
3128
3153
  if (!this.isDiagnosticPullSupported() && snapshot.publishGeneration === 0) {
3129
3154
  const cached = this.documents.getPullCache(snapshot);