@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
@@ -1,6 +1,11 @@
1
1
  import { readdirSync } from "node:fs";
2
2
  import * as path from "node:path";
3
- import type { CodeResult, ConfidenceMode } from "@mrclrchtr/supi-code-runtime/api";
3
+ import {
4
+ type CodeRequestControl,
5
+ type CodeResult,
6
+ type ConfidenceMode,
7
+ isCodeRequestInterruption,
8
+ } from "@mrclrchtr/supi-code-runtime/api";
4
9
  import { isWithinOrEqual } from "@mrclrchtr/supi-core/project";
5
10
  import type { WorkspaceLspRuntimeState } from "@mrclrchtr/supi-lsp/api";
6
11
  import type { EvidenceListMetadata, EvidencePartialReason } from "../../analysis/evidence.ts";
@@ -153,6 +158,7 @@ export async function appendStructuralFileFacts(
153
158
  builder: ContextOrientationBuilder,
154
159
  provider: CodeProvider | null,
155
160
  file: string,
161
+ requestControl?: CodeRequestControl,
156
162
  ): Promise<void> {
157
163
  if (!provider) {
158
164
  appendUnavailableStructuralSections(builder);
@@ -162,19 +168,22 @@ export async function appendStructuralFileFacts(
162
168
  await appendStructuralList(builder, {
163
169
  key: "structural.outline",
164
170
  title: "Provider outline",
165
- collect: () => provider.outline(file),
171
+ collect: () => provider.outline(file, requestControl),
172
+ requestControl,
166
173
  render: (item) => `\`${item.name}\` (${item.kind}, L${item.startLine}–L${item.endLine})`,
167
174
  });
168
175
  await appendStructuralList(builder, {
169
176
  key: "structural.imports",
170
177
  title: "Provider imports",
171
- collect: () => provider.imports(file),
178
+ collect: () => provider.imports(file, requestControl),
179
+ requestControl,
172
180
  render: (item) => `\`${item.moduleSpecifier}\``,
173
181
  });
174
182
  await appendStructuralList(builder, {
175
183
  key: "structural.exports",
176
184
  title: "Provider exports",
177
- collect: () => provider.exports(file),
185
+ collect: () => provider.exports(file, requestControl),
186
+ requestControl,
178
187
  render: (item) => `\`${item.name}\` (${item.kind})`,
179
188
  });
180
189
  }
@@ -201,12 +210,14 @@ async function appendStructuralList<T>(
201
210
  title: string;
202
211
  collect: () => Promise<CodeResult<T[]>>;
203
212
  render: (item: T) => string;
213
+ requestControl?: CodeRequestControl;
204
214
  },
205
215
  ): Promise<void> {
206
216
  let result: CodeResult<T[]>;
207
217
  try {
208
218
  result = await input.collect();
209
219
  } catch (error) {
220
+ if (isCodeRequestInterruption(error, input.requestControl)) throw error;
210
221
  appendUnavailable(builder, {
211
222
  key: input.key,
212
223
  title: input.title,
@@ -246,7 +257,8 @@ export function appendPrioritySignals(
246
257
  ): void {
247
258
  if (input.lspRuntime.kind !== "ready") return;
248
259
  const scopePath = path.resolve(input.scope);
249
- const entries = input.lspRuntime.runtime.getOutstandingDiagnosticSummary(2).filter((entry) => {
260
+ const snapshot = input.lspRuntime.runtime.getOutstandingDiagnosticSummary(2);
261
+ const entries = snapshot.entries.filter((entry) => {
250
262
  const file = path.resolve(input.cwd, entry.file);
251
263
  return input.isFile ? file === scopePath : isWithinOrEqual(scopePath, file);
252
264
  });
@@ -265,8 +277,9 @@ export function appendPrioritySignals(
265
277
  confidence: "semantic",
266
278
  provenance: [{ source: "semantic", capability: "LSP diagnostic snapshot" }],
267
279
  status: "partial",
268
- reason:
269
- "This is the current LSP snapshot, not a complete diagnostic scan; use code_health for diagnostic status.",
280
+ reason: snapshot.current
281
+ ? "This is the current LSP snapshot, not a complete diagnostic scan; use code_health for diagnostic status."
282
+ : "This LSP snapshot was invalidated by a document or workspace change; use code_health with refresh:true before relying on it.",
270
283
  });
271
284
  }
272
285
 
@@ -6,10 +6,12 @@
6
6
  * evidence collector in `collect.ts`.
7
7
  */
8
8
 
9
- import type {
10
- SemanticProvider,
11
- SourceRange,
12
- StructuralProvider,
9
+ import {
10
+ type CodeRequestControl,
11
+ isCodeRequestInterruption,
12
+ type SemanticProvider,
13
+ type SourceRange,
14
+ type StructuralProvider,
13
15
  } from "@mrclrchtr/supi-code-runtime/api";
14
16
 
15
17
  /** Structural provider subset plus optional semantic hover/definition used for gathering. */
@@ -64,6 +66,7 @@ export async function gatherSubstrateContext(
64
66
  line: number,
65
67
  character: number,
66
68
  positionStrict: boolean,
69
+ requestControl?: CodeRequestControl,
67
70
  ): Promise<SubstrateContext> {
68
71
  let nodeInfo: SubstrateContext["nodeInfo"] = null;
69
72
  let outline: SubstrateContext["outline"] = [];
@@ -76,7 +79,7 @@ export async function gatherSubstrateContext(
76
79
 
77
80
  try {
78
81
  if (positionStrict) {
79
- const nodeResult = await provider.nodeAt(relPath, line, character);
82
+ const nodeResult = await provider.nodeAt(relPath, line, character, requestControl);
80
83
  if (nodeResult.kind === "success") {
81
84
  nodeInfo = {
82
85
  type: nodeResult.data.type,
@@ -88,7 +91,7 @@ export async function gatherSubstrateContext(
88
91
  }
89
92
  }
90
93
 
91
- const outlineResult = await provider.outline(relPath);
94
+ const outlineResult = await provider.outline(relPath, requestControl);
92
95
  if (outlineResult.kind === "success") {
93
96
  outline = outlineResult.data.map((item) => ({
94
97
  name: item.name,
@@ -98,12 +101,12 @@ export async function gatherSubstrateContext(
98
101
  }));
99
102
  }
100
103
 
101
- const importsResult = await provider.imports(relPath);
104
+ const importsResult = await provider.imports(relPath, requestControl);
102
105
  if (importsResult.kind === "success") {
103
106
  imports = importsResult.data;
104
107
  }
105
108
 
106
- const exportsResult = await provider.exports(relPath);
109
+ const exportsResult = await provider.exports(relPath, requestControl);
107
110
  if (exportsResult.kind === "success") {
108
111
  exports = exportsResult.data.map((item) => ({
109
112
  name: item.name,
@@ -119,7 +122,8 @@ export async function gatherSubstrateContext(
119
122
  character: character - 1,
120
123
  });
121
124
  if (hoverResult.kind !== "unavailable" && hoverResult.data) hover = hoverResult.data;
122
- } catch {
125
+ } catch (error) {
126
+ if (isCodeRequestInterruption(error, requestControl)) throw error;
123
127
  // hover failed — continue without it
124
128
  }
125
129
  }
@@ -137,11 +141,13 @@ export async function gatherSubstrateContext(
137
141
  range: loc.range,
138
142
  }));
139
143
  }
140
- } catch {
144
+ } catch (error) {
145
+ if (isCodeRequestInterruption(error, requestControl)) throw error;
141
146
  // definition failed — continue without it
142
147
  }
143
148
  }
144
- } catch {
149
+ } catch (error) {
150
+ if (isCodeRequestInterruption(error, requestControl)) throw error;
145
151
  // Provider not available
146
152
  }
147
153
 
@@ -1,4 +1,4 @@
1
- import type { ConfidenceMode } from "@mrclrchtr/supi-code-runtime/api";
1
+ import type { CodeRequestControl, ConfidenceMode } from "@mrclrchtr/supi-code-runtime/api";
2
2
  import type { WorkspaceLspRuntimeState } from "@mrclrchtr/supi-lsp/api";
3
3
  import type { ArchitectureModel } from "../analysis/architecture/model.ts";
4
4
  import type { EvidenceListMetadata } from "../analysis/evidence.ts";
@@ -37,6 +37,7 @@ export interface OrientationDeps {
37
37
  readonly provider: CodeProvider | null;
38
38
  readonly cwd: string;
39
39
  readonly lspRuntime: WorkspaceLspRuntimeState;
40
+ readonly requestControl?: CodeRequestControl;
40
41
  }
41
42
 
42
43
  /**
@@ -8,7 +8,7 @@ import {
8
8
  collectInstructionFiles,
9
9
  findInstructionFilesForDirectory,
10
10
  } from "../analysis/instruction-files.ts";
11
- import { createStructuralCodeProvider } from "../analysis/provider.ts";
11
+ import { createStructuralCodeProvider, withSemanticRequestControl } from "../analysis/provider.ts";
12
12
  import { normalizePath } from "../analysis/search/paths.ts";
13
13
  import { loadCodeIntelligenceConfig } from "../config.ts";
14
14
  import type { CapabilityAdapter } from "./capability-adapter.ts";
@@ -58,8 +58,9 @@ export async function runOrientationWorkflow(
58
58
  if (!request.focus) {
59
59
  const result = await executeOrientation(
60
60
  { maxResults },
61
- { model, provider, lspRuntime, cwd: deps.cwd },
61
+ { model, provider, lspRuntime, cwd: deps.cwd, requestControl: control },
62
62
  );
63
+ throwIfAborted(control);
63
64
  return { kind: "completed", data: result };
64
65
  }
65
66
 
@@ -74,8 +75,9 @@ export async function runOrientationWorkflow(
74
75
  focus: focus.path,
75
76
  maxResults,
76
77
  },
77
- { model, provider, lspRuntime, cwd: deps.cwd },
78
+ { model, provider, lspRuntime, cwd: deps.cwd, requestControl: control },
78
79
  );
80
+ throwIfAborted(control);
79
81
  const withInstructions = addInstructionFiles(result, focus.path, deps);
80
82
  return { kind: "completed", data: withInstructions };
81
83
  }
@@ -101,7 +103,9 @@ async function orientTarget(options: {
101
103
  maxResults,
102
104
  },
103
105
  deps,
106
+ control,
104
107
  );
108
+ throwIfAborted(control);
105
109
  if (target.kind === "target-group") {
106
110
  return {
107
111
  kind: "invalid-input",
@@ -133,13 +137,14 @@ async function orientTarget(options: {
133
137
  throwIfAborted(control);
134
138
 
135
139
  const entry = target.entry;
136
- const readiness = await deps.capability.ensureSemanticReadiness(deps.cwd, {
137
- kind: "file",
138
- file: entry.file,
139
- });
140
+ const readiness = await deps.capability.ensureSemanticReadiness(
141
+ deps.cwd,
142
+ { kind: "file", file: entry.file },
143
+ control,
144
+ );
140
145
  const semanticReady = readiness.kind === "ready";
141
146
  const provider = semanticReady
142
- ? deps.capability.getProvider(deps.cwd)
147
+ ? withSemanticRequestControl(deps.capability.getProvider(deps.cwd), control)
143
148
  : createStructuralCodeProvider(deps.capability.getStructuralProvider(deps.cwd));
144
149
  const lspRuntime = semanticReady
145
150
  ? deps.capability.getLspRuntimeState(deps.cwd)
@@ -154,8 +159,10 @@ async function orientTarget(options: {
154
159
  provider,
155
160
  lspRuntime,
156
161
  cwd: deps.cwd,
162
+ requestControl: control,
157
163
  },
158
164
  );
165
+ throwIfAborted(control);
159
166
  return {
160
167
  kind: "completed",
161
168
  data: addTargetSummary(result, entry, target.notes, deps.cwd),
@@ -19,6 +19,8 @@ export interface RefactorPlan {
19
19
  targetLine: number;
20
20
  targetCharacter: number;
21
21
  edits: WorkspaceEdit;
22
+ /** Canonical roots that the routed semantic provider authorized. */
23
+ authorizedMutationRoots: string[];
22
24
  fileFingerprints: Array<{ file: string; fingerprint: string }>;
23
25
  createdAt: number;
24
26
  }
@@ -8,6 +8,10 @@ import type {
8
8
  } from "@mrclrchtr/supi-code-runtime/api";
9
9
  import { toLspPosition } from "@mrclrchtr/supi-lsp/api";
10
10
  import { applyWorkspaceEdit } from "../analysis/refactor/apply.ts";
11
+ import {
12
+ establishMutationAuthority,
13
+ revalidateMutationAuthority,
14
+ } from "../analysis/refactor/mutation-authority.ts";
11
15
  import { validateEdit } from "../analysis/refactor/safety.ts";
12
16
  import { normalizePath } from "../analysis/search/paths.ts";
13
17
  import type { CapabilityAdapter } from "./capability-adapter.ts";
@@ -66,7 +70,9 @@ export async function runRefactorPlanWorkflow(
66
70
  nameAnchorRequired: parsed.operation === "rename_symbol",
67
71
  },
68
72
  deps,
73
+ control,
69
74
  );
75
+ throwIfAborted(control);
70
76
  if (target.kind === "target-group") {
71
77
  return {
72
78
  kind: "invalid-input",
@@ -81,10 +87,11 @@ export async function runRefactorPlanWorkflow(
81
87
  }
82
88
  if (target.kind !== "resolved") return target;
83
89
 
84
- const readiness = await deps.capability.ensureSemanticReadiness(deps.cwd, {
85
- kind: "file",
86
- file: target.entry.file,
87
- });
90
+ const readiness = await deps.capability.ensureSemanticReadiness(
91
+ deps.cwd,
92
+ { kind: "file", file: target.entry.file },
93
+ control,
94
+ );
88
95
  if (readiness.kind === "timeout") {
89
96
  return { kind: "unavailable", reason: "Semantic readiness timed out." };
90
97
  }
@@ -92,13 +99,17 @@ export async function runRefactorPlanWorkflow(
92
99
  throwIfAborted(control);
93
100
 
94
101
  const file = normalizePath(target.entry.file, deps.cwd);
95
- const result = await planWithProvider(deps.capability.getSemanticProvider(deps.cwd), {
96
- operation: parsed.operation,
97
- file,
98
- position: toLspPosition(target.entry.displayLine, target.entry.displayCharacter),
99
- range: parsed.range ? toLspRange(parsed.range) : undefined,
100
- newName: parsed.newName,
101
- });
102
+ const result = await planWithProvider(
103
+ deps.capability.getSemanticProvider(deps.cwd),
104
+ {
105
+ operation: parsed.operation,
106
+ file,
107
+ position: toLspPosition(target.entry.displayLine, target.entry.displayCharacter),
108
+ range: parsed.range ? toLspRange(parsed.range) : undefined,
109
+ newName: parsed.newName,
110
+ },
111
+ control,
112
+ );
102
113
  if (result.kind === "unavailable") return result;
103
114
  if (result.kind === "ambiguous") {
104
115
  return { kind: "ambiguous", candidates: result.candidates };
@@ -108,6 +119,11 @@ export async function runRefactorPlanWorkflow(
108
119
  if (!validation.safe) {
109
120
  return { kind: "invalid-input", message: `Refactor safety check failed: ${validation.reason}` };
110
121
  }
122
+ const authority = establishMutationAuthority(
123
+ result.edits.edits.map((edit) => edit.file),
124
+ result.authorizedMutationRoots,
125
+ );
126
+ if (authority.kind === "unavailable") return authority;
111
127
 
112
128
  const plan: RefactorPlan = {
113
129
  id: generatePlanId(
@@ -123,6 +139,7 @@ export async function runRefactorPlanWorkflow(
123
139
  targetLine: target.entry.displayLine,
124
140
  targetCharacter: target.entry.displayCharacter,
125
141
  edits: result.edits,
142
+ authorizedMutationRoots: authority.canonicalRoots,
126
143
  fileFingerprints: collectFileFingerprints(result.edits.edits),
127
144
  createdAt: Date.now(),
128
145
  };
@@ -147,6 +164,11 @@ export async function runRefactorApplyWorkflow(
147
164
  };
148
165
  }
149
166
 
167
+ const authority = revalidateMutationAuthority(
168
+ plan.edits.edits.map((edit) => edit.file),
169
+ plan.authorizedMutationRoots,
170
+ );
171
+ if (authority.kind === "unavailable") return authority;
150
172
  const freshness = isPlanFresh(plan);
151
173
  if (!freshness.fresh) return { kind: "invalid-input", message: freshness.reason };
152
174
  const validation = validateEdit(plan.edits);
@@ -161,12 +183,26 @@ export async function runRefactorApplyWorkflow(
161
183
  const expectedFingerprints = new Map(
162
184
  plan.fileFingerprints.map(({ file, fingerprint }) => [file, fingerprint]),
163
185
  );
164
- const result = await applyWorkspaceEdit(plan.edits, { expectedFingerprints });
186
+ const getOpenDocumentVersion = getDocumentVersionReader(deps);
187
+ const result = await applyWorkspaceEdit(plan.edits, {
188
+ authorizedMutationRoots: plan.authorizedMutationRoots,
189
+ expectedFingerprints,
190
+ getOpenDocumentVersion,
191
+ });
165
192
  if (result.kind === "error") return { kind: "unavailable", reason: result.reason };
166
193
  deps.removePlan(plan.id);
167
194
  return { kind: "completed", plan: immutablePlan(plan), result };
168
195
  }
169
196
 
197
+ function getDocumentVersionReader(
198
+ deps: RefactorWorkflowDeps,
199
+ ): ((file: string) => number | null) | undefined {
200
+ const state = deps.capability.getLspRuntimeState(deps.cwd);
201
+ if (state.kind !== "ready" && state.kind !== "inactive") return undefined;
202
+ if (typeof state.runtime.getOpenDocumentVersion !== "function") return undefined;
203
+ return (file) => state.runtime.getOpenDocumentVersion(file);
204
+ }
205
+
170
206
  function parseOperation(input: RefactorOperationInput):
171
207
  | {
172
208
  kind: "ok";
@@ -230,11 +266,12 @@ async function planWithProvider(
230
266
  range?: SourceRange;
231
267
  newName: string;
232
268
  },
269
+ control?: WorkflowControl,
233
270
  ): Promise<RefactorResult> {
234
271
  if (!provider) return { kind: "unavailable", reason: "No semantic provider is active." };
235
- if (provider.refactor) return provider.refactor(request);
272
+ if (provider.refactor) return provider.refactor(request, control);
236
273
  if (request.operation === "rename_symbol" && provider.rename) {
237
- return provider.rename(request.file, request.position, request.newName);
274
+ return provider.rename(request.file, request.position, request.newName, control);
238
275
  }
239
276
  return {
240
277
  kind: "unavailable",
@@ -255,7 +292,15 @@ function immutablePlan(plan: RefactorPlan): Readonly<RefactorPlan> {
255
292
  edits: Object.freeze({
256
293
  ...plan.edits,
257
294
  edits: Object.freeze(plan.edits.edits.map((edit) => Object.freeze({ ...edit }))),
295
+ documentPreconditions: plan.edits.documentPreconditions
296
+ ? Object.freeze(
297
+ plan.edits.documentPreconditions.map((precondition) =>
298
+ Object.freeze({ ...precondition }),
299
+ ),
300
+ )
301
+ : undefined,
258
302
  }),
303
+ authorizedMutationRoots: Object.freeze([...plan.authorizedMutationRoots]),
259
304
  fileFingerprints: Object.freeze(
260
305
  plan.fileFingerprints.map((fingerprint) => Object.freeze({ ...fingerprint })),
261
306
  ),
@@ -231,7 +231,7 @@ export class WorkspaceCodeIntelligenceSession {
231
231
  phase: "target",
232
232
  message: "Resolving target evidence",
233
233
  });
234
- return resolveTargetWorkflow(
234
+ const outcome = await resolveTargetWorkflow(
235
235
  request.target,
236
236
  {
237
237
  fileLevelAllowed: true,
@@ -239,7 +239,10 @@ export class WorkspaceCodeIntelligenceSession {
239
239
  maxResults: request.maxResults,
240
240
  },
241
241
  this.targetWorkflowDeps(),
242
+ control,
242
243
  );
244
+ throwIfAborted(control);
245
+ return outcome;
243
246
  }
244
247
 
245
248
  /** Collect evidence-backed workspace health facts. */
@@ -4,8 +4,10 @@
4
4
  * Turns one exact target selector into immutable resolved-target facts before
5
5
  * graph, Orientation, resolve, or refactor analysis begins.
6
6
  */
7
-
7
+ // biome-ignore lint/style/noExcessiveLinesPerFile: target workflow keeps anchored, symbol, and file resolution together.
8
8
  import { existsSync } from "node:fs";
9
+ import type { CodeRequestControl } from "@mrclrchtr/supi-code-runtime/api";
10
+ import { withSemanticRequestControl, withStructuralRequestControl } from "../analysis/provider.ts";
9
11
  import { normalizePath, resolveScope } from "../analysis/search/paths.ts";
10
12
  import { resolveAnchoredSymbolTarget } from "../analysis/target/anchored.ts";
11
13
  import { resolveFileTargetGroup, validateFileTargetDiscovery } from "../analysis/target/file.ts";
@@ -87,6 +89,7 @@ export async function resolveTargetWorkflow(
87
89
  input: TargetInput,
88
90
  policy: TargetWorkflowPolicy,
89
91
  deps: TargetWorkflowDeps,
92
+ control?: CodeRequestControl,
90
93
  ): Promise<TargetWorkflowOutcome> {
91
94
  const parsed = parseTargetInput(input, ["handle", "anchor", "symbol", "file"]);
92
95
  if (parsed.kind === "invalid-input") return parsed;
@@ -96,10 +99,10 @@ export async function resolveTargetWorkflow(
96
99
  return resolveHandle(target.handle, policy, deps);
97
100
  }
98
101
  if ("anchor" in target) {
99
- return resolveAnchoredWorkflow(target.anchor, policy, deps);
102
+ return resolveAnchoredWorkflow(target.anchor, policy, deps, control);
100
103
  }
101
104
  if ("symbol" in target) {
102
- return resolveSymbolWorkflow(target.symbol, policy, deps);
105
+ return resolveSymbolWorkflow(target.symbol, policy, deps, control);
103
106
  }
104
107
  if (!policy.fileLevelAllowed) {
105
108
  return {
@@ -107,7 +110,7 @@ export async function resolveTargetWorkflow(
107
110
  message: "This workflow requires a handle, anchored point, or symbol target.",
108
111
  };
109
112
  }
110
- return resolveFileOnlyWorkflow(target.file, policy.maxResults ?? 10, deps);
113
+ return resolveFileOnlyWorkflow(target.file, policy.maxResults ?? 10, deps, control);
111
114
  }
112
115
 
113
116
  function resolveHandle(
@@ -134,16 +137,18 @@ async function resolveAnchoredWorkflow(
134
137
  anchor: { file: string; line: number; character: number },
135
138
  policy: TargetWorkflowPolicy,
136
139
  deps: TargetWorkflowDeps,
140
+ control?: CodeRequestControl,
137
141
  ): Promise<TargetWorkflowOutcome> {
138
142
  const file = normalizePath(anchor.file, deps.cwd);
139
143
  if (!existsSync(file)) {
140
144
  return { kind: "invalid-input", message: `File not found: \`${anchor.file}\`` };
141
145
  }
142
146
 
143
- const readiness = await deps.capability.ensureSemanticReadiness(deps.cwd, {
144
- kind: "file",
145
- file,
146
- });
147
+ const readiness = await deps.capability.ensureSemanticReadiness(
148
+ deps.cwd,
149
+ { kind: "file", file },
150
+ control,
151
+ );
147
152
  if (readiness.kind === "timeout") {
148
153
  return {
149
154
  kind: "unavailable",
@@ -158,13 +163,19 @@ async function resolveAnchoredWorkflow(
158
163
  file,
159
164
  anchor.line,
160
165
  anchor.character,
161
- deps.capability.getProvider(deps.cwd),
166
+ withSemanticRequestControl(
167
+ withStructuralRequestControl(deps.capability.getProvider(deps.cwd), control),
168
+ control,
169
+ ),
170
+ control,
162
171
  );
163
172
  return toWorkflowOutcome(
164
173
  await refineTargetOutcomeIdentity(
165
174
  outcome,
166
175
  deps.cwd,
167
- deps.capability.getStructuralProvider(deps.cwd) ?? undefined,
176
+ withStructuralRequestControl(deps.capability.getStructuralProvider(deps.cwd), control) ??
177
+ undefined,
178
+ control,
168
179
  ),
169
180
  policy,
170
181
  deps,
@@ -175,6 +186,7 @@ async function resolveSymbolWorkflow(
175
186
  symbol: { query: string; scope?: string; symbolKind?: TargetSymbolKind },
176
187
  policy: TargetWorkflowPolicy,
177
188
  deps: TargetWorkflowDeps,
189
+ control?: CodeRequestControl,
178
190
  ): Promise<TargetWorkflowOutcome> {
179
191
  if (!symbol.query.trim()) {
180
192
  return { kind: "invalid-input", message: "Symbol query must not be empty." };
@@ -189,9 +201,11 @@ async function resolveSymbolWorkflow(
189
201
  scope = resolved.path;
190
202
  }
191
203
 
192
- const readiness = await deps.capability.ensureSemanticReadiness(deps.cwd, {
193
- kind: "workspace",
194
- });
204
+ const readiness = await deps.capability.ensureSemanticReadiness(
205
+ deps.cwd,
206
+ { kind: "workspace" },
207
+ control,
208
+ );
195
209
  if (readiness.kind === "timeout") {
196
210
  return { kind: "unavailable", reason: "LSP readiness timed out. Retry shortly." };
197
211
  }
@@ -199,7 +213,10 @@ async function resolveSymbolWorkflow(
199
213
  return { kind: "unavailable", reason: readiness.reason };
200
214
  }
201
215
 
202
- const provider = deps.capability.getSemanticProvider(deps.cwd);
216
+ const provider = withSemanticRequestControl(
217
+ deps.capability.getSemanticProvider(deps.cwd),
218
+ control,
219
+ );
203
220
  if (!provider) {
204
221
  return {
205
222
  kind: "unavailable",
@@ -211,12 +228,15 @@ async function resolveSymbolWorkflow(
211
228
  path: scope,
212
229
  kind: symbol.symbolKind,
213
230
  maxResults: policy.maxResults,
231
+ control,
214
232
  });
215
233
  return toWorkflowOutcome(
216
234
  await refineTargetOutcomeIdentity(
217
235
  outcome,
218
236
  deps.cwd,
219
- deps.capability.getStructuralProvider(deps.cwd) ?? undefined,
237
+ withStructuralRequestControl(deps.capability.getStructuralProvider(deps.cwd), control) ??
238
+ undefined,
239
+ control,
220
240
  ),
221
241
  policy,
222
242
  deps,
@@ -227,15 +247,17 @@ async function resolveFileOnlyWorkflow(
227
247
  requestedFile: string,
228
248
  maxResults: number,
229
249
  deps: TargetWorkflowDeps,
250
+ control?: CodeRequestControl,
230
251
  ): Promise<TargetWorkflowOutcome> {
231
252
  const validation = validateFileTargetDiscovery(requestedFile, deps.cwd);
232
253
  if (validation.kind === "invalid-input") return validation;
233
254
  const file = validation.file;
234
255
 
235
- const readiness = await deps.capability.ensureSemanticReadiness(deps.cwd, {
236
- kind: "file",
237
- file,
238
- });
256
+ const readiness = await deps.capability.ensureSemanticReadiness(
257
+ deps.cwd,
258
+ { kind: "file", file },
259
+ control,
260
+ );
239
261
  if (readiness.kind === "timeout") {
240
262
  return { kind: "unavailable", reason: "LSP readiness timed out. Retry shortly." };
241
263
  }
@@ -243,10 +265,19 @@ async function resolveFileOnlyWorkflow(
243
265
  return { kind: "unavailable", reason: readiness.reason };
244
266
  }
245
267
 
246
- const result = await resolveFileTargetGroup(file, deps.cwd, {
247
- semantic: deps.capability.getSemanticProvider(deps.cwd) ?? undefined,
248
- structural: deps.capability.getStructuralProvider(deps.cwd) ?? undefined,
249
- });
268
+ const result = await resolveFileTargetGroup(
269
+ file,
270
+ deps.cwd,
271
+ {
272
+ semantic:
273
+ withSemanticRequestControl(deps.capability.getSemanticProvider(deps.cwd), control) ??
274
+ undefined,
275
+ structural:
276
+ withStructuralRequestControl(deps.capability.getStructuralProvider(deps.cwd), control) ??
277
+ undefined,
278
+ },
279
+ control,
280
+ );
250
281
  if (result.kind === "invalid-input") return result;
251
282
  if (result.kind === "unavailable") {
252
283
  return { kind: "unavailable", reason: result.message };
@@ -1,3 +1,8 @@
1
+ import {
2
+ type CodeRequestControl,
3
+ throwIfCodeRequestInterrupted,
4
+ } from "@mrclrchtr/supi-code-runtime/api";
5
+
1
6
  /** Execution controls shared by Workspace code-intelligence session workflows. */
2
7
 
3
8
  /** Stable progress event emitted by a session-owned workflow. */
@@ -16,8 +21,7 @@ export interface WorkflowProgressEvent {
16
21
  }
17
22
 
18
23
  /** Per-call cancellation and progress controls. */
19
- export interface WorkflowControl {
20
- readonly signal?: AbortSignal;
24
+ export interface WorkflowControl extends CodeRequestControl {
21
25
  readonly progress?: (event: WorkflowProgressEvent) => void;
22
26
  }
23
27
 
@@ -31,5 +35,5 @@ export function reportProgress(
31
35
 
32
36
  /** Throw the platform-standard cancellation reason before starting a phase. */
33
37
  export function throwIfAborted(control: WorkflowControl | undefined): void {
34
- control?.signal?.throwIfAborted();
38
+ throwIfCodeRequestInterrupted(control);
35
39
  }