@mrclrchtr/supi-code-intelligence 4.9.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 (215) 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/debug-timing.ts +34 -21
  14. package/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +3 -0
  15. package/node_modules/@mrclrchtr/supi-lsp/README.md +80 -5
  16. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/README.md +2 -0
  17. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
  18. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +9 -0
  19. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +53 -13
  20. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/request-control.ts +47 -0
  21. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +13 -1
  22. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/README.md +2 -0
  23. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/package.json +1 -1
  24. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/config/config.ts +31 -0
  25. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/config.ts +2 -0
  26. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +19 -3
  27. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/debug-timing.ts +34 -21
  28. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +3 -0
  29. package/node_modules/@mrclrchtr/supi-lsp/package.json +7 -6
  30. package/node_modules/@mrclrchtr/supi-lsp/src/api.ts +10 -0
  31. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-cache.ts +206 -0
  32. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-capabilities.ts +78 -0
  33. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-collection.ts +114 -0
  34. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-evidence.ts +372 -0
  35. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-host.ts +14 -0
  36. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-pull.ts +62 -0
  37. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-refresh.ts +491 -0
  38. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-request.ts +9 -0
  39. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-timing.ts +215 -0
  40. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-waiters.ts +206 -0
  41. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostics.ts +370 -266
  42. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-document-state.ts +52 -0
  43. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-document-sync.ts +185 -0
  44. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-file-state.ts +25 -0
  45. package/node_modules/@mrclrchtr/supi-lsp/src/client/client.ts +467 -115
  46. package/node_modules/@mrclrchtr/supi-lsp/src/client/transport.ts +238 -11
  47. package/node_modules/@mrclrchtr/supi-lsp/src/config/capabilities.ts +10 -1
  48. package/node_modules/@mrclrchtr/supi-lsp/src/config/defaults.json +1 -1
  49. package/node_modules/@mrclrchtr/supi-lsp/src/debug-telemetry.ts +45 -0
  50. package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/evidence.ts +38 -0
  51. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-client-state.ts +79 -9
  52. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-diagnostics.ts +13 -4
  53. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-recovery.ts +300 -24
  54. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-symbol.ts +5 -2
  55. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager.ts +464 -96
  56. package/node_modules/@mrclrchtr/supi-lsp/src/provider/lsp-refactor-provider.ts +130 -0
  57. package/node_modules/@mrclrchtr/supi-lsp/src/provider/lsp-semantic-provider.ts +45 -329
  58. package/node_modules/@mrclrchtr/supi-lsp/src/provider/refactor-planning.ts +57 -120
  59. package/node_modules/@mrclrchtr/supi-lsp/src/provider/semantic-edit-normalizer.ts +320 -0
  60. package/node_modules/@mrclrchtr/supi-lsp/src/provider/semantic-symbol-mapper.ts +207 -0
  61. package/node_modules/@mrclrchtr/supi-lsp/src/session/readiness.ts +72 -2
  62. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-controller.ts +151 -26
  63. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-diagnostic-surface.ts +40 -0
  64. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-diagnostics.ts +50 -0
  65. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-registry.ts +136 -120
  66. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-transition-debug.ts +49 -0
  67. package/node_modules/@mrclrchtr/supi-lsp/src/session/workspace-lsp-runtime.ts +102 -0
  68. package/node_modules/@mrclrchtr/supi-tree-sitter/README.md +26 -6
  69. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/README.md +2 -0
  70. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
  71. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +9 -0
  72. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +53 -13
  73. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/request-control.ts +47 -0
  74. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +13 -1
  75. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/README.md +2 -0
  76. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/package.json +1 -1
  77. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/config/config.ts +31 -0
  78. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/config.ts +2 -0
  79. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +19 -3
  80. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/debug-timing.ts +34 -21
  81. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +3 -0
  82. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/LICENSE +21 -0
  83. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/README.md +258 -0
  84. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/dist/babel.cjs +257 -0
  85. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/dist/jiti.cjs +1 -0
  86. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-cli.mjs +34 -0
  87. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-hooks.mjs +124 -0
  88. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-native.mjs +121 -0
  89. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-register.d.mts +1 -0
  90. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-register.mjs +4 -0
  91. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-static.mjs +23 -0
  92. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.cjs +30 -0
  93. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.d.cts +8 -0
  94. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.d.mts +8 -0
  95. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.mjs +29 -0
  96. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/types.d.ts +420 -0
  97. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/package.json +146 -0
  98. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.wasm +0 -0
  99. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.wasm.map +4 -4
  100. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/package.json +1 -1
  101. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.wasm +0 -0
  102. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.wasm.map +4 -4
  103. package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +7 -3
  104. package/node_modules/@mrclrchtr/supi-tree-sitter/resources/grammars/kotlin/tree-sitter-kotlin.wasm.json +1 -1
  105. package/node_modules/@mrclrchtr/supi-tree-sitter/resources/grammars/sql/tree-sitter-sql.wasm.json +1 -1
  106. package/node_modules/@mrclrchtr/supi-tree-sitter/src/api.ts +0 -9
  107. package/node_modules/@mrclrchtr/supi-tree-sitter/src/index.ts +0 -8
  108. package/node_modules/@mrclrchtr/supi-tree-sitter/src/provider/tree-sitter-provider.ts +16 -12
  109. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/runtime-controller.ts +65 -87
  110. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/session.ts +47 -95
  111. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-timing.ts +147 -0
  112. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-client-lifecycle.ts +39 -0
  113. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-client.ts +561 -0
  114. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-message-size.ts +24 -0
  115. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-protocol.ts +452 -0
  116. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/call-sites.ts +4 -2
  117. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/callees.ts +12 -4
  118. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/exports.ts +4 -2
  119. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/imports.ts +4 -2
  120. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/node-at.ts +5 -3
  121. package/node_modules/@mrclrchtr/supi-tree-sitter/src/types.ts +33 -12
  122. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/blocking-test-bootstrap.mjs +34 -0
  123. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/bootstrap.mjs +8 -0
  124. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/parsed-file-store-helpers.ts +23 -0
  125. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/parsed-file-store.ts +400 -0
  126. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/request-control.ts +48 -0
  127. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/runtime-parser-helpers.ts +24 -0
  128. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/runtime-query-helpers.ts +43 -0
  129. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/runtime.ts +421 -0
  130. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/service.ts +116 -0
  131. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/worker-main.ts +201 -0
  132. package/package.json +5 -5
  133. package/src/analysis/health/diagnostics.ts +236 -24
  134. package/src/analysis/health/recovery.ts +6 -2
  135. package/src/analysis/provider.ts +58 -0
  136. package/src/analysis/readiness.ts +30 -9
  137. package/src/analysis/refactor/apply.ts +59 -20
  138. package/src/analysis/refactor/mutation-authority.ts +143 -0
  139. package/src/analysis/refactor/position.ts +47 -0
  140. package/src/analysis/refactor/safety.ts +18 -10
  141. package/src/analysis/relations/callees.ts +9 -1
  142. package/src/analysis/relations/types.ts +5 -2
  143. package/src/analysis/search/ast-scan-timing.ts +9 -4
  144. package/src/analysis/search/ast-scan.ts +1 -1
  145. package/src/analysis/search/deadline.ts +2 -2
  146. package/src/analysis/search/pattern-analysis.ts +46 -32
  147. package/src/analysis/search/pattern.ts +12 -2
  148. package/src/analysis/target/anchored.ts +20 -11
  149. package/src/analysis/target/file.ts +18 -11
  150. package/src/analysis/target/identity.ts +19 -3
  151. package/src/analysis/target/symbol.ts +36 -15
  152. package/src/api.ts +4 -0
  153. package/src/diagnostics/evidence.ts +51 -0
  154. package/src/session/capability-adapter.ts +12 -3
  155. package/src/session/find-workflow.ts +17 -7
  156. package/src/session/graph/collect.ts +18 -2
  157. package/src/session/graph-workflow.ts +19 -12
  158. package/src/session/health-refresh.ts +148 -0
  159. package/src/session/health-types.ts +37 -15
  160. package/src/session/health-workflow.ts +37 -39
  161. package/src/session/inspect/collect.ts +20 -3
  162. package/src/session/inspect-workflow.ts +10 -5
  163. package/src/session/orientation/collect.ts +10 -1
  164. package/src/session/orientation/context-facts.ts +3 -1
  165. package/src/session/orientation/context-sections.ts +20 -7
  166. package/src/session/orientation/gather.ts +17 -11
  167. package/src/session/orientation-types.ts +2 -1
  168. package/src/session/orientation-workflow.ts +15 -8
  169. package/src/session/refactor-plans.ts +2 -0
  170. package/src/session/refactor-workflow.ts +59 -14
  171. package/src/session/session.ts +4 -1
  172. package/src/session/target-workflow.ts +54 -23
  173. package/src/session/workflow-control.ts +7 -3
  174. package/src/substrate/lsp/lifecycle.ts +26 -46
  175. package/src/substrate/lsp/maintenance.ts +199 -25
  176. package/src/substrate/lsp/state.ts +2 -2
  177. package/src/substrate/workspace-provider-host.ts +25 -3
  178. package/src/tool/find/execute.ts +7 -1
  179. package/src/tool/find/render.ts +20 -3
  180. package/src/tool/find/tui.ts +23 -21
  181. package/src/tool/graph/execute.ts +23 -3
  182. package/src/tool/graph/tui.ts +59 -46
  183. package/src/tool/health/execute.ts +7 -2
  184. package/src/tool/health/markdown.ts +56 -14
  185. package/src/tool/health/refresh-status.ts +105 -0
  186. package/src/tool/health/tui.ts +95 -98
  187. package/src/tool/infra/workflow-control.ts +8 -0
  188. package/src/tool/inspect/execute.ts +7 -1
  189. package/src/tool/inspect/tui.ts +26 -18
  190. package/src/tool/orientation/execute.ts +21 -3
  191. package/src/tool/orientation/tui.ts +51 -35
  192. package/src/tool/refactor-apply/execute.ts +3 -0
  193. package/src/tool/refactor-apply/tui.ts +43 -25
  194. package/src/tool/refactor-plan/execute.ts +4 -0
  195. package/src/tool/refactor-plan/tui.ts +33 -20
  196. package/src/tool/register.ts +127 -22
  197. package/src/tool/resolve/execute.ts +18 -1
  198. package/src/tool/resolve/tui.ts +42 -24
  199. package/src/tool/result/display.ts +107 -0
  200. package/src/tool/result/errors.ts +20 -17
  201. package/src/tool/result/find.ts +52 -8
  202. package/src/tool/result/graph.ts +44 -1
  203. package/src/tool/result/health.ts +53 -1
  204. package/src/tool/result/inspect.ts +113 -1
  205. package/src/tool/result/orientation.ts +66 -14
  206. package/src/tool/result/refactor.ts +36 -4
  207. package/src/tool/result/resolve.ts +44 -7
  208. package/src/tool/result/types.ts +20 -0
  209. package/src/types/execution.ts +18 -5
  210. package/src/types/index.ts +8 -1
  211. package/src/ui/status-command.ts +5 -3
  212. package/src/ui/status-overlay.ts +4 -0
  213. package/src/ui/tui/common.ts +108 -10
  214. package/src/ui/tui/display.ts +48 -0
  215. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/runtime.ts +0 -247
@@ -30,7 +30,8 @@ export async function runFindWorkflow(
30
30
  const scope = resolveScopeSet(request.scope ? [...request.scope] : undefined, deps.cwd);
31
31
  if (scope.kind === "error") return { kind: "invalid-input", message: scope.reason };
32
32
 
33
- throwIfAborted(control);
33
+ if (mode === "ast") control?.signal?.throwIfAborted();
34
+ else throwIfAborted(control);
34
35
  reportProgress(control, {
35
36
  intent: "find",
36
37
  phase: mode,
@@ -69,9 +70,11 @@ async function runSemanticSearch(options: {
69
70
  control?: WorkflowControl;
70
71
  }): Promise<FindWorkflowOutcome> {
71
72
  const { query, scopePaths, scopeLabel, maxResults, deps, control } = options;
72
- const readiness = await deps.capability.ensureSemanticReadiness(deps.cwd, {
73
- kind: "workspace",
74
- });
73
+ const readiness = await deps.capability.ensureSemanticReadiness(
74
+ deps.cwd,
75
+ { kind: "workspace" },
76
+ control,
77
+ );
75
78
  if (readiness.kind === "timeout") {
76
79
  return { kind: "unavailable", reason: "Semantic readiness timed out." };
77
80
  }
@@ -82,7 +85,10 @@ async function runSemanticSearch(options: {
82
85
  if (!provider?.workspaceSymbols) {
83
86
  return { kind: "unavailable", reason: "No semantic workspace-symbol provider is active." };
84
87
  }
85
- const result = await provider.workspaceSymbols(query);
88
+ const result = await provider.workspaceSymbols(query, control);
89
+ // A cancellation that landed during the request must not publish symbols
90
+ // the caller no longer awaits.
91
+ throwIfAborted(control);
86
92
  if (result.kind === "unavailable") {
87
93
  return { kind: "unavailable", reason: result.reason };
88
94
  }
@@ -120,13 +126,17 @@ async function runAstSearch(options: {
120
126
  if (!provider) {
121
127
  return { kind: "unavailable", reason: "No structural provider is active." };
122
128
  }
123
- throwIfAborted(control);
129
+ control?.signal?.throwIfAborted();
124
130
  const outcome = await getStructuredPatternMatches({
125
131
  params: { pattern: query, kind: input.kind },
126
132
  roots: scopePaths,
127
133
  cwd: deps.cwd,
128
134
  structural: provider,
129
- control: { signal: control?.signal },
135
+ control: {
136
+ operationId: control?.operationId,
137
+ signal: control?.signal,
138
+ deadline: control?.deadline,
139
+ },
130
140
  });
131
141
  if (outcome.kind === "invalid-input") return outcome;
132
142
  if (outcome.kind === "unavailable") return outcome;
@@ -1,5 +1,10 @@
1
1
  /** Presentation-neutral relation collection used by the session-owned graph workflow. */
2
2
 
3
+ import {
4
+ type CodeRequestControl,
5
+ isCodeRequestInterruption,
6
+ unavailableCodeQuery,
7
+ } from "@mrclrchtr/supi-code-runtime/api";
3
8
  import type { CodeProvider } from "../../analysis/provider.ts";
4
9
  import {
5
10
  readNextEnclosingScope,
@@ -25,6 +30,7 @@ export interface CollectRelationOptions {
25
30
  semanticReadinessError: string | null;
26
31
  anchorKind: AnchorKind;
27
32
  calleeDepth?: "direct" | "deep";
33
+ requestControl?: CodeRequestControl;
28
34
  }
29
35
 
30
36
  /** Collect one evidence-backed graph relation without rendering it. */
@@ -46,6 +52,7 @@ export async function collectRelation(
46
52
  return collectImplementationsRelation(options);
47
53
  }
48
54
  } catch (error) {
55
+ if (isCodeRequestInterruption(error, options.requestControl)) throw error;
49
56
  return {
50
57
  kind: "unavailable",
51
58
  rel: relation,
@@ -61,7 +68,11 @@ async function collectReferences(options: CollectRelationOptions): Promise<Graph
61
68
 
62
69
  const result = await collectCallers(options.file, options.position, options.displayName, {
63
70
  cwd: options.cwd,
64
- provider: { references: options.provider.references },
71
+ provider: {
72
+ references: async (file, position) =>
73
+ options.provider?.references(file, position, options.requestControl) ??
74
+ unavailableCodeQuery("References unavailable"),
75
+ },
65
76
  });
66
77
  if (result.confidence === "unavailable") {
67
78
  return { kind: "unavailable", rel: "references", message: "References unavailable" };
@@ -118,6 +129,7 @@ async function collectCalleesRelation(options: CollectRelationOptions): Promise<
118
129
  { cwd: options.cwd, provider: { calleesAt: options.provider.calleesAt } },
119
130
  undefined,
120
131
  options.calleeDepth ?? "direct",
132
+ options.requestControl,
121
133
  );
122
134
  if (result.confidence === "unavailable") {
123
135
  return { kind: "unavailable", rel: "callees", message: "Callees unavailable" };
@@ -161,7 +173,11 @@ async function collectImplementationsRelation(
161
173
 
162
174
  const result = await collectImplementations(options.file, options.position, options.displayName, {
163
175
  cwd: options.cwd,
164
- provider: { implementation: options.provider.implementation },
176
+ provider: {
177
+ implementation: async (file, position) =>
178
+ options.provider?.implementation(file, position, options.requestControl) ??
179
+ unavailableCodeQuery("Implementations unavailable"),
180
+ },
165
181
  });
166
182
  if (result.confidence === "unavailable") {
167
183
  return { kind: "unavailable", rel: "implements", message: "Implementations unavailable" };
@@ -54,7 +54,9 @@ export async function runGraphWorkflow(
54
54
  maxResults: request.maxResults,
55
55
  },
56
56
  deps,
57
+ control,
57
58
  );
59
+ throwIfAborted(control);
58
60
  if (targetOutcome.kind === "target-group") {
59
61
  return {
60
62
  kind: "invalid-input",
@@ -64,12 +66,13 @@ export async function runGraphWorkflow(
64
66
  if (targetOutcome.kind !== "resolved") return targetOutcome;
65
67
 
66
68
  const entry = targetOutcome.entry;
67
- const semanticReadinessError = await getSemanticReadinessError(
69
+ const semanticReadinessError = await getSemanticReadinessError({
68
70
  relations,
69
- entry.file,
70
- deps.capability,
71
- deps.cwd,
72
- );
71
+ file: entry.file,
72
+ capability: deps.capability,
73
+ cwd: deps.cwd,
74
+ control,
75
+ });
73
76
  const provider = deps.capability.getProvider(deps.cwd);
74
77
  const maxResults = request.maxResults ?? 8;
75
78
  const displayName =
@@ -94,9 +97,11 @@ export async function runGraphWorkflow(
94
97
  semanticReadinessError,
95
98
  anchorKind: entry.anchorKind,
96
99
  calleeDepth: request.calleeDepth,
100
+ requestControl: control,
97
101
  }),
98
102
  );
99
103
  }
104
+ throwIfAborted(control);
100
105
 
101
106
  if (sections.length > 0 && sections.every((section) => section.kind === "unavailable")) {
102
107
  return {
@@ -127,16 +132,18 @@ function normalizeRelations(
127
132
  return requested as readonly GraphRelationKind[];
128
133
  }
129
134
 
130
- async function getSemanticReadinessError(
131
- relations: readonly GraphRelationKind[],
132
- file: string,
133
- capability: CapabilityAdapter,
134
- cwd: string,
135
- ): Promise<string | null> {
135
+ async function getSemanticReadinessError(options: {
136
+ relations: readonly GraphRelationKind[];
137
+ file: string;
138
+ capability: CapabilityAdapter;
139
+ cwd: string;
140
+ control?: WorkflowControl;
141
+ }): Promise<string | null> {
142
+ const { relations, file, capability, cwd, control } = options;
136
143
  if (!relations.some((relation) => relation === "references" || relation === "implements")) {
137
144
  return null;
138
145
  }
139
- const readiness = await capability.ensureSemanticReadiness(cwd, { kind: "file", file });
146
+ const readiness = await capability.ensureSemanticReadiness(cwd, { kind: "file", file }, control);
140
147
  if (readiness.kind === "ready") return null;
141
148
  if (readiness.kind === "timeout") {
142
149
  return "Semantic readiness timed out. Retry shortly or inspect code_health.";
@@ -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
  }