@mrclrchtr/supi-code-intelligence 4.10.0 → 5.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 (203) hide show
  1. package/README.md +2 -1
  2. package/node_modules/@mrclrchtr/supi-code-runtime/README.md +2 -0
  3. package/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
  4. package/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +9 -0
  5. package/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +53 -13
  6. package/node_modules/@mrclrchtr/supi-code-runtime/src/request-control.ts +47 -0
  7. package/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +13 -1
  8. package/node_modules/@mrclrchtr/supi-core/README.md +2 -0
  9. package/node_modules/@mrclrchtr/supi-core/package.json +1 -1
  10. package/node_modules/@mrclrchtr/supi-core/src/config/config.ts +31 -0
  11. package/node_modules/@mrclrchtr/supi-core/src/config.ts +2 -0
  12. package/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +19 -3
  13. package/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +3 -0
  14. package/node_modules/@mrclrchtr/supi-lsp/README.md +80 -5
  15. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/README.md +2 -0
  16. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
  17. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +9 -0
  18. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +53 -13
  19. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/request-control.ts +47 -0
  20. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +13 -1
  21. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/README.md +2 -0
  22. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/package.json +1 -1
  23. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/config/config.ts +31 -0
  24. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/config.ts +2 -0
  25. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +19 -3
  26. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +3 -0
  27. package/node_modules/@mrclrchtr/supi-lsp/package.json +7 -6
  28. package/node_modules/@mrclrchtr/supi-lsp/src/api.ts +10 -0
  29. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-cache.ts +206 -0
  30. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-capabilities.ts +78 -0
  31. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-collection.ts +114 -0
  32. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-evidence.ts +372 -0
  33. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-host.ts +14 -0
  34. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-pull.ts +62 -0
  35. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-refresh.ts +491 -0
  36. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-request.ts +9 -0
  37. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-timing.ts +71 -11
  38. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-waiters.ts +206 -0
  39. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostics.ts +365 -297
  40. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-document-state.ts +52 -0
  41. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-document-sync.ts +185 -0
  42. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-file-state.ts +25 -0
  43. package/node_modules/@mrclrchtr/supi-lsp/src/client/client.ts +467 -115
  44. package/node_modules/@mrclrchtr/supi-lsp/src/client/transport.ts +161 -33
  45. package/node_modules/@mrclrchtr/supi-lsp/src/config/capabilities.ts +10 -1
  46. package/node_modules/@mrclrchtr/supi-lsp/src/config/defaults.json +1 -1
  47. package/node_modules/@mrclrchtr/supi-lsp/src/debug-telemetry.ts +45 -0
  48. package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/evidence.ts +38 -0
  49. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-client-state.ts +79 -9
  50. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-diagnostics.ts +13 -4
  51. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-recovery.ts +300 -24
  52. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-symbol.ts +5 -2
  53. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager.ts +464 -96
  54. package/node_modules/@mrclrchtr/supi-lsp/src/provider/lsp-refactor-provider.ts +130 -0
  55. package/node_modules/@mrclrchtr/supi-lsp/src/provider/lsp-semantic-provider.ts +45 -329
  56. package/node_modules/@mrclrchtr/supi-lsp/src/provider/refactor-planning.ts +57 -120
  57. package/node_modules/@mrclrchtr/supi-lsp/src/provider/semantic-edit-normalizer.ts +320 -0
  58. package/node_modules/@mrclrchtr/supi-lsp/src/provider/semantic-symbol-mapper.ts +207 -0
  59. package/node_modules/@mrclrchtr/supi-lsp/src/session/readiness.ts +72 -2
  60. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-controller.ts +151 -26
  61. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-diagnostic-surface.ts +40 -0
  62. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-diagnostics.ts +50 -0
  63. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-registry.ts +136 -120
  64. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-transition-debug.ts +49 -0
  65. package/node_modules/@mrclrchtr/supi-lsp/src/session/workspace-lsp-runtime.ts +102 -0
  66. package/node_modules/@mrclrchtr/supi-tree-sitter/README.md +17 -7
  67. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/README.md +2 -0
  68. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
  69. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +9 -0
  70. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +53 -13
  71. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/request-control.ts +47 -0
  72. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +13 -1
  73. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/README.md +2 -0
  74. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/package.json +1 -1
  75. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/config/config.ts +31 -0
  76. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/config.ts +2 -0
  77. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +19 -3
  78. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +3 -0
  79. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/LICENSE +21 -0
  80. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/README.md +258 -0
  81. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/dist/babel.cjs +257 -0
  82. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/dist/jiti.cjs +1 -0
  83. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-cli.mjs +34 -0
  84. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-hooks.mjs +124 -0
  85. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-native.mjs +121 -0
  86. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-register.d.mts +1 -0
  87. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-register.mjs +4 -0
  88. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-static.mjs +23 -0
  89. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.cjs +30 -0
  90. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.d.cts +8 -0
  91. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.d.mts +8 -0
  92. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.mjs +29 -0
  93. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/types.d.ts +420 -0
  94. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/package.json +146 -0
  95. package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +6 -3
  96. package/node_modules/@mrclrchtr/supi-tree-sitter/src/api.ts +0 -9
  97. package/node_modules/@mrclrchtr/supi-tree-sitter/src/index.ts +0 -8
  98. package/node_modules/@mrclrchtr/supi-tree-sitter/src/provider/tree-sitter-provider.ts +16 -12
  99. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/runtime-controller.ts +65 -87
  100. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/session.ts +47 -95
  101. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-timing.ts +147 -0
  102. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-client-lifecycle.ts +39 -0
  103. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-client.ts +561 -0
  104. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-message-size.ts +24 -0
  105. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-protocol.ts +452 -0
  106. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/call-sites.ts +4 -2
  107. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/callees.ts +12 -4
  108. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/exports.ts +4 -2
  109. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/imports.ts +4 -2
  110. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/node-at.ts +5 -3
  111. package/node_modules/@mrclrchtr/supi-tree-sitter/src/types.ts +33 -12
  112. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/blocking-test-bootstrap.mjs +34 -0
  113. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/bootstrap.mjs +8 -0
  114. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/parsed-file-store-helpers.ts +23 -0
  115. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/parsed-file-store.ts +400 -0
  116. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/request-control.ts +48 -0
  117. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/runtime-parser-helpers.ts +24 -0
  118. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/runtime-query-helpers.ts +43 -0
  119. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/runtime.ts +421 -0
  120. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/service.ts +116 -0
  121. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/worker-main.ts +201 -0
  122. package/package.json +5 -5
  123. package/src/analysis/health/diagnostics.ts +236 -24
  124. package/src/analysis/health/recovery.ts +6 -2
  125. package/src/analysis/provider.ts +58 -0
  126. package/src/analysis/readiness.ts +30 -9
  127. package/src/analysis/refactor/apply.ts +45 -1
  128. package/src/analysis/refactor/mutation-authority.ts +143 -0
  129. package/src/analysis/relations/callees.ts +9 -1
  130. package/src/analysis/relations/types.ts +5 -2
  131. package/src/analysis/search/ast-scan-timing.ts +9 -2
  132. package/src/analysis/search/ast-scan.ts +1 -1
  133. package/src/analysis/search/deadline.ts +2 -2
  134. package/src/analysis/search/pattern-analysis.ts +46 -32
  135. package/src/analysis/search/pattern.ts +12 -2
  136. package/src/analysis/target/anchored.ts +20 -11
  137. package/src/analysis/target/file.ts +18 -11
  138. package/src/analysis/target/identity.ts +19 -3
  139. package/src/analysis/target/symbol.ts +36 -15
  140. package/src/api.ts +4 -0
  141. package/src/diagnostics/evidence.ts +51 -0
  142. package/src/session/capability-adapter.ts +12 -3
  143. package/src/session/find-workflow.ts +17 -7
  144. package/src/session/graph/collect.ts +18 -2
  145. package/src/session/graph-workflow.ts +19 -12
  146. package/src/session/health-refresh.ts +148 -0
  147. package/src/session/health-types.ts +37 -15
  148. package/src/session/health-workflow.ts +37 -39
  149. package/src/session/inspect/collect.ts +20 -3
  150. package/src/session/inspect-workflow.ts +10 -5
  151. package/src/session/orientation/collect.ts +10 -1
  152. package/src/session/orientation/context-facts.ts +3 -1
  153. package/src/session/orientation/context-sections.ts +20 -7
  154. package/src/session/orientation/gather.ts +17 -11
  155. package/src/session/orientation-types.ts +2 -1
  156. package/src/session/orientation-workflow.ts +15 -8
  157. package/src/session/refactor-plans.ts +2 -0
  158. package/src/session/refactor-workflow.ts +59 -14
  159. package/src/session/session.ts +4 -1
  160. package/src/session/target-workflow.ts +54 -23
  161. package/src/session/workflow-control.ts +7 -3
  162. package/src/substrate/lsp/lifecycle.ts +26 -46
  163. package/src/substrate/lsp/maintenance.ts +199 -25
  164. package/src/substrate/lsp/state.ts +2 -2
  165. package/src/substrate/workspace-provider-host.ts +25 -3
  166. package/src/tool/find/execute.ts +7 -1
  167. package/src/tool/find/render.ts +20 -3
  168. package/src/tool/find/tui.ts +23 -21
  169. package/src/tool/graph/execute.ts +23 -3
  170. package/src/tool/graph/tui.ts +59 -46
  171. package/src/tool/health/execute.ts +7 -2
  172. package/src/tool/health/markdown.ts +56 -14
  173. package/src/tool/health/refresh-status.ts +105 -0
  174. package/src/tool/health/tui.ts +95 -98
  175. package/src/tool/infra/workflow-control.ts +8 -0
  176. package/src/tool/inspect/execute.ts +7 -1
  177. package/src/tool/inspect/tui.ts +26 -18
  178. package/src/tool/orientation/execute.ts +21 -3
  179. package/src/tool/orientation/tui.ts +51 -35
  180. package/src/tool/refactor-apply/execute.ts +3 -0
  181. package/src/tool/refactor-apply/tui.ts +43 -25
  182. package/src/tool/refactor-plan/execute.ts +4 -0
  183. package/src/tool/refactor-plan/tui.ts +33 -20
  184. package/src/tool/register.ts +127 -22
  185. package/src/tool/resolve/execute.ts +18 -1
  186. package/src/tool/resolve/tui.ts +42 -24
  187. package/src/tool/result/display.ts +107 -0
  188. package/src/tool/result/errors.ts +20 -17
  189. package/src/tool/result/find.ts +52 -8
  190. package/src/tool/result/graph.ts +44 -1
  191. package/src/tool/result/health.ts +53 -1
  192. package/src/tool/result/inspect.ts +113 -1
  193. package/src/tool/result/orientation.ts +66 -14
  194. package/src/tool/result/refactor.ts +36 -4
  195. package/src/tool/result/resolve.ts +44 -7
  196. package/src/tool/result/types.ts +20 -0
  197. package/src/types/execution.ts +18 -5
  198. package/src/types/index.ts +8 -1
  199. package/src/ui/status-command.ts +5 -3
  200. package/src/ui/status-overlay.ts +4 -0
  201. package/src/ui/tui/common.ts +108 -10
  202. package/src/ui/tui/display.ts +48 -0
  203. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/runtime.ts +0 -351
@@ -0,0 +1,148 @@
1
+ import {
2
+ type CodeRequestControl,
3
+ isCodeRequestInterruption,
4
+ } from "@mrclrchtr/supi-code-runtime/api";
5
+ import type { WorkspaceLspRuntime } from "@mrclrchtr/supi-lsp/api";
6
+ import { recoverDiagnosticRuntime } from "../analysis/health/recovery.ts";
7
+ import { mergeDiagnosticEvidence } from "../diagnostics/evidence.ts";
8
+ import { refreshFileLspMaintenance, refreshLspMaintenance } from "../substrate/lsp/maintenance.ts";
9
+ import type { HealthDiagnosticScope, HealthRefreshAttempt } from "./health-types.ts";
10
+
11
+ interface HealthRefreshAttemptOptions {
12
+ readonly runtime: WorkspaceLspRuntime;
13
+ readonly diagnosticsScope: HealthDiagnosticScope;
14
+ readonly attemptedAt: number;
15
+ readonly cwd: string;
16
+ readonly sentinelSnapshot: Map<string, number>;
17
+ readonly control?: CodeRequestControl;
18
+ readonly reportRecoveryProgress?: () => void;
19
+ }
20
+
21
+ /** Run one file- or workspace-scoped health refresh attempt. */
22
+ export async function collectHealthRefreshAttempt(
23
+ options: HealthRefreshAttemptOptions,
24
+ ): Promise<HealthRefreshAttempt> {
25
+ if (options.diagnosticsScope.kind === "file") {
26
+ return collectFileRefreshAttempt(options, options.diagnosticsScope);
27
+ }
28
+ return collectWorkspaceRefreshAttempt(options);
29
+ }
30
+
31
+ async function collectFileRefreshAttempt(
32
+ options: HealthRefreshAttemptOptions,
33
+ scope: Extract<HealthDiagnosticScope, { kind: "file" }>,
34
+ ): Promise<Extract<HealthRefreshAttempt, { kind: "completed" }>> {
35
+ const maintenance = await refreshFileLspMaintenance({
36
+ runtime: options.runtime,
37
+ cwd: options.cwd,
38
+ sentinelSnapshot: options.sentinelSnapshot,
39
+ filePath: scope.path,
40
+ control: options.control,
41
+ });
42
+ updateSentinelSnapshot(options.sentinelSnapshot, maintenance.snapshot);
43
+ const readiness = await options.runtime.waitUntilReadyForFile(
44
+ scope.path,
45
+ undefined,
46
+ options.control,
47
+ );
48
+ return {
49
+ kind: "completed",
50
+ attemptedAt: options.attemptedAt,
51
+ elapsedMs: Date.now() - options.attemptedAt,
52
+ requestedDiagnosticScope: scope,
53
+ operationScope: "file-runtime",
54
+ attemptedActiveClients: readiness.kind === "ready" ? 1 : 0,
55
+ restartedClients: 0,
56
+ staleAssessment: {
57
+ scope: "file",
58
+ suspected: null,
59
+ matchedFileCount: maintenance.matchedStaleFileCount,
60
+ warning: null,
61
+ },
62
+ };
63
+ }
64
+
65
+ async function collectWorkspaceRefreshAttempt(
66
+ options: HealthRefreshAttemptOptions,
67
+ ): Promise<HealthRefreshAttempt> {
68
+ const maintenance = await refreshLspMaintenance(
69
+ options.runtime,
70
+ options.cwd,
71
+ options.sentinelSnapshot,
72
+ options.control,
73
+ );
74
+ updateSentinelSnapshot(options.sentinelSnapshot, maintenance.snapshot);
75
+ if (maintenance.failureReason) {
76
+ return {
77
+ kind: "failed",
78
+ attemptedAt: options.attemptedAt,
79
+ elapsedMs: Date.now() - options.attemptedAt,
80
+ requestedDiagnosticScope: options.diagnosticsScope,
81
+ operationScope: "workspace-runtime",
82
+ diagnosticEvidence: maintenance.diagnosticEvidence,
83
+ reason: maintenance.failureReason,
84
+ };
85
+ }
86
+
87
+ try {
88
+ const recovery = await recoverDiagnosticRuntime({
89
+ service: options.runtime,
90
+ control: options.control,
91
+ progress: options.reportRecoveryProgress,
92
+ });
93
+ const diagnosticEvidence = mergeDiagnosticEvidence(
94
+ maintenance.diagnosticEvidence,
95
+ recovery.diagnosticEvidence,
96
+ options.cwd,
97
+ );
98
+ if (recovery.refreshFailureReason) {
99
+ return {
100
+ kind: "failed",
101
+ attemptedAt: options.attemptedAt,
102
+ elapsedMs: Date.now() - options.attemptedAt,
103
+ requestedDiagnosticScope: options.diagnosticsScope,
104
+ operationScope: "workspace-runtime",
105
+ diagnosticEvidence,
106
+ reason: recovery.refreshFailureReason,
107
+ };
108
+ }
109
+ return {
110
+ kind: "completed",
111
+ attemptedAt: options.attemptedAt,
112
+ elapsedMs: Date.now() - options.attemptedAt,
113
+ requestedDiagnosticScope: options.diagnosticsScope,
114
+ operationScope: "workspace-runtime",
115
+ attemptedActiveClients: recovery.attemptedClients,
116
+ restartedClients: recovery.restartedClients,
117
+ diagnosticEvidence,
118
+ staleAssessment: {
119
+ scope: "workspace",
120
+ suspected: recovery.staleAssessment.suspected,
121
+ matchedFileCount: recovery.staleAssessment.matchedFiles.length,
122
+ warning: recovery.staleAssessment.warning,
123
+ },
124
+ };
125
+ } catch (error) {
126
+ // Cancellation must propagate; a cancelled caller no longer awaits a
127
+ // recorded failed attempt.
128
+ if (isCodeRequestInterruption(error, options.control)) throw error;
129
+ return {
130
+ kind: "failed",
131
+ attemptedAt: options.attemptedAt,
132
+ elapsedMs: Date.now() - options.attemptedAt,
133
+ requestedDiagnosticScope: options.diagnosticsScope,
134
+ operationScope: "workspace-runtime",
135
+ diagnosticEvidence: maintenance.diagnosticEvidence,
136
+ reason: errorMessage(error),
137
+ };
138
+ }
139
+ }
140
+
141
+ function updateSentinelSnapshot(target: Map<string, number>, next: Map<string, number>): void {
142
+ target.clear();
143
+ for (const [key, value] of next) target.set(key, value);
144
+ }
145
+
146
+ function errorMessage(error: unknown): string {
147
+ return error instanceof Error && error.message ? error.message : "Diagnostic refresh failed.";
148
+ }
@@ -1,3 +1,4 @@
1
+ import type { DiagnosticEvidenceSummary } from "@mrclrchtr/supi-lsp/api";
1
2
  import type { CapabilityWarningReport } from "../analysis/capability/capability-warnings.ts";
2
3
 
3
4
  export type HealthSection = "diagnostics" | "servers";
@@ -53,46 +54,67 @@ export type HealthDiagnosticObservation =
53
54
  readonly kind: "completed";
54
55
  readonly scope: HealthDiagnosticScope;
55
56
  readonly entries: readonly HealthDiagnosticEntry[];
57
+ readonly evidence: DiagnosticEvidenceSummary;
56
58
  }
57
59
  | {
58
60
  readonly kind: "partial";
59
61
  readonly scope: HealthDiagnosticScope;
60
62
  readonly entries: readonly HealthDiagnosticEntry[];
63
+ readonly evidence: DiagnosticEvidenceSummary;
61
64
  readonly reason: string;
62
65
  }
63
66
  | {
64
67
  readonly kind: "unavailable";
65
68
  readonly scope: HealthDiagnosticScope;
66
69
  readonly entries: readonly HealthDiagnosticEntry[];
70
+ readonly evidence: DiagnosticEvidenceSummary;
67
71
  readonly reason: string;
68
72
  };
69
73
 
70
- /** Bounded stale-diagnostic metadata from a completed workspace recovery pass. */
74
+ /** Bounded stale-diagnostic metadata from one refresh attempt. */
71
75
  export interface HealthStaleAssessment {
72
- readonly suspected: boolean;
76
+ readonly scope: "file" | "workspace";
77
+ readonly suspected: boolean | null;
73
78
  readonly matchedFileCount: number;
74
79
  readonly warning: string | null;
75
80
  }
76
81
 
77
- /** A diagnostic refresh attempt against the workspace LSP runtime. */
82
+ export type HealthRefreshOperationScope = "file-runtime" | "workspace-runtime";
83
+
84
+ /** Shared facts for one completed refresh or file-maintenance attempt. */
85
+ interface CompletedHealthRefreshAttempt {
86
+ readonly kind: "completed";
87
+ readonly attemptedAt: number;
88
+ /** Wall-clock duration of the attempt, for telemetry. */
89
+ readonly elapsedMs: number;
90
+ /** The diagnostic evidence scope requested by the caller, not the runtime operation scope. */
91
+ readonly requestedDiagnosticScope: HealthDiagnosticScope;
92
+ /** Active clients targeted by the best-effort operation; this is not a confirmed-success count. */
93
+ readonly attemptedActiveClients: number;
94
+ readonly restartedClients: number;
95
+ readonly staleAssessment: HealthStaleAssessment;
96
+ }
97
+
98
+ /** A diagnostic refresh attempt against an explicit LSP runtime scope. */
78
99
  export type HealthRefreshAttempt =
79
- | {
80
- readonly kind: "completed";
81
- readonly attemptedAt: number;
82
- /** The diagnostic evidence scope requested by the caller, not the runtime operation scope. */
83
- readonly requestedDiagnosticScope: HealthDiagnosticScope;
84
- /** Recovery always operates against the workspace runtime. */
100
+ | (CompletedHealthRefreshAttempt & {
85
101
  readonly operationScope: "workspace-runtime";
86
- /** Active clients targeted by the best-effort refresh; this is not a confirmed-success count. */
87
- readonly attemptedActiveClients: number;
88
- readonly restartedClients: number;
89
- readonly staleAssessment: HealthStaleAssessment;
90
- }
102
+ /** Final document-level evidence from the refresh or recovery pass. */
103
+ readonly diagnosticEvidence: DiagnosticEvidenceSummary;
104
+ })
105
+ | (CompletedHealthRefreshAttempt & {
106
+ /** File maintenance does not claim a workspace diagnostic refresh. */
107
+ readonly operationScope: "file-runtime";
108
+ })
91
109
  | {
92
110
  readonly kind: "failed";
93
111
  readonly attemptedAt: number;
112
+ /** Wall-clock duration of the attempt, for telemetry. */
113
+ readonly elapsedMs: number;
94
114
  readonly requestedDiagnosticScope: HealthDiagnosticScope;
95
- readonly operationScope: "workspace-runtime";
115
+ readonly operationScope: HealthRefreshOperationScope;
116
+ /** Evidence collected before the operation failed, when available. */
117
+ readonly diagnosticEvidence?: DiagnosticEvidenceSummary;
96
118
  readonly reason: string;
97
119
  };
98
120
 
@@ -1,6 +1,7 @@
1
1
  /** Session-owned workspace health workflow. */
2
2
 
3
3
  import type { CapabilityState } from "@mrclrchtr/supi-code-runtime/api";
4
+ import { isCodeRequestInterruption } from "@mrclrchtr/supi-code-runtime/api";
4
5
  import type {
5
6
  LspRuntimeController,
6
7
  WorkspaceLspRuntime,
@@ -15,11 +16,11 @@ import {
15
16
  diagnosticScope,
16
17
  isScopedFile,
17
18
  } from "../analysis/health/diagnostics.ts";
18
- import { describeStructuralState, recoverDiagnosticRuntime } from "../analysis/health/recovery.ts";
19
+ import { describeStructuralState } from "../analysis/health/recovery.ts";
19
20
  import { collectServers } from "../analysis/health/signals.ts";
20
21
  import { resolveScope } from "../analysis/search/paths.ts";
21
- import { refreshLspMaintenance } from "../substrate/lsp/maintenance.ts";
22
22
  import type { CapabilityAdapter } from "./capability-adapter.ts";
23
+ import { collectHealthRefreshAttempt } from "./health-refresh.ts";
23
24
  import type {
24
25
  HealthData,
25
26
  HealthDiagnosticScope,
@@ -63,10 +64,11 @@ export async function runHealthWorkflow(
63
64
  phase: "collection",
64
65
  message: "Collecting workspace health evidence",
65
66
  });
66
-
67
67
  const lspState = deps.capability.getLspRuntimeState(deps.cwd);
68
68
  const capabilityStates = deps.capability.getCapabilityStates(deps.cwd);
69
69
  const runtime = lspState.kind === "ready" ? lspState.runtime : null;
70
+ const evidenceRuntime =
71
+ lspState.kind === "ready" || lspState.kind === "inactive" ? lspState.runtime : null;
70
72
  const serverInventoryAvailable = lspState.kind === "ready" || lspState.kind === "disabled";
71
73
 
72
74
  const diagnosticsScope = diagnosticScope(scopeFilter);
@@ -85,18 +87,29 @@ export async function runHealthWorkflow(
85
87
  scopeFilter,
86
88
  lspState,
87
89
  capabilityState: capabilityStates.semantic,
90
+ control,
88
91
  });
89
92
  const semanticReady = semanticState?.kind === "ready";
90
93
  throwIfAborted(control);
91
94
 
92
95
  const diagnostics = await collectDiagnostics({
93
96
  service: semanticReady ? runtime : null,
97
+ evidenceService: evidenceRuntime,
94
98
  included,
95
99
  scope: diagnosticsScope,
96
100
  cwd: deps.cwd,
97
101
  unavailableReason: diagnosticUnavailableReason(semanticState),
98
102
  detailed: level === "detailed",
103
+ requestControl: control,
104
+ refreshEvidence:
105
+ (refresh.kind === "completed" || refresh.kind === "failed") &&
106
+ refresh.operationScope === "workspace-runtime"
107
+ ? refresh.diagnosticEvidence
108
+ : undefined,
99
109
  });
110
+ // A cancellation that landed during diagnostic resolution must not produce
111
+ // a completed health result the caller no longer awaits.
112
+ throwIfAborted(control);
100
113
  const servers = collectServers(runtime, included);
101
114
  const capabilityWarnings = collectCapabilityWarnings(semanticRequested, deps);
102
115
 
@@ -113,9 +126,9 @@ export async function runHealthWorkflow(
113
126
  capabilityWarnings: capabilityWarnings?.hasWarnings ? capabilityWarnings : undefined,
114
127
  };
115
128
 
129
+ throwIfAborted(control);
116
130
  return { kind: "completed", data };
117
131
  }
118
-
119
132
  function healthNeedsSemantic(included: readonly HealthSection[]): boolean {
120
133
  return included.includes("diagnostics") || included.includes("servers");
121
134
  }
@@ -126,6 +139,7 @@ interface SemanticHealthStateOptions {
126
139
  scopeFilter: string | null;
127
140
  lspState: WorkspaceLspRuntimeState;
128
141
  capabilityState: CapabilityState;
142
+ control?: WorkflowControl;
129
143
  }
130
144
 
131
145
  async function establishSemanticHealthState(
@@ -133,7 +147,11 @@ async function establishSemanticHealthState(
133
147
  ): Promise<SemanticHealthState | null> {
134
148
  if (!options.requested) return null;
135
149
  if (options.runtime && isScopedFile(options.scopeFilter)) {
136
- const readiness = await options.runtime.waitUntilReadyForFile(options.scopeFilter);
150
+ const readiness = await options.runtime.waitUntilReadyForFile(
151
+ options.scopeFilter,
152
+ undefined,
153
+ options.control,
154
+ );
137
155
  if (readiness.kind === "ready") return { kind: "ready" };
138
156
  if (readiness.kind === "timeout") {
139
157
  return { kind: "pending", reason: "File semantic readiness timed out" };
@@ -231,54 +249,39 @@ async function collectRefreshState(options: RefreshStateOptions): Promise<Health
231
249
  }
232
250
 
233
251
  const attemptedAt = Date.now();
252
+ const operationScope = diagnosticsScope.kind === "file" ? "file-runtime" : "workspace-runtime";
234
253
  try {
235
254
  reportProgress(options.control, {
236
255
  intent: "health",
237
256
  phase: "maintenance",
238
257
  message: "Refreshing LSP state and sentinel snapshot",
239
258
  });
240
- updateSentinelSnapshot(
241
- deps.sentinelSnapshot,
242
- await refreshLspMaintenance(runtime, deps.cwd, deps.sentinelSnapshot),
243
- );
244
- if (diagnosticsScope.kind === "file") {
245
- try {
246
- await runtime.waitUntilReadyForFile(diagnosticsScope.path);
247
- } catch {
248
- // Recovery still gets a chance to restart a failed routed client.
249
- }
250
- }
251
-
252
- const recovery = await recoverDiagnosticRuntime({
253
- service: runtime,
254
- progress: () =>
259
+ const attempt = await collectHealthRefreshAttempt({
260
+ runtime,
261
+ diagnosticsScope,
262
+ attemptedAt,
263
+ cwd: options.deps.cwd,
264
+ sentinelSnapshot: options.deps.sentinelSnapshot,
265
+ control: options.control,
266
+ reportRecoveryProgress: () =>
255
267
  reportProgress(options.control, {
256
268
  intent: "health",
257
269
  phase: "recovery",
258
270
  message: "Refreshing diagnostics and recovery state",
259
271
  }),
260
272
  });
261
- const attempt: HealthRefreshAttempt = {
262
- kind: "completed",
263
- attemptedAt,
264
- requestedDiagnosticScope: diagnosticsScope,
265
- operationScope: "workspace-runtime",
266
- attemptedActiveClients: recovery.attemptedClients,
267
- restartedClients: recovery.restartedClients,
268
- staleAssessment: {
269
- suspected: recovery.staleAssessment.suspected,
270
- matchedFileCount: recovery.staleAssessment.matchedFiles.length,
271
- warning: recovery.staleAssessment.warning,
272
- },
273
- };
274
273
  deps.trackRefreshAttempt(attempt);
275
274
  return attempt;
276
275
  } catch (error) {
276
+ // Cancellation must propagate; a cancelled caller no longer awaits a
277
+ // recorded failed attempt or the refresh data it would carry.
278
+ if (isCodeRequestInterruption(error, options.control)) throw error;
277
279
  const attempt: HealthRefreshAttempt = {
278
280
  kind: "failed",
279
281
  attemptedAt,
282
+ elapsedMs: Date.now() - attemptedAt,
280
283
  requestedDiagnosticScope: diagnosticsScope,
281
- operationScope: "workspace-runtime",
284
+ operationScope,
282
285
  reason: errorMessage(error),
283
286
  };
284
287
  deps.trackRefreshAttempt(attempt);
@@ -286,11 +289,6 @@ async function collectRefreshState(options: RefreshStateOptions): Promise<Health
286
289
  }
287
290
  }
288
291
 
289
- function updateSentinelSnapshot(target: Map<string, number>, next: Map<string, number>): void {
290
- target.clear();
291
- for (const [key, value] of next) target.set(key, value);
292
- }
293
-
294
292
  function refreshUnavailableReason(lspState: WorkspaceLspRuntimeState): string {
295
293
  switch (lspState.kind) {
296
294
  case "unavailable":
@@ -2,6 +2,8 @@
2
2
 
3
3
  import {
4
4
  type CodePosition,
5
+ type CodeRequestControl,
6
+ isCodeRequestInterruption,
5
7
  mapCodeQueryResult,
6
8
  type OutlineData,
7
9
  type SemanticProvider,
@@ -27,6 +29,7 @@ export interface InspectCollectionInput {
27
29
  readonly line: number;
28
30
  readonly character: number;
29
31
  readonly lineCount: number;
32
+ readonly requestControl?: CodeRequestControl;
30
33
  readonly structural: StructuralProvider | null;
31
34
  readonly semantic: SemanticProvider | null;
32
35
  readonly semanticUnavailableReason: string;
@@ -50,7 +53,12 @@ async function collectNode(
50
53
  ): Promise<InspectObservation<InspectNode | null>> {
51
54
  if (!input.structural) return unavailableCodeQuery("No structural node provider is active.");
52
55
  try {
53
- const result = await input.structural.nodeAt(input.file, input.line, input.character);
56
+ const result = await input.structural.nodeAt(
57
+ input.file,
58
+ input.line,
59
+ input.character,
60
+ input.requestControl,
61
+ );
54
62
  if (result.kind !== "success") return unavailableCodeQuery(result.message);
55
63
  return {
56
64
  kind: "completed",
@@ -65,6 +73,7 @@ async function collectNode(
65
73
  },
66
74
  };
67
75
  } catch (error) {
76
+ if (isCodeRequestInterruption(error, input.requestControl)) throw error;
68
77
  return unavailableCodeQuery(failureReason("Structural node lookup", error));
69
78
  }
70
79
  }
@@ -74,7 +83,7 @@ async function collectEnclosingSymbol(
74
83
  ): Promise<InspectObservation<InspectEnclosingSymbol | null>> {
75
84
  if (!input.structural) return unavailableCodeQuery("No structural outline provider is active.");
76
85
  try {
77
- const result = await input.structural.outline(input.file);
86
+ const result = await input.structural.outline(input.file, input.requestControl);
78
87
  if (result.kind !== "success") return unavailableCodeQuery(result.message);
79
88
  return {
80
89
  kind: "completed",
@@ -84,6 +93,7 @@ async function collectEnclosingSymbol(
84
93
  }),
85
94
  };
86
95
  } catch (error) {
96
+ if (isCodeRequestInterruption(error, input.requestControl)) throw error;
87
97
  return unavailableCodeQuery(failureReason("Structural outline lookup", error));
88
98
  }
89
99
  }
@@ -98,6 +108,7 @@ async function collectHover(
98
108
  (hover) => hover?.contents ?? null,
99
109
  );
100
110
  } catch (error) {
111
+ if (isCodeRequestInterruption(error, input.requestControl)) throw error;
101
112
  return unavailableCodeQuery(failureReason("Hover lookup", error));
102
113
  }
103
114
  }
@@ -131,6 +142,7 @@ async function collectDefinition(
131
142
  ? { kind: "partial", data: definitions, reason: reasons.join(" ") }
132
143
  : { kind: "completed", data: definitions };
133
144
  } catch (error) {
145
+ if (isCodeRequestInterruption(error, input.requestControl)) throw error;
134
146
  return unavailableCodeQuery(failureReason("Definition lookup", error));
135
147
  }
136
148
  }
@@ -142,7 +154,11 @@ async function collectDiagnostics(
142
154
  return unavailableCodeQuery(lspUnavailableReason(input.lspState));
143
155
  }
144
156
  try {
145
- const result = await input.lspState.runtime.fileDiagnostics(input.file, 4);
157
+ const result = await input.lspState.runtime.fileDiagnostics(
158
+ input.file,
159
+ 4,
160
+ input.requestControl,
161
+ );
146
162
  if (result.kind === "unavailable") return result;
147
163
  const diagnostics = result.data
148
164
  .filter((diagnostic) => diagnosticOverlapsWindow(diagnostic.range, input))
@@ -159,6 +175,7 @@ async function collectDiagnostics(
159
175
  ? { kind: "partial", data: diagnostics, reason: result.reason }
160
176
  : { kind: "completed", data: diagnostics };
161
177
  } catch (error) {
178
+ if (isCodeRequestInterruption(error, input.requestControl)) throw error;
162
179
  return unavailableCodeQuery(failureReason("Diagnostic lookup", error));
163
180
  }
164
181
  }
@@ -1,6 +1,7 @@
1
1
  /** Session-owned point inspection workflow. */
2
2
 
3
3
  import type { WorkspaceLspRuntimeState } from "@mrclrchtr/supi-lsp/api";
4
+ import { withSemanticRequestControl } from "../analysis/provider.ts";
4
5
  import type { CapabilityAdapter, ReadinessOutcome } from "./capability-adapter.ts";
5
6
  import { parseInspectWorkflowInput } from "./input/workflows.ts";
6
7
  import { collectInspectSections } from "./inspect/collect.ts";
@@ -37,14 +38,17 @@ export async function runInspectWorkflow(
37
38
  phase: "providers",
38
39
  message: "Collecting point facts",
39
40
  });
40
- const readiness = await deps.capability.ensureSemanticReadiness(deps.cwd, {
41
- kind: "file",
42
- file: point.value.file,
43
- });
41
+ const readiness = await deps.capability.ensureSemanticReadiness(
42
+ deps.cwd,
43
+ { kind: "file", file: point.value.file },
44
+ control,
45
+ );
44
46
  throwIfAborted(control);
45
47
 
46
48
  const semanticReady = readiness.kind === "ready";
47
- const semantic = semanticReady ? deps.capability.getSemanticProvider(deps.cwd) : null;
49
+ const semantic = semanticReady
50
+ ? withSemanticRequestControl(deps.capability.getSemanticProvider(deps.cwd), control)
51
+ : null;
48
52
  const lspState = semanticReady
49
53
  ? deps.capability.getLspRuntimeState(deps.cwd)
50
54
  : unavailableLspState(readiness);
@@ -54,6 +58,7 @@ export async function runInspectWorkflow(
54
58
  line: point.value.line,
55
59
  character: point.value.character,
56
60
  lineCount: point.value.lineCount,
61
+ requestControl: control,
57
62
  structural: deps.capability.getStructuralProvider(deps.cwd),
58
63
  semantic,
59
64
  semanticUnavailableReason: semantic
@@ -2,6 +2,7 @@
2
2
  import { existsSync, readFileSync } from "node:fs";
3
3
  import * as path from "node:path";
4
4
  import type { ConfidenceMode } from "@mrclrchtr/supi-code-runtime/api";
5
+ import { isCodeRequestInterruption } from "@mrclrchtr/supi-code-runtime/api";
5
6
  import { uriToFile } from "@mrclrchtr/supi-core/path";
6
7
  import type { Diagnostic } from "@mrclrchtr/supi-lsp/api";
7
8
  import {
@@ -69,6 +70,7 @@ async function executeOrientationContext(
69
70
  focus: input.focus,
70
71
  maxResults: input.maxResults ?? 10,
71
72
  lspRuntime: deps.lspRuntime,
73
+ requestControl: deps.requestControl,
72
74
  });
73
75
  }
74
76
 
@@ -262,6 +264,7 @@ async function collectDefinitionTargets(
262
264
  evidenceLists: [evidence.metadata],
263
265
  };
264
266
  } catch (error) {
267
+ if (isCodeRequestInterruption(error, deps.requestControl)) throw error;
265
268
  return {
266
269
  items: [],
267
270
  hasSemanticEvidence: false,
@@ -295,7 +298,11 @@ async function buildDiagnosticsSection(
295
298
 
296
299
  try {
297
300
  const targetFile = path.resolve(deps.cwd, target.file);
298
- const result = await deps.lspRuntime.runtime.fileDiagnostics(targetFile, 4);
301
+ const result = await deps.lspRuntime.runtime.fileDiagnostics(
302
+ targetFile,
303
+ 4,
304
+ deps.requestControl,
305
+ );
299
306
  if (result.kind === "unavailable") {
300
307
  return unavailableTargetSection(
301
308
  [{ kind: "paragraph", text: `Diagnostics unavailable for this target — ${result.reason}` }],
@@ -331,6 +338,7 @@ async function buildDiagnosticsSection(
331
338
  evidenceLists: [evidence.metadata],
332
339
  };
333
340
  } catch (error) {
341
+ if (isCodeRequestInterruption(error, deps.requestControl)) throw error;
334
342
  return unavailableTargetSection(
335
343
  [{ kind: "paragraph", text: "Diagnostics failed to load." }],
336
344
  false,
@@ -492,6 +500,7 @@ async function maybeGatherTreeContext(
492
500
  target.displayLine,
493
501
  target.displayCharacter,
494
502
  target.anchorKind !== "declaration",
503
+ deps.requestControl,
495
504
  );
496
505
  }
497
506
 
@@ -1,5 +1,6 @@
1
1
  import { statSync } from "node:fs";
2
2
  import * as path from "node:path";
3
+ import type { CodeRequestControl } from "@mrclrchtr/supi-code-runtime/api";
3
4
  import type { WorkspaceLspRuntimeState } from "@mrclrchtr/supi-lsp/api";
4
5
  import type {
5
6
  ArchitectureModel,
@@ -32,6 +33,7 @@ interface ContextFactsInput {
32
33
  readonly maxResults: number;
33
34
  readonly provider: CodeProvider | null;
34
35
  readonly lspRuntime: WorkspaceLspRuntimeState;
36
+ readonly requestControl?: CodeRequestControl;
35
37
  }
36
38
 
37
39
  /** Collect direct filesystem, parsed-manifest, and explicit-provider Orientation facts. */
@@ -115,7 +117,7 @@ async function collectFileFacts(
115
117
  });
116
118
  appendTopologyWarning(builder, input.model);
117
119
  appendPackageContext(builder, input.model, focus);
118
- await appendStructuralFileFacts(builder, input.provider, focus);
120
+ await appendStructuralFileFacts(builder, input.provider, focus, input.requestControl);
119
121
  appendPrioritySignals(builder, {
120
122
  scope: focus,
121
123
  isFile: true,