@mrclrchtr/supi-lsp 6.4.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +35 -13
  2. package/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
  3. package/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +8 -1
  4. package/node_modules/@mrclrchtr/supi-core/README.md +8 -0
  5. package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
  6. package/node_modules/@mrclrchtr/supi-core/src/footer-registry.ts +10 -3
  7. package/node_modules/@mrclrchtr/supi-core/src/index.ts +2 -0
  8. package/node_modules/@mrclrchtr/supi-core/src/llm.ts +141 -16
  9. package/node_modules/ignore/index.js +3 -1
  10. package/node_modules/ignore/legacy.js +3 -1
  11. package/node_modules/ignore/package.json +1 -1
  12. package/package.json +3 -3
  13. package/src/api.ts +6 -0
  14. package/src/client/client-diagnostic-cache.ts +43 -35
  15. package/src/client/client-diagnostic-capabilities.ts +83 -17
  16. package/src/client/client-diagnostic-collection.ts +108 -92
  17. package/src/client/client-diagnostic-evidence.ts +44 -82
  18. package/src/client/client-diagnostic-host.ts +3 -4
  19. package/src/client/client-diagnostic-publication.ts +9 -68
  20. package/src/client/client-diagnostic-pull.ts +45 -58
  21. package/src/client/client-diagnostic-refresh.ts +230 -331
  22. package/src/client/client-diagnostic-request.ts +201 -1
  23. package/src/client/client-diagnostic-timing.ts +129 -70
  24. package/src/client/client-diagnostic-typescript.ts +395 -0
  25. package/src/client/client-diagnostic-waiters.ts +8 -12
  26. package/src/client/client-diagnostics.ts +685 -183
  27. package/src/client/client-document-state.ts +2 -2
  28. package/src/client/client-document-sync.ts +60 -60
  29. package/src/client/client-request-enrollment.ts +75 -0
  30. package/src/client/client-semantic-input-barrier.ts +443 -0
  31. package/src/client/client-semantic-input-errors.ts +30 -0
  32. package/src/client/client-semantic-input-file.ts +15 -0
  33. package/src/client/client.ts +290 -37
  34. package/src/client/transport.ts +72 -16
  35. package/src/config/capabilities.ts +1 -0
  36. package/src/config/tsconfig-scope.ts +30 -4
  37. package/src/diagnostics/evidence.ts +1 -1
  38. package/src/manager/manager-diagnostics.ts +10 -4
  39. package/src/manager/manager-process-crash-report.ts +50 -1
  40. package/src/manager/manager-workspace-recovery.ts +11 -7
  41. package/src/manager/manager.ts +608 -45
  42. package/src/session/runtime-diagnostic-surface.ts +3 -1
  43. package/src/session/runtime-diagnostics.ts +37 -4
  44. package/src/session/runtime-registry.ts +31 -11
  45. package/src/session/workspace-lsp-runtime.ts +19 -3
@@ -14,6 +14,8 @@ import type {
14
14
  */
15
15
  export interface ProcessCrashDiagnosticDemand {
16
16
  readonly scopes?: readonly string[];
17
+ /** Allow one bounded retry for failed routes during explicit health refresh. */
18
+ readonly explicit?: boolean;
17
19
  }
18
20
 
19
21
  /** Diagnostic and recovery operations owned by a workspace LSP runtime. */
@@ -45,7 +47,7 @@ export interface WorkspaceLspDiagnosticSurface {
45
47
  quietMs?: number;
46
48
  /** Evidence from a refresh the caller already completed; skips this pass's own refresh when no watched-file changes apply. */
47
49
  initialEvidence?: DiagnosticEvidenceSummary;
48
- /** Explicit demand to recover crashed routes with tracked files in scope. */
50
+ /** Explicit demand to retry crashed and failed routes in scope. */
49
51
  processCrashDemand?: ProcessCrashDiagnosticDemand;
50
52
  control?: CodeRequestControl;
51
53
  }): Promise<RecoverDiagnosticsResult>;
@@ -52,8 +52,8 @@ export type ProcessCrashRecoveryOutcome =
52
52
  | "recovery-failed"
53
53
  | "recovery-exhausted";
54
54
 
55
- /** Typed next action for a non-recovered process-crash route. */
56
- export type ProcessCrashRecoveryNextAction = "use-exact-file" | "reload-workspace";
55
+ /** Typed next action for a route that needs another explicit health refresh. */
56
+ export type ProcessCrashRecoveryNextAction = "use-exact-file" | "refresh";
57
57
 
58
58
  /** One bounded route entry in a process-crash recovery report. */
59
59
  export interface ProcessCrashRecoveryEntry {
@@ -84,6 +84,29 @@ export interface ProcessCrashRecoveryReport {
84
84
  readonly omittedEntries: number;
85
85
  }
86
86
 
87
+ /** Stable outcome for one initial-start route handled by explicit refresh. */
88
+ export type StartupRetryOutcome = "recovered" | "retry-failed";
89
+
90
+ /** Typed next action for a failed initial-start retry. */
91
+ export type StartupRetryNextAction = "refresh";
92
+
93
+ /** One bounded route entry in an initial-start retry report. */
94
+ export interface StartupRetryEntry {
95
+ readonly name: string;
96
+ readonly root: string;
97
+ readonly outcome: StartupRetryOutcome;
98
+ readonly nextAction?: StartupRetryNextAction;
99
+ readonly failureMessage?: string;
100
+ }
101
+
102
+ /** Bounded result of explicit retries for initial-start routes. */
103
+ export interface StartupRetryReport {
104
+ readonly recoveredRoutes: number;
105
+ readonly failedRoutes: number;
106
+ readonly entries: readonly StartupRetryEntry[];
107
+ readonly omittedEntries: number;
108
+ }
109
+
87
110
  /** Create the empty outcome for a pass with no process-crash demand. */
88
111
  export function emptyProcessCrashRecoveryReport(): ProcessCrashRecoveryReport {
89
112
  return {
@@ -96,6 +119,11 @@ export function emptyProcessCrashRecoveryReport(): ProcessCrashRecoveryReport {
96
119
  };
97
120
  }
98
121
 
122
+ /** Create the empty outcome for a pass with no initial-start retry. */
123
+ export function emptyStartupRetryReport(): StartupRetryReport {
124
+ return { recoveredRoutes: 0, failedRoutes: 0, entries: [], omittedEntries: 0 };
125
+ }
126
+
99
127
  /** Result from a workspace diagnostic recovery pass. */
100
128
  export interface RecoverDiagnosticsResult {
101
129
  /** Active clients targeted by the best-effort refresh, not confirmed successful refreshes. */
@@ -104,6 +132,8 @@ export interface RecoverDiagnosticsResult {
104
132
  restartedClients: number;
105
133
  /** Separate outcome for process-crash route recovery selected by this pass. */
106
134
  processCrashRecovery: ProcessCrashRecoveryReport;
135
+ /** Separate outcome for explicit retries of failed initial-start routes. */
136
+ startupRetry: StartupRetryReport;
107
137
  /** Evidence collected by the refresh and recovery operations. */
108
138
  diagnosticEvidence: DiagnosticEvidenceSummary;
109
139
  /** Final diagnostic report captured after all refresh and recovery work. */
@@ -128,7 +158,10 @@ export interface ScopeDecisionEntry {
128
158
  basis: string | null;
129
159
  }
130
160
 
131
- /** Aggregate tsconfig scope decisions for all tracked files, for debug telemetry. */
161
+ /**
162
+ * Aggregate tsconfig scope decisions for automatic-scope TypeScript/JavaScript-family
163
+ * tracked files, for debug telemetry.
164
+ */
132
165
  export interface ScopeDecisionSummary {
133
166
  caseSensitiveFileNames: boolean;
134
167
  counts: {
@@ -141,6 +174,6 @@ export interface ScopeDecisionSummary {
141
174
  basisCounts: Record<string, number>;
142
175
  /** Bounded workspace-relative entries (oldest first), not the full set. */
143
176
  entries: ScopeDecisionEntry[];
144
- /** Total number of tracked files the summary was computed over. */
177
+ /** Total number of automatic-scope TypeScript/JavaScript-family tracked files covered. */
145
178
  totalFiles: number;
146
179
  }
@@ -41,6 +41,7 @@ import type {
41
41
  DiagnosticEvidenceSummary,
42
42
  ProcessCrashRecoveryReport,
43
43
  RecoverDiagnosticsResult,
44
+ StartupRetryReport,
44
45
  } from "./runtime-diagnostics.ts";
45
46
  import type {
46
47
  BulkTrackFilesResult,
@@ -59,6 +60,7 @@ export {
59
60
  type DiagnosticEvidenceStatus,
60
61
  type DiagnosticEvidenceSummary,
61
62
  emptyProcessCrashRecoveryReport,
63
+ emptyStartupRetryReport,
62
64
  MAX_PROCESS_CRASH_RECOVERY_ENTRIES,
63
65
  type OutstandingDiagnosticSummaryEntry,
64
66
  type ProcessCrashRecoveryEntry,
@@ -66,6 +68,10 @@ export {
66
68
  type ProcessCrashRecoveryOutcome,
67
69
  type ProcessCrashRecoveryReport,
68
70
  type RecoverDiagnosticsResult,
71
+ type StartupRetryEntry,
72
+ type StartupRetryNextAction,
73
+ type StartupRetryOutcome,
74
+ type StartupRetryReport,
69
75
  type WorkspaceDiagnosticReport,
70
76
  type WorkspaceDiagnosticSnapshot,
71
77
  type WorkspaceDiagnosticSummaryEntry,
@@ -270,11 +276,11 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
270
276
  */
271
277
  async waitUntilReadyForFile(
272
278
  filePath: string,
273
- options: { timeoutMs?: number } = {},
279
+ options: { timeoutMs?: number; retryFailedRoute?: boolean } = {},
274
280
  control?: CodeRequestControl,
275
281
  ): Promise<SemanticReadinessResult> {
276
282
  const resolvedPath = this.resolveFilePath(filePath);
277
- if (!this.manager.canServeFile(resolvedPath)) {
283
+ if (!options.retryFailedRoute && !this.manager.canServeFile(resolvedPath)) {
278
284
  const processCrashRecovery = this.manager.getProcessCrashRecoveryReportForFile(resolvedPath);
279
285
  return {
280
286
  kind: "unavailable",
@@ -284,31 +290,44 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
284
290
  }
285
291
 
286
292
  let eagerProcessCrashRecovery: ProcessCrashRecoveryReport | undefined;
293
+ let eagerStartupRetry: StartupRetryReport | undefined;
287
294
  const readiness = await raceReadinessValue(
288
- this.manager.waitUntilFileReady(resolvedPath, control, (report) => {
289
- eagerProcessCrashRecovery = report;
295
+ this.manager.waitUntilFileReady(resolvedPath, control, {
296
+ retryFailedRoute: options.retryFailedRoute === true,
297
+ onProcessCrashRecovery: (report) => {
298
+ eagerProcessCrashRecovery = report;
299
+ },
300
+ onStartupRetry: (report) => {
301
+ eagerStartupRetry = report;
302
+ },
290
303
  }),
291
304
  options.timeoutMs,
292
305
  control,
293
306
  );
294
307
  if (readiness.kind !== "resolved") {
295
- // A timeout can happen before shared recovery settles. Do not create a
296
- // route outcome for work that has no final result yet.
308
+ // A timeout can happen before shared recovery settles. Keep only route
309
+ // outcomes that completed before the timeout.
297
310
  const currentProcessCrashRecovery =
298
311
  this.manager.getProcessCrashRecoveryReportForFile(resolvedPath);
299
312
  const processCrashRecovery = currentProcessCrashRecovery ?? eagerProcessCrashRecovery;
300
- return processCrashRecovery ? { ...readiness, processCrashRecovery } : readiness;
313
+ return {
314
+ ...readiness,
315
+ ...(eagerStartupRetry ? { startupRetry: eagerStartupRetry } : {}),
316
+ ...(processCrashRecovery ? { processCrashRecovery } : {}),
317
+ };
301
318
  }
302
- const { client, processCrashRecovery } = readiness.value;
319
+ const { client, processCrashRecovery, startupRetry } = readiness.value;
303
320
  const recovery = hasProcessCrashRecovery(processCrashRecovery) ? { processCrashRecovery } : {};
321
+ const startup = startupRetry && startupRetry.entries.length > 0 ? { startupRetry } : {};
304
322
  if (!client) {
305
323
  return {
306
324
  kind: "unavailable",
307
325
  reason: "The routed LSP client could not be started for this file",
326
+ ...startup,
308
327
  ...recovery,
309
328
  };
310
329
  }
311
- return { kind: "ready", ...recovery };
330
+ return { kind: "ready", ...startup, ...recovery };
312
331
  }
313
332
 
314
333
  /**
@@ -433,14 +452,14 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
433
452
  return this.manager.getOutstandingDiagnosticSummarySnapshot(maxSeverity);
434
453
  }
435
454
 
436
- /** Trigger a workspace-wide diagnostics refresh and stale-state recovery pass. */
455
+ /** Retry failed routes and run a workspace-wide diagnostic recovery pass. */
437
456
  async recoverDiagnostics(options?: {
438
457
  restartIfStillStale?: boolean;
439
458
  maxWaitMs?: number;
440
459
  quietMs?: number;
441
460
  /** Evidence from a refresh the caller already completed; skips this pass's own refresh when no watched-file changes apply. */
442
461
  initialEvidence?: DiagnosticEvidenceSummary;
443
- /** Explicit demand to recover crashed routes with tracked files in scope. */
462
+ /** Explicit demand to retry failed startup and crashed routes in scope. */
444
463
  processCrashDemand?: import("./runtime-diagnostic-surface.ts").ProcessCrashDiagnosticDemand;
445
464
  control?: CodeRequestControl;
446
465
  }): Promise<RecoverDiagnosticsResult> {
@@ -460,6 +479,7 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
460
479
  attemptedClients: result.attemptedClients,
461
480
  restartedClients: result.restartedClients,
462
481
  processCrashRecovery: result.processCrashRecovery,
482
+ startupRetry: result.startupRetry,
463
483
  attemptedServers: boundServerNames(result.attemptedServers ?? []),
464
484
  restartedServers: boundServerNames(result.restartedServers ?? []),
465
485
  ...(result.restartReason ? { reason: result.restartReason } : {}),
@@ -19,7 +19,7 @@ import type {
19
19
  } from "../diagnostics/workspace-sentinels.ts";
20
20
  import type { WorkspaceSourceInventory } from "../diagnostics/workspace-sources.ts";
21
21
  import type { WorkspaceLspDiagnosticSurface } from "./runtime-diagnostic-surface.ts";
22
- import type { ProcessCrashRecoveryReport } from "./runtime-diagnostics.ts";
22
+ import type { ProcessCrashRecoveryReport, StartupRetryReport } from "./runtime-diagnostics.ts";
23
23
 
24
24
  /** Maximum number of files processed by one automatic bulk-tracking call. */
25
25
  export const MAX_BULK_TRACK_FILES = 256;
@@ -34,17 +34,23 @@ export type WorkspaceLspRuntimeState =
34
34
  export type SemanticReadinessResult =
35
35
  | {
36
36
  kind: "ready";
37
+ /** Initial-start retry observed while establishing file readiness. */
38
+ startupRetry?: StartupRetryReport;
37
39
  /** Process-crash route recovery observed while establishing file readiness. */
38
40
  processCrashRecovery?: ProcessCrashRecoveryReport;
39
41
  }
40
42
  | {
41
43
  kind: "timeout";
44
+ /** Initial-start retry observed before the readiness timeout. */
45
+ startupRetry?: StartupRetryReport;
42
46
  /** Process-crash route recovery observed before the readiness timeout. */
43
47
  processCrashRecovery?: ProcessCrashRecoveryReport;
44
48
  }
45
49
  | {
46
50
  kind: "unavailable";
47
51
  reason: string;
52
+ /** Initial-start retry observed before readiness became unavailable. */
53
+ startupRetry?: StartupRetryReport;
48
54
  /** Process-crash route recovery observed before readiness became unavailable. */
49
55
  processCrashRecovery?: ProcessCrashRecoveryReport;
50
56
  };
@@ -61,9 +67,15 @@ export interface RoutedMutationResponse<T> {
61
67
  export type BulkTrackFileOutcome =
62
68
  | { readonly file: string; readonly kind: "tracked" }
63
69
  | { readonly file: string; readonly kind: "already-tracked" }
70
+ /**
71
+ * Automatic tracking skipped this candidate. This includes policy-excluded
72
+ * paths, unsupported automatic routes, missing paths, and paths that are no
73
+ * longer regular. The coarse reason does not prove one cause or that an
74
+ * explicit request cannot be served.
75
+ */
64
76
  | {
65
77
  readonly file: string;
66
- readonly kind: "unsupported";
78
+ readonly kind: "skipped";
67
79
  readonly reason: "missing" | "not-automatic-source";
68
80
  }
69
81
  | { readonly file: string; readonly kind: "unavailable"; readonly reason: string };
@@ -124,9 +136,13 @@ export interface WorkspaceLspRuntime extends WorkspaceLspDiagnosticSurface {
124
136
  control?: CodeRequestControl,
125
137
  ): Promise<RoutedMutationResponse<CodeAction[] | null> | null>;
126
138
  getOpenDocumentVersion(filePath: string): number | null;
139
+ /**
140
+ * Wait for file readiness; an explicit refresh may make one shared route
141
+ * retry for this call without changing ordinary request recovery limits.
142
+ */
127
143
  waitUntilReadyForFile(
128
144
  filePath: string,
129
- options?: { timeoutMs?: number },
145
+ options?: { timeoutMs?: number; retryFailedRoute?: boolean },
130
146
  control?: CodeRequestControl,
131
147
  ): Promise<SemanticReadinessResult>;
132
148
  waitUntilReadyForWorkspace(