@mrclrchtr/supi-code-intelligence 4.10.0 → 6.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 (269) hide show
  1. package/README.md +4 -3
  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 +2 -2
  10. package/node_modules/@mrclrchtr/supi-core/src/api.ts +1 -1
  11. package/node_modules/@mrclrchtr/supi-core/src/config/config.ts +31 -0
  12. package/node_modules/@mrclrchtr/supi-core/src/config.ts +2 -0
  13. package/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +19 -6
  14. package/node_modules/@mrclrchtr/supi-core/src/debug.ts +9 -0
  15. package/node_modules/@mrclrchtr/supi-core/src/index.ts +1 -1
  16. package/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +3 -0
  17. package/node_modules/@mrclrchtr/supi-lsp/README.md +111 -5
  18. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/README.md +2 -0
  19. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
  20. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +9 -0
  21. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +53 -13
  22. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/request-control.ts +47 -0
  23. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +13 -1
  24. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/README.md +2 -0
  25. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/package.json +2 -2
  26. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/api.ts +1 -1
  27. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/config/config.ts +31 -0
  28. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/config.ts +2 -0
  29. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +19 -6
  30. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/debug.ts +9 -0
  31. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/index.ts +1 -1
  32. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +3 -0
  33. package/node_modules/@mrclrchtr/supi-lsp/package.json +7 -6
  34. package/node_modules/@mrclrchtr/supi-lsp/src/api.ts +22 -1
  35. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-cache.ts +245 -0
  36. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-capabilities.ts +78 -0
  37. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-collection.ts +171 -0
  38. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-evidence.ts +413 -0
  39. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-host.ts +15 -0
  40. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-publication.ts +214 -0
  41. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-pull.ts +62 -0
  42. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-refresh.ts +690 -0
  43. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-request.ts +9 -0
  44. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-timing.ts +97 -16
  45. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostic-waiters.ts +206 -0
  46. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-diagnostics.ts +448 -298
  47. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-document-state.ts +70 -0
  48. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-document-sync.ts +231 -0
  49. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-file-state.ts +25 -0
  50. package/node_modules/@mrclrchtr/supi-lsp/src/client/client.ts +529 -119
  51. package/node_modules/@mrclrchtr/supi-lsp/src/client/transport.ts +161 -33
  52. package/node_modules/@mrclrchtr/supi-lsp/src/config/capabilities.ts +12 -3
  53. package/node_modules/@mrclrchtr/supi-lsp/src/config/config.ts +5 -5
  54. package/node_modules/@mrclrchtr/supi-lsp/src/config/defaults.json +1 -1
  55. package/node_modules/@mrclrchtr/supi-lsp/src/config/server-config.ts +3 -0
  56. package/node_modules/@mrclrchtr/supi-lsp/src/config/tsconfig-extends.ts +68 -0
  57. package/node_modules/@mrclrchtr/supi-lsp/src/config/tsconfig-path.ts +8 -0
  58. package/node_modules/@mrclrchtr/supi-lsp/src/config/tsconfig-scope.ts +176 -24
  59. package/node_modules/@mrclrchtr/supi-lsp/src/debug-telemetry.ts +45 -0
  60. package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/evidence.ts +42 -0
  61. package/node_modules/@mrclrchtr/supi-lsp/src/diagnostics/workspace-sentinels.ts +46 -10
  62. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-client-state.ts +79 -9
  63. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-diagnostics.ts +17 -7
  64. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-recovery.ts +350 -26
  65. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-workspace-symbol.ts +5 -2
  66. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager.ts +586 -96
  67. package/node_modules/@mrclrchtr/supi-lsp/src/provider/lsp-refactor-provider.ts +130 -0
  68. package/node_modules/@mrclrchtr/supi-lsp/src/provider/lsp-semantic-provider.ts +45 -329
  69. package/node_modules/@mrclrchtr/supi-lsp/src/provider/refactor-planning.ts +57 -120
  70. package/node_modules/@mrclrchtr/supi-lsp/src/provider/semantic-edit-normalizer.ts +320 -0
  71. package/node_modules/@mrclrchtr/supi-lsp/src/provider/semantic-symbol-mapper.ts +207 -0
  72. package/node_modules/@mrclrchtr/supi-lsp/src/session/readiness.ts +72 -2
  73. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-controller.ts +151 -26
  74. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-diagnostic-surface.ts +42 -0
  75. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-diagnostics.ts +92 -0
  76. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-registry.ts +165 -118
  77. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-transition-debug.ts +49 -0
  78. package/node_modules/@mrclrchtr/supi-lsp/src/session/workspace-lsp-runtime.ts +102 -0
  79. package/node_modules/@mrclrchtr/supi-tree-sitter/README.md +17 -7
  80. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/README.md +2 -0
  81. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/package.json +1 -1
  82. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +9 -0
  83. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +53 -13
  84. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/request-control.ts +47 -0
  85. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +13 -1
  86. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/README.md +2 -0
  87. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/package.json +2 -2
  88. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/api.ts +1 -1
  89. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/config/config.ts +31 -0
  90. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/config.ts +2 -0
  91. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +19 -6
  92. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/debug.ts +9 -0
  93. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/index.ts +1 -1
  94. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +3 -0
  95. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/LICENSE +21 -0
  96. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/README.md +258 -0
  97. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/dist/babel.cjs +257 -0
  98. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/dist/jiti.cjs +1 -0
  99. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-cli.mjs +34 -0
  100. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-hooks.mjs +124 -0
  101. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-native.mjs +121 -0
  102. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-register.d.mts +1 -0
  103. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-register.mjs +4 -0
  104. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti-static.mjs +23 -0
  105. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.cjs +30 -0
  106. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.d.cts +8 -0
  107. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.d.mts +8 -0
  108. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/jiti.mjs +29 -0
  109. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/lib/types.d.ts +420 -0
  110. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/jiti/package.json +146 -0
  111. package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +6 -3
  112. package/node_modules/@mrclrchtr/supi-tree-sitter/src/api.ts +0 -9
  113. package/node_modules/@mrclrchtr/supi-tree-sitter/src/index.ts +0 -8
  114. package/node_modules/@mrclrchtr/supi-tree-sitter/src/provider/tree-sitter-provider.ts +16 -12
  115. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/runtime-controller.ts +65 -87
  116. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/session.ts +47 -95
  117. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-timing.ts +147 -0
  118. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-client-lifecycle.ts +39 -0
  119. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-client.ts +561 -0
  120. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-message-size.ts +24 -0
  121. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/structural-worker-protocol.ts +452 -0
  122. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/call-sites.ts +4 -2
  123. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/callees.ts +12 -4
  124. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/exports.ts +4 -2
  125. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/imports.ts +4 -2
  126. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/node-at.ts +5 -3
  127. package/node_modules/@mrclrchtr/supi-tree-sitter/src/types.ts +33 -12
  128. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/blocking-test-bootstrap.mjs +34 -0
  129. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/bootstrap.mjs +8 -0
  130. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/parsed-file-store-helpers.ts +23 -0
  131. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/parsed-file-store.ts +400 -0
  132. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/request-control.ts +48 -0
  133. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/runtime-parser-helpers.ts +24 -0
  134. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/runtime-query-helpers.ts +43 -0
  135. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/runtime.ts +421 -0
  136. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/service.ts +116 -0
  137. package/node_modules/@mrclrchtr/supi-tree-sitter/src/worker/worker-main.ts +201 -0
  138. package/package.json +5 -5
  139. package/src/analysis/health/diagnostics.ts +221 -77
  140. package/src/analysis/health/file-scope.ts +184 -0
  141. package/src/analysis/health/recovery.ts +14 -3
  142. package/src/analysis/provider.ts +58 -0
  143. package/src/analysis/readiness.ts +34 -9
  144. package/src/analysis/refactor/apply.ts +45 -1
  145. package/src/analysis/refactor/mutation-authority.ts +143 -0
  146. package/src/analysis/relations/callees.ts +9 -1
  147. package/src/analysis/relations/types.ts +5 -2
  148. package/src/analysis/search/ast-scan-timing.ts +9 -2
  149. package/src/analysis/search/ast-scan.ts +5 -2
  150. package/src/analysis/search/deadline.ts +2 -2
  151. package/src/analysis/search/pattern-analysis.ts +54 -33
  152. package/src/analysis/search/pattern.ts +18 -3
  153. package/src/analysis/target/anchored.ts +20 -11
  154. package/src/analysis/target/file.ts +18 -11
  155. package/src/analysis/target/identity.ts +19 -3
  156. package/src/analysis/target/symbol.ts +36 -15
  157. package/src/api.ts +4 -0
  158. package/src/config.ts +35 -1
  159. package/src/diagnostics/evidence.ts +51 -0
  160. package/src/extension.ts +57 -14
  161. package/src/overview/overview-data.ts +9 -2
  162. package/src/overview/overview.ts +49 -30
  163. package/src/overview/types.ts +2 -0
  164. package/src/session/capability-adapter.ts +12 -3
  165. package/src/session/find-types.ts +2 -2
  166. package/src/session/find-workflow.ts +20 -9
  167. package/src/session/graph/collect.ts +18 -2
  168. package/src/session/graph-workflow.ts +19 -12
  169. package/src/session/health-refresh.ts +175 -0
  170. package/src/session/health-types.ts +43 -15
  171. package/src/session/health-workflow.ts +69 -54
  172. package/src/session/input/workflows.ts +2 -2
  173. package/src/session/inspect/collect.ts +20 -3
  174. package/src/session/inspect-workflow.ts +12 -6
  175. package/src/session/orientation/collect.ts +12 -3
  176. package/src/session/orientation/context-facts.ts +3 -1
  177. package/src/session/orientation/context-sections.ts +20 -7
  178. package/src/session/orientation/gather.ts +17 -11
  179. package/src/session/orientation-types.ts +4 -1
  180. package/src/session/orientation-workflow.ts +23 -10
  181. package/src/session/refactor-plans.ts +2 -0
  182. package/src/session/refactor-workflow.ts +61 -15
  183. package/src/session/session.ts +29 -2
  184. package/src/session/target-workflow.ts +54 -23
  185. package/src/session/workflow-control.ts +7 -3
  186. package/src/substrate/lsp/lifecycle.ts +26 -46
  187. package/src/substrate/lsp/maintenance.ts +284 -28
  188. package/src/substrate/lsp/recovery.ts +11 -5
  189. package/src/substrate/lsp/state.ts +2 -2
  190. package/src/substrate/workspace-provider-host.ts +25 -3
  191. package/src/tool/{find → code_find}/execute.ts +2 -16
  192. package/src/tool/code_find/guidance.ts +8 -0
  193. package/src/tool/{find → code_find}/render.ts +21 -4
  194. package/src/tool/{result/find.ts → code_find/result.ts} +78 -9
  195. package/src/tool/code_find/spec.ts +37 -0
  196. package/src/tool/code_find/tui.ts +41 -0
  197. package/src/tool/code_graph/execute.ts +24 -0
  198. package/src/tool/code_graph/guidance.ts +6 -0
  199. package/src/tool/{graph → code_graph}/markdown.ts +1 -1
  200. package/src/tool/{result/graph.ts → code_graph/result.ts} +111 -3
  201. package/src/tool/code_graph/spec.ts +39 -0
  202. package/src/tool/code_graph/tui.ts +117 -0
  203. package/src/tool/{health → code_health}/execute.ts +2 -13
  204. package/src/tool/code_health/guidance.ts +8 -0
  205. package/src/tool/{health → code_health}/markdown.ts +119 -27
  206. package/src/tool/code_health/refresh-status.ts +105 -0
  207. package/src/tool/{result/health.ts → code_health/result.ts} +80 -3
  208. package/src/tool/code_health/spec.ts +41 -0
  209. package/src/tool/{health → code_health}/tui.ts +95 -98
  210. package/src/tool/{inspect → code_inspect}/execute.ts +2 -16
  211. package/src/tool/code_inspect/guidance.ts +6 -0
  212. package/src/tool/{inspect → code_inspect}/markdown.ts +1 -1
  213. package/src/tool/{result/inspect.ts → code_inspect/result.ts} +143 -2
  214. package/src/tool/code_inspect/spec.ts +25 -0
  215. package/src/tool/code_inspect/tui.ts +44 -0
  216. package/src/tool/code_orientation/execute.ts +25 -0
  217. package/src/tool/code_orientation/guidance.ts +9 -0
  218. package/src/tool/{orientation → code_orientation}/markdown.ts +1 -1
  219. package/src/tool/code_orientation/result.ts +248 -0
  220. package/src/tool/code_orientation/spec.ts +25 -0
  221. package/src/tool/{orientation → code_orientation}/tui.ts +51 -35
  222. package/src/tool/code_refactor_apply/execute.ts +17 -0
  223. package/src/tool/code_refactor_apply/guidance.ts +5 -0
  224. package/src/tool/{refactor-apply/execute.ts → code_refactor_apply/result.ts} +8 -11
  225. package/src/tool/code_refactor_apply/spec.ts +26 -0
  226. package/src/tool/code_refactor_apply/tui.ts +73 -0
  227. package/src/tool/code_refactor_plan/execute.ts +27 -0
  228. package/src/tool/code_refactor_plan/guidance.ts +8 -0
  229. package/src/tool/{refactor-plan/execute.ts → code_refactor_plan/result.ts} +13 -22
  230. package/src/tool/code_refactor_plan/spec.ts +25 -0
  231. package/src/tool/code_refactor_plan/tui.ts +54 -0
  232. package/src/tool/code_resolve/execute.ts +19 -0
  233. package/src/tool/code_resolve/guidance.ts +8 -0
  234. package/src/tool/{resolve → code_resolve}/markdown.ts +1 -1
  235. package/src/tool/{result/resolve.ts → code_resolve/result.ts} +79 -29
  236. package/src/tool/code_resolve/spec.ts +25 -0
  237. package/src/tool/code_resolve/tui.ts +60 -0
  238. package/src/tool/guidance.ts +71 -52
  239. package/src/tool/infra/truncate.ts +40 -0
  240. package/src/tool/infra/workflow-control.ts +8 -0
  241. package/src/tool/{refactor-plan/markdown.ts → refactor-markdown.ts} +4 -7
  242. package/src/tool/register.ts +105 -88
  243. package/src/tool/result/display.ts +107 -0
  244. package/src/tool/result/errors.ts +20 -17
  245. package/src/tool/result/refactor.ts +37 -8
  246. package/src/tool/result/types.ts +20 -0
  247. package/src/tool/schemas.ts +26 -157
  248. package/src/tool/specs.ts +40 -126
  249. package/src/types/execution.ts +18 -5
  250. package/src/types/index.ts +8 -1
  251. package/src/ui/status-command.ts +5 -3
  252. package/src/ui/status-overlay.ts +4 -0
  253. package/src/ui/tui/common.ts +108 -10
  254. package/src/ui/tui/display.ts +48 -0
  255. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/runtime.ts +0 -351
  256. package/src/tool/find/tui.ts +0 -39
  257. package/src/tool/graph/execute.ts +0 -62
  258. package/src/tool/graph/tui.ts +0 -104
  259. package/src/tool/inspect/tui.ts +0 -36
  260. package/src/tool/orientation/execute.ts +0 -62
  261. package/src/tool/refactor-apply/tui.ts +0 -55
  262. package/src/tool/refactor-plan/tui.ts +0 -41
  263. package/src/tool/resolve/execute.ts +0 -36
  264. package/src/tool/resolve/tui.ts +0 -42
  265. package/src/tool/result/orientation.ts +0 -132
  266. /package/src/tool/{find → code_find}/ast-kinds.ts +0 -0
  267. /package/src/tool/{find → code_find}/markdown.ts +0 -0
  268. /package/src/tool/{find → code_find}/modes.ts +0 -0
  269. /package/src/tool/{health → code_health}/semantic-state.ts +0 -0
@@ -0,0 +1,92 @@
1
+ import type { Diagnostic } from "../config/types.ts";
2
+ import type { DiagnosticEvidenceSummary } from "../diagnostics/evidence.ts";
3
+
4
+ export type {
5
+ DiagnosticEvidenceDocument,
6
+ DiagnosticEvidenceStatus,
7
+ DiagnosticEvidenceSummary,
8
+ } from "../diagnostics/evidence.ts";
9
+
10
+ /** Workspace diagnostic snapshot with explicit cache freshness and coverage. */
11
+ export interface WorkspaceDiagnosticSnapshot<T> {
12
+ entries: T[];
13
+ current: boolean;
14
+ evidence: DiagnosticEvidenceSummary;
15
+ }
16
+
17
+ /** Workspace diagnostic summary grouped by file. */
18
+ export interface WorkspaceDiagnosticSummaryEntry {
19
+ file: string;
20
+ errors: number;
21
+ warnings: number;
22
+ }
23
+
24
+ /**
25
+ * One coherent post-refresh observation of workspace diagnostics.
26
+ *
27
+ * Both projections are captured from the same client snapshots. The report is
28
+ * short-lived and must not be retained as the runtime's last refresh attempt.
29
+ */
30
+ export interface WorkspaceDiagnosticReport {
31
+ summary: WorkspaceDiagnosticSnapshot<WorkspaceDiagnosticSummaryEntry>;
32
+ outstanding: WorkspaceDiagnosticSnapshot<{
33
+ file: string;
34
+ diagnostics: Diagnostic[];
35
+ }>;
36
+ }
37
+
38
+ /** Outstanding diagnostics grouped by file, including info and hint counts. */
39
+ export interface OutstandingDiagnosticSummaryEntry {
40
+ file: string;
41
+ total: number;
42
+ errors: number;
43
+ warnings: number;
44
+ information: number;
45
+ hints: number;
46
+ }
47
+
48
+ /** Result from a workspace diagnostic recovery pass. */
49
+ export interface RecoverDiagnosticsResult {
50
+ /** Active clients targeted by the best-effort refresh, not confirmed successful refreshes. */
51
+ attemptedClients: number;
52
+ restartedClients: number;
53
+ /** Evidence collected by the refresh and recovery operations. */
54
+ diagnosticEvidence: DiagnosticEvidenceSummary;
55
+ /** Final diagnostic report captured after all refresh and recovery work. */
56
+ diagnosticReport: WorkspaceDiagnosticReport;
57
+ /** Failure from the first refresh, when no later pass replaced it. */
58
+ refreshFailureReason?: string;
59
+ /** Wall-clock duration of the whole recovery pass, for telemetry. */
60
+ elapsedMs: number;
61
+ staleAssessment: {
62
+ suspected: boolean;
63
+ matchedFiles: Array<{ file: string; diagnostics: Diagnostic[] }>;
64
+ warning: string | null;
65
+ };
66
+ }
67
+
68
+ /** One tracked file's tsconfig scope decision, for debug telemetry. */
69
+ export interface ScopeDecisionEntry {
70
+ /** Workspace-relative file path. */
71
+ file: string;
72
+ status: "included" | "excluded" | "no-config" | "out-of-tree";
73
+ /** Decision mechanism; null when no decision applies. */
74
+ basis: string | null;
75
+ }
76
+
77
+ /** Aggregate tsconfig scope decisions for all tracked files, for debug telemetry. */
78
+ export interface ScopeDecisionSummary {
79
+ caseSensitiveFileNames: boolean;
80
+ counts: {
81
+ included: number;
82
+ excluded: number;
83
+ noConfig: number;
84
+ outOfTree: number;
85
+ };
86
+ /** Exact decision-basis counts; keys are {@link ScopeDecisionEntry.basis} values. */
87
+ basisCounts: Record<string, number>;
88
+ /** Bounded workspace-relative entries (oldest first), not the full set. */
89
+ entries: ScopeDecisionEntry[];
90
+ /** Total number of tracked files the summary was computed over. */
91
+ totalFiles: number;
92
+ }
@@ -1,10 +1,15 @@
1
1
  // Shared session-scoped LSP service registry reused by peer extensions.
2
2
 
3
+ // biome-ignore lint/style/noExcessiveLinesPerFile: session registry, runtime recovery, and telemetry stay in one file; splitting would hide the recovery contract.
3
4
  import {
4
5
  type CodeQueryResult,
6
+ type CodeRequestControl,
7
+ isCodeRequestInterruption,
5
8
  mapCodeQueryResult,
9
+ throwIfCodeRequestInterrupted,
6
10
  unavailableCodeQuery,
7
11
  } from "@mrclrchtr/supi-code-runtime/api";
12
+ import { recordDebugEvent } from "@mrclrchtr/supi-core/debug";
8
13
  import { createSessionStateRegistry } from "@mrclrchtr/supi-core/session";
9
14
  import type {
10
15
  CodeAction,
@@ -21,9 +26,35 @@ import type {
21
26
  WorkspaceEdit,
22
27
  WorkspaceSymbol,
23
28
  } from "../config/types.ts";
29
+ import { boundServerNames, truncateIdentity } from "../debug-telemetry.ts";
24
30
  import type { LspManager } from "../manager/manager.ts";
25
31
  import { resolveSessionPath } from "../utils.ts";
26
32
  import { raceReadinessValue } from "./readiness.ts";
33
+ import type { DiagnosticEvidenceSummary, RecoverDiagnosticsResult } from "./runtime-diagnostics.ts";
34
+ import type {
35
+ RoutedMutationResponse,
36
+ SemanticReadinessResult,
37
+ WorkspaceLspRuntime,
38
+ WorkspaceLspRuntimeState,
39
+ } from "./workspace-lsp-runtime.ts";
40
+
41
+ export type { WorkspaceLspDiagnosticSurface } from "./runtime-diagnostic-surface.ts";
42
+ export type {
43
+ DiagnosticEvidenceDocument,
44
+ DiagnosticEvidenceStatus,
45
+ DiagnosticEvidenceSummary,
46
+ OutstandingDiagnosticSummaryEntry,
47
+ RecoverDiagnosticsResult,
48
+ WorkspaceDiagnosticReport,
49
+ WorkspaceDiagnosticSnapshot,
50
+ WorkspaceDiagnosticSummaryEntry,
51
+ } from "./runtime-diagnostics.ts";
52
+ export type {
53
+ RoutedMutationResponse,
54
+ SemanticReadinessResult,
55
+ WorkspaceLspRuntime,
56
+ WorkspaceLspRuntimeState,
57
+ } from "./workspace-lsp-runtime.ts";
27
58
 
28
59
  function isRange(value: Position | Range): value is Range {
29
60
  return "start" in value && "end" in value;
@@ -33,97 +64,31 @@ function unavailableFileQuery<T>(operation: string, file: string): CodeQueryResu
33
64
  return unavailableCodeQuery(`No routed LSP client could complete ${operation} for ${file}.`);
34
65
  }
35
66
 
36
- /** Workspace diagnostic summary grouped by file. */
37
- export interface WorkspaceDiagnosticSummaryEntry {
38
- file: string;
39
- errors: number;
40
- warnings: number;
41
- }
42
-
43
- /** Outstanding diagnostics grouped by file, including info and hint counts. */
44
- export interface OutstandingDiagnosticSummaryEntry {
45
- file: string;
46
- total: number;
47
- errors: number;
48
- warnings: number;
49
- information: number;
50
- hints: number;
51
- }
52
-
53
- /** Result from a workspace diagnostic recovery pass. */
54
- export interface RecoverDiagnosticsResult {
55
- /** Active clients targeted by the best-effort refresh, not confirmed successful refreshes. */
56
- attemptedClients: number;
57
- restartedClients: number;
58
- staleAssessment: {
59
- suspected: boolean;
60
- matchedFiles: Array<{ file: string; diagnostics: Diagnostic[] }>;
61
- warning: string | null;
62
- };
63
- }
64
-
65
- export type WorkspaceLspRuntimeState =
66
- | { kind: "ready"; runtime: WorkspaceLspRuntime }
67
- | { kind: "inactive"; runtime: WorkspaceLspRuntime }
68
- | { kind: "pending" }
69
- | { kind: "disabled" }
70
- | { kind: "unavailable"; reason: string };
71
-
72
- export type SemanticReadinessResult =
73
- | { kind: "ready" }
74
- | { kind: "timeout" }
75
- | { kind: "unavailable"; reason: string };
76
-
77
- /**
78
- * Workspace-scoped LSP interface that owns routing, readiness, semantic operations,
79
- * diagnostics, and recovery without exposing clients or the mutable manager.
80
- * File path inputs may be absolute or session-cwd-relative; a leading `@` is stripped
81
- * to match pi's built-in path-tool convention. Position arguments use raw 0-based LSP
82
- * coordinates; use `toLspPosition()` from `@mrclrchtr/supi-lsp/api` when starting from
83
- * user-facing 1-based line and character values.
84
- */
85
- export interface WorkspaceLspRuntime {
86
- hover(filePath: string, position: Position): Promise<CodeQueryResult<Hover | null>>;
87
- definition(
88
- filePath: string,
89
- position: Position,
90
- ): Promise<CodeQueryResult<Location | Location[] | LocationLink[] | null>>;
91
- references(filePath: string, position: Position): Promise<CodeQueryResult<Location[]>>;
92
- implementation(
93
- filePath: string,
94
- position: Position,
95
- ): Promise<CodeQueryResult<Location | Location[] | LocationLink[] | null>>;
96
- documentSymbols(
97
- filePath: string,
98
- ): Promise<CodeQueryResult<DocumentSymbol[] | SymbolInformation[]>>;
99
- workspaceSymbol(query: string): Promise<CodeQueryResult<SymbolInformation[] | WorkspaceSymbol[]>>;
100
- rename(filePath: string, position: Position, newName: string): Promise<WorkspaceEdit | null>;
101
- codeActions(filePath: string, positionOrRange: Position | Range): Promise<CodeAction[] | null>;
102
- /** Succeeds only when the concrete routed client exists and is query-ready. */
103
- waitUntilReadyForFile(
104
- filePath: string,
105
- options?: { timeoutMs?: number },
106
- ): Promise<SemanticReadinessResult>;
107
- /** Succeeds only when at least one concrete workspace client is active and query-ready. */
108
- waitUntilReadyForWorkspace(options?: { timeoutMs?: number }): Promise<SemanticReadinessResult>;
109
- getProjectServers(): ProjectServerInfo[];
110
- isSupportedSourceFile(filePath: string): boolean;
111
- trackFile(filePath: string): Promise<boolean>;
112
- closeFile(filePath: string): void;
113
- pruneMissingFiles(): readonly string[];
114
- noteWorkspaceChanges(changes: FileEvent[]): void;
115
- fileDiagnostics(filePath: string, maxSeverity?: number): Promise<CodeQueryResult<Diagnostic[]>>;
116
- refreshOpenDiagnostics(options?: { maxWaitMs?: number; quietMs?: number }): Promise<void>;
117
- getWorkspaceDiagnosticSummary(): WorkspaceDiagnosticSummaryEntry[];
118
- getOutstandingDiagnostics(
119
- maxSeverity?: number,
120
- ): Array<{ file: string; diagnostics: Diagnostic[] }>;
121
- getOutstandingDiagnosticSummary(maxSeverity?: number): OutstandingDiagnosticSummaryEntry[];
122
- recoverDiagnostics(options?: {
123
- restartIfStillStale?: boolean;
124
- maxWaitMs?: number;
125
- quietMs?: number;
126
- }): Promise<RecoverDiagnosticsResult>;
67
+ /** Emit one aggregate tsconfig scope-decision event after a recovery pass. */
68
+ function recordScopeDecisionEvent(manager: LspManager): void {
69
+ try {
70
+ const summary = manager.getScopeDecisionSummary();
71
+ recordDebugEvent({
72
+ source: "lsp",
73
+ level: "debug",
74
+ category: "diagnostics.scope",
75
+ message: "LSP diagnostic tsconfig scope decisions",
76
+ cwd: truncateIdentity(manager.getCwd()),
77
+ data: {
78
+ caseSensitiveFileNames: summary.caseSensitiveFileNames,
79
+ counts: summary.counts,
80
+ basisCounts: summary.basisCounts,
81
+ totalFiles: summary.totalFiles,
82
+ entries: summary.entries.map((entry) => ({
83
+ file: truncateIdentity(entry.file),
84
+ status: entry.status,
85
+ ...(entry.basis ? { basis: entry.basis } : {}),
86
+ })),
87
+ },
88
+ });
89
+ } catch {
90
+ // Telemetry must never turn a completed recovery into a failure.
91
+ }
127
92
  }
128
93
 
129
94
  class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
@@ -136,29 +101,38 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
136
101
 
137
102
  // ── Semantic lookups ────────────────────────────────────────────────
138
103
 
139
- async hover(filePath: string, position: Position): Promise<CodeQueryResult<Hover | null>> {
104
+ async hover(
105
+ filePath: string,
106
+ position: Position,
107
+ control?: CodeRequestControl,
108
+ ): Promise<CodeQueryResult<Hover | null>> {
140
109
  const resolvedPath = this.resolveFilePath(filePath);
141
110
  const client = await this.manager.ensureFileOpen(resolvedPath);
142
111
  if (!client) return unavailableFileQuery("hover", resolvedPath);
143
- return client.hover(resolvedPath, position);
112
+ return client.hover(resolvedPath, position, control);
144
113
  }
145
114
 
146
115
  async definition(
147
116
  filePath: string,
148
117
  position: Position,
118
+ control?: CodeRequestControl,
149
119
  ): Promise<CodeQueryResult<Location | Location[] | LocationLink[] | null>> {
150
120
  const resolvedPath = this.resolveFilePath(filePath);
151
121
  const client = await this.manager.ensureFileOpen(resolvedPath);
152
122
  if (!client) return unavailableFileQuery("definition", resolvedPath);
153
- return client.definition(resolvedPath, position);
123
+ return client.definition(resolvedPath, position, control);
154
124
  }
155
125
 
156
- async references(filePath: string, position: Position): Promise<CodeQueryResult<Location[]>> {
126
+ async references(
127
+ filePath: string,
128
+ position: Position,
129
+ control?: CodeRequestControl,
130
+ ): Promise<CodeQueryResult<Location[]>> {
157
131
  const resolvedPath = this.resolveFilePath(filePath);
158
132
  const client = await this.manager.ensureFileOpen(resolvedPath);
159
133
  if (!client) return unavailableFileQuery("references", resolvedPath);
160
134
  return mapCodeQueryResult(
161
- await client.references(resolvedPath, position),
135
+ await client.references(resolvedPath, position, control),
162
136
  (data) => data ?? [],
163
137
  );
164
138
  }
@@ -166,43 +140,58 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
166
140
  async implementation(
167
141
  filePath: string,
168
142
  position: Position,
143
+ control?: CodeRequestControl,
169
144
  ): Promise<CodeQueryResult<Location | Location[] | LocationLink[] | null>> {
170
145
  const resolvedPath = this.resolveFilePath(filePath);
171
146
  const client = await this.manager.ensureFileOpen(resolvedPath);
172
147
  if (!client) return unavailableFileQuery("implementation", resolvedPath);
173
- return client.implementation(resolvedPath, position);
148
+ return client.implementation(resolvedPath, position, control);
174
149
  }
175
150
 
176
151
  async documentSymbols(
177
152
  filePath: string,
153
+ control?: CodeRequestControl,
178
154
  ): Promise<CodeQueryResult<DocumentSymbol[] | SymbolInformation[]>> {
179
155
  const resolvedPath = this.resolveFilePath(filePath);
180
156
  const client = await this.manager.ensureFileOpen(resolvedPath);
181
157
  if (!client) return unavailableFileQuery("document symbols", resolvedPath);
182
- return mapCodeQueryResult(await client.documentSymbols(resolvedPath), (data) => data ?? []);
158
+ return mapCodeQueryResult(
159
+ await client.documentSymbols(resolvedPath, control),
160
+ (data) => data ?? [],
161
+ );
183
162
  }
184
163
 
185
164
  async workspaceSymbol(
186
165
  query: string,
166
+ control?: CodeRequestControl,
187
167
  ): Promise<CodeQueryResult<SymbolInformation[] | WorkspaceSymbol[]>> {
188
- return this.manager.workspaceSymbol(query);
168
+ return this.manager.workspaceSymbol(query, control);
189
169
  }
190
170
 
191
171
  async rename(
192
172
  filePath: string,
193
173
  position: Position,
194
174
  newName: string,
195
- ): Promise<WorkspaceEdit | null> {
175
+ control?: CodeRequestControl,
176
+ ): Promise<RoutedMutationResponse<WorkspaceEdit | null> | null> {
196
177
  const resolvedPath = this.resolveFilePath(filePath);
197
178
  const client = await this.manager.ensureFileOpen(resolvedPath);
198
179
  if (!client) return null;
199
- return client.rename(resolvedPath, position, newName);
180
+ return {
181
+ value: await client.rename(resolvedPath, position, newName, control),
182
+ authorizedMutationRoots: [client.root],
183
+ };
184
+ }
185
+
186
+ getOpenDocumentVersion(filePath: string): number | null {
187
+ return this.manager.getOpenDocumentVersion(this.resolveFilePath(filePath));
200
188
  }
201
189
 
202
190
  async codeActions(
203
191
  filePath: string,
204
192
  positionOrRange: Position | Range,
205
- ): Promise<CodeAction[] | null> {
193
+ control?: CodeRequestControl,
194
+ ): Promise<RoutedMutationResponse<CodeAction[] | null> | null> {
206
195
  const resolvedPath = this.resolveFilePath(filePath);
207
196
  const client = await this.manager.ensureFileOpen(resolvedPath);
208
197
  if (!client) return null;
@@ -215,7 +204,10 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
215
204
  .filter((diagnostic) => diagnostic.range.end.line >= range.start.line)
216
205
  .filter((diagnostic) => diagnostic.range.start.line <= range.end.line);
217
206
 
218
- return client.codeActions(resolvedPath, range, { diagnostics });
207
+ return {
208
+ value: await client.codeActions(resolvedPath, range, { diagnostics }, control),
209
+ authorizedMutationRoots: [client.root],
210
+ };
219
211
  }
220
212
 
221
213
  /**
@@ -225,6 +217,7 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
225
217
  async waitUntilReadyForFile(
226
218
  filePath: string,
227
219
  options: { timeoutMs?: number } = {},
220
+ control?: CodeRequestControl,
228
221
  ): Promise<SemanticReadinessResult> {
229
222
  const resolvedPath = this.resolveFilePath(filePath);
230
223
  if (!this.manager.canServeFile(resolvedPath)) {
@@ -235,8 +228,9 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
235
228
  }
236
229
 
237
230
  const readiness = await raceReadinessValue(
238
- this.manager.waitUntilFileReady(resolvedPath),
231
+ this.manager.waitUntilFileReady(resolvedPath, control),
239
232
  options.timeoutMs,
233
+ control,
240
234
  );
241
235
  if (readiness.kind !== "resolved") return readiness;
242
236
  if (readiness.value === null) {
@@ -254,10 +248,12 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
254
248
  */
255
249
  async waitUntilReadyForWorkspace(
256
250
  options: { timeoutMs?: number } = {},
251
+ control?: CodeRequestControl,
257
252
  ): Promise<SemanticReadinessResult> {
258
253
  const readiness = await raceReadinessValue(
259
- this.manager.waitUntilWorkspaceReady(),
254
+ this.manager.waitUntilWorkspaceReady(control),
260
255
  options.timeoutMs,
256
+ control,
261
257
  );
262
258
  if (readiness.kind !== "resolved") return readiness;
263
259
  if (readiness.value === 0) {
@@ -297,7 +293,7 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
297
293
  /** Notify routed clients of workspace file changes and reset pull state. */
298
294
  noteWorkspaceChanges(changes: FileEvent[]): void {
299
295
  this.manager.clearAllPullResultIds();
300
- this.manager.notifyWorkspaceFileChanges(changes);
296
+ this.manager.noteWorkspaceChanges(changes);
301
297
  }
302
298
 
303
299
  async #shutdown(): Promise<void> {
@@ -310,34 +306,36 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
310
306
  async fileDiagnostics(
311
307
  filePath: string,
312
308
  maxSeverity: number = 4,
309
+ control?: CodeRequestControl,
313
310
  ): Promise<CodeQueryResult<Diagnostic[]>> {
314
311
  const resolvedPath = this.resolveFilePath(filePath);
315
312
  if (!this.manager.canServeFile(resolvedPath)) {
316
313
  return unavailableFileQuery("diagnostics", resolvedPath);
317
314
  }
318
- return this.manager.syncFileAndGetDiagnostics(resolvedPath, maxSeverity);
315
+ return this.manager.syncFileAndGetDiagnostics(resolvedPath, maxSeverity, control);
319
316
  }
320
317
 
321
318
  /** Re-sync every open document and wait for diagnostics to settle. */
322
- async refreshOpenDiagnostics(options?: { maxWaitMs?: number; quietMs?: number }): Promise<void> {
323
- await this.manager.refreshOpenDiagnostics(options);
319
+ async refreshOpenDiagnostics(
320
+ options?: { maxWaitMs?: number; quietMs?: number },
321
+ control?: CodeRequestControl,
322
+ ): Promise<DiagnosticEvidenceSummary> {
323
+ return this.manager.refreshOpenDiagnostics({ ...options, ...control });
324
324
  }
325
325
 
326
326
  /** Get a lightweight workspace diagnostic summary for all tracked files. */
327
- getWorkspaceDiagnosticSummary(): WorkspaceDiagnosticSummaryEntry[] {
328
- return this.manager.getDiagnosticSummary();
327
+ getWorkspaceDiagnosticSummary() {
328
+ return this.manager.getDiagnosticSnapshot();
329
329
  }
330
330
 
331
331
  /** Get outstanding diagnostics grouped by file at or above the supplied severity threshold. */
332
- getOutstandingDiagnostics(
333
- maxSeverity: number = 1,
334
- ): Array<{ file: string; diagnostics: Diagnostic[] }> {
335
- return this.manager.getOutstandingDiagnostics(maxSeverity);
332
+ getOutstandingDiagnostics(maxSeverity: number = 1) {
333
+ return this.manager.getOutstandingDiagnosticsSnapshot(maxSeverity);
336
334
  }
337
335
 
338
336
  /** Get outstanding diagnostic counts grouped by file. */
339
- getOutstandingDiagnosticSummary(maxSeverity: number = 1): OutstandingDiagnosticSummaryEntry[] {
340
- return this.manager.getOutstandingDiagnosticSummary(maxSeverity);
337
+ getOutstandingDiagnosticSummary(maxSeverity: number = 1) {
338
+ return this.manager.getOutstandingDiagnosticSummarySnapshot(maxSeverity);
341
339
  }
342
340
 
343
341
  /** Trigger a workspace-wide diagnostics refresh and stale-state recovery pass. */
@@ -345,8 +343,53 @@ class DefaultWorkspaceLspRuntime implements WorkspaceLspRuntime {
345
343
  restartIfStillStale?: boolean;
346
344
  maxWaitMs?: number;
347
345
  quietMs?: number;
346
+ /** Evidence from a refresh the caller already completed; skips this pass's own refresh when no watched-file changes apply. */
347
+ initialEvidence?: DiagnosticEvidenceSummary;
348
+ control?: CodeRequestControl;
348
349
  }): Promise<RecoverDiagnosticsResult> {
349
- return this.manager.recoverWorkspaceDiagnostics(options);
350
+ const recoveryStartedAt = Date.now();
351
+ try {
352
+ const result = await this.manager.recoverWorkspaceDiagnostics(options);
353
+ const outcome = result.refreshFailureReason ? "failed" : "completed";
354
+ recordDebugEvent({
355
+ source: "lsp",
356
+ level: "debug",
357
+ category: "runtime.recovery",
358
+ message: `LSP diagnostic recovery ${outcome}`,
359
+ cwd: truncateIdentity(this.manager.getCwd()),
360
+ data: {
361
+ outcome,
362
+ elapsedMs: result.elapsedMs,
363
+ attemptedClients: result.attemptedClients,
364
+ restartedClients: result.restartedClients,
365
+ attemptedServers: boundServerNames(result.attemptedServers ?? []),
366
+ restartedServers: boundServerNames(result.restartedServers ?? []),
367
+ ...(result.restartReason ? { reason: result.restartReason } : {}),
368
+ },
369
+ });
370
+ recordScopeDecisionEvent(this.manager);
371
+ return result;
372
+ } catch (error) {
373
+ // A cancelled pass has no result object, so telemetry records the
374
+ // cancelled outcome, the elapsed time, and the server names that are
375
+ // still running at cancellation. Restart identity is unavailable
376
+ // because the pass produced no result.
377
+ if (isCodeRequestInterruption(error, options?.control)) {
378
+ recordDebugEvent({
379
+ source: "lsp",
380
+ level: "debug",
381
+ category: "runtime.recovery",
382
+ message: "LSP diagnostic recovery cancelled",
383
+ cwd: truncateIdentity(this.manager.getCwd()),
384
+ data: {
385
+ outcome: "cancelled",
386
+ elapsedMs: Date.now() - recoveryStartedAt,
387
+ attemptedServers: boundServerNames(this.manager.getRunningClientNames()),
388
+ },
389
+ });
390
+ }
391
+ throw error;
392
+ }
350
393
  }
351
394
 
352
395
  private resolveFilePath(filePath: string): string {
@@ -380,15 +423,19 @@ export function getWorkspaceLspRuntime(cwd: string): WorkspaceLspRuntimeState {
380
423
  export async function waitForWorkspaceLspRuntime(
381
424
  cwd: string,
382
425
  timeoutMs: number = 250,
426
+ control?: CodeRequestControl,
383
427
  ): Promise<WorkspaceLspRuntimeState> {
384
428
  const deadline = Date.now() + Math.max(0, timeoutMs);
385
429
  let state = getWorkspaceLspRuntime(cwd);
386
430
 
387
431
  while (state.kind === "pending" && Date.now() < deadline) {
432
+ throwIfCodeRequestInterrupted(control);
388
433
  await new Promise((resolve) => setTimeout(resolve, WAIT_INTERVAL_MS));
389
434
  state = getWorkspaceLspRuntime(cwd);
390
435
  }
391
436
 
437
+ // A cancelled poll must not hand a runtime to a caller that no longer awaits.
438
+ throwIfCodeRequestInterrupted(control);
392
439
  return state;
393
440
  }
394
441
 
@@ -0,0 +1,49 @@
1
+ import { recordDebugEvent } from "@mrclrchtr/supi-core/debug";
2
+ import type { ProjectServerInfo } from "../config/types.ts";
3
+ import { MAX_SERVERS, truncateIdentity } from "../debug-telemetry.ts";
4
+ import type { LspRuntimeTransition } from "./runtime-controller.ts";
5
+
6
+ /** One bounded server entry in a runtime-transition payload. */
7
+ export interface TransitionServerEntry {
8
+ readonly name: string;
9
+ readonly status: ProjectServerInfo["status"];
10
+ readonly ready: boolean;
11
+ }
12
+
13
+ /** Bound a project-server snapshot to MAX_SERVERS name/status/ready entries. */
14
+ function boundedServerEntries(
15
+ projectServers: readonly ProjectServerInfo[],
16
+ ): TransitionServerEntry[] {
17
+ return projectServers.slice(0, MAX_SERVERS).map((server) => ({
18
+ name: truncateIdentity(server.name),
19
+ status: server.status,
20
+ ready: server.ready,
21
+ }));
22
+ }
23
+
24
+ /** Record bounded aggregate telemetry for one runtime transition. */
25
+ export function recordLspRuntimeTransition(cwd: string, transition: LspRuntimeTransition): void {
26
+ const readyClients = transition.projectServers.filter(
27
+ (server) => server.status === "running" && server.ready,
28
+ ).length;
29
+ const trackedFiles = transition.projectServers.reduce(
30
+ (count, server) => count + server.openFiles.length,
31
+ 0,
32
+ );
33
+ recordDebugEvent({
34
+ source: "lsp",
35
+ level: transition.kind === "crash" ? "warning" : "debug",
36
+ category: "runtime.transition",
37
+ message: `LSP runtime transition: ${transition.kind}`,
38
+ cwd: truncateIdentity(cwd),
39
+ data: {
40
+ generation: transition.generation,
41
+ kind: transition.kind,
42
+ semanticReady: transition.semanticReady,
43
+ readyClients,
44
+ totalClients: transition.projectServers.length,
45
+ trackedFiles,
46
+ servers: boundedServerEntries(transition.projectServers),
47
+ },
48
+ });
49
+ }