@mrclrchtr/supi-code-intelligence 1.16.1 → 2.0.1

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 (344) hide show
  1. package/README.md +373 -63
  2. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +6 -1
  3. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/abort-utils.ts +31 -0
  4. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/api.ts +8 -0
  5. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config/config-settings.ts +10 -4
  6. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config.ts +1 -0
  7. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/footer-registry.ts +1 -1
  8. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/index.ts +6 -0
  9. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/model-selection.ts +134 -0
  10. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +9 -2
  11. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-ui.ts +109 -4
  12. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings-ui.ts +5 -1
  13. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/spinner-frames.ts +11 -0
  14. package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/status-spinner.ts +68 -0
  15. package/node_modules/@mrclrchtr/supi-code-runtime/package.json +3 -2
  16. package/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +7 -0
  17. package/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +56 -2
  18. package/node_modules/@mrclrchtr/supi-code-runtime/src/evidence-badge.ts +40 -0
  19. package/node_modules/@mrclrchtr/supi-code-runtime/src/index.ts +5 -0
  20. package/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +76 -3
  21. package/node_modules/@mrclrchtr/supi-code-runtime/src/workspace/runtime.ts +37 -2
  22. package/node_modules/@mrclrchtr/supi-core/package.json +6 -1
  23. package/node_modules/@mrclrchtr/supi-core/src/abort-utils.ts +31 -0
  24. package/node_modules/@mrclrchtr/supi-core/src/api.ts +8 -0
  25. package/node_modules/@mrclrchtr/supi-core/src/config/config-settings.ts +10 -4
  26. package/node_modules/@mrclrchtr/supi-core/src/config.ts +1 -0
  27. package/node_modules/@mrclrchtr/supi-core/src/footer-registry.ts +1 -1
  28. package/node_modules/@mrclrchtr/supi-core/src/index.ts +6 -0
  29. package/node_modules/@mrclrchtr/supi-core/src/model-selection.ts +134 -0
  30. package/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +9 -2
  31. package/node_modules/@mrclrchtr/supi-core/src/settings/settings-ui.ts +109 -4
  32. package/node_modules/@mrclrchtr/supi-core/src/settings-ui.ts +5 -1
  33. package/node_modules/@mrclrchtr/supi-core/src/spinner-frames.ts +11 -0
  34. package/node_modules/@mrclrchtr/supi-core/src/status-spinner.ts +68 -0
  35. package/node_modules/@mrclrchtr/supi-lsp/README.md +44 -56
  36. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +6 -1
  37. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/abort-utils.ts +31 -0
  38. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/api.ts +8 -0
  39. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config/config-settings.ts +10 -4
  40. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config.ts +1 -0
  41. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/footer-registry.ts +1 -1
  42. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/index.ts +6 -0
  43. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/model-selection.ts +134 -0
  44. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +9 -2
  45. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-ui.ts +109 -4
  46. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings-ui.ts +5 -1
  47. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/spinner-frames.ts +11 -0
  48. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/status-spinner.ts +68 -0
  49. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/package.json +3 -2
  50. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +7 -0
  51. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +56 -2
  52. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/evidence-badge.ts +40 -0
  53. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/index.ts +5 -0
  54. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +76 -3
  55. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-code-runtime/src/workspace/runtime.ts +37 -2
  56. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/package.json +6 -1
  57. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/abort-utils.ts +31 -0
  58. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/api.ts +8 -0
  59. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/config/config-settings.ts +10 -4
  60. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/config.ts +1 -0
  61. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/footer-registry.ts +1 -1
  62. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/index.ts +6 -0
  63. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/model-selection.ts +134 -0
  64. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +9 -2
  65. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings/settings-ui.ts +109 -4
  66. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/settings-ui.ts +5 -1
  67. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/spinner-frames.ts +11 -0
  68. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/status-spinner.ts +68 -0
  69. package/node_modules/@mrclrchtr/supi-lsp/package.json +4 -31
  70. package/node_modules/@mrclrchtr/supi-lsp/src/api.ts +27 -0
  71. package/node_modules/@mrclrchtr/supi-lsp/src/client/client-refresh.ts +5 -0
  72. package/node_modules/@mrclrchtr/supi-lsp/src/client/client.ts +246 -1
  73. package/node_modules/@mrclrchtr/supi-lsp/src/client/transport.ts +4 -0
  74. package/node_modules/@mrclrchtr/supi-lsp/src/config/capabilities.ts +3 -0
  75. package/node_modules/@mrclrchtr/supi-lsp/src/config/config.ts +4 -2
  76. package/node_modules/@mrclrchtr/supi-lsp/src/config/lsp-settings.ts +102 -0
  77. package/node_modules/@mrclrchtr/supi-lsp/src/config/server-actions.ts +59 -0
  78. package/node_modules/@mrclrchtr/supi-lsp/src/config/server-config.ts +4 -0
  79. package/node_modules/@mrclrchtr/supi-lsp/src/index.ts +11 -0
  80. package/node_modules/@mrclrchtr/supi-lsp/src/manager/capability-index.ts +1 -1
  81. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-project-info.ts +2 -1
  82. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager.ts +115 -26
  83. package/node_modules/@mrclrchtr/supi-lsp/src/provider/lsp-semantic-provider.ts +177 -134
  84. package/node_modules/@mrclrchtr/supi-lsp/src/provider/refactor-planning.ts +214 -0
  85. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-controller.ts +320 -0
  86. package/node_modules/@mrclrchtr/supi-lsp/src/session/runtime-registration.ts +26 -5
  87. package/node_modules/@mrclrchtr/supi-lsp/src/session/service-registry.ts +81 -4
  88. package/node_modules/@mrclrchtr/supi-lsp/src/summary.ts +2 -0
  89. package/node_modules/@mrclrchtr/supi-tree-sitter/README.md +18 -37
  90. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +6 -1
  91. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/abort-utils.ts +31 -0
  92. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/api.ts +8 -0
  93. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config/config-settings.ts +10 -4
  94. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/config.ts +1 -0
  95. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/footer-registry.ts +1 -1
  96. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/index.ts +6 -0
  97. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/model-selection.ts +134 -0
  98. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +9 -2
  99. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-ui.ts +109 -4
  100. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings-ui.ts +5 -1
  101. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/spinner-frames.ts +11 -0
  102. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/status-spinner.ts +68 -0
  103. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/package.json +3 -2
  104. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +7 -0
  105. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +56 -2
  106. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/evidence-badge.ts +40 -0
  107. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/index.ts +5 -0
  108. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +76 -3
  109. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-code-runtime/src/workspace/runtime.ts +37 -2
  110. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/package.json +6 -1
  111. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/abort-utils.ts +31 -0
  112. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/api.ts +8 -0
  113. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/config/config-settings.ts +10 -4
  114. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/config.ts +1 -0
  115. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/footer-registry.ts +1 -1
  116. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/index.ts +6 -0
  117. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/model-selection.ts +134 -0
  118. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-registry.ts +9 -2
  119. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings/settings-ui.ts +109 -4
  120. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/settings-ui.ts +5 -1
  121. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/spinner-frames.ts +11 -0
  122. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/status-spinner.ts +68 -0
  123. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/LICENSE +21 -0
  124. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/README.md +265 -0
  125. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.cjs +4661 -0
  126. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.cjs.map +7 -0
  127. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.js +4605 -0
  128. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.js.map +7 -0
  129. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.wasm +0 -0
  130. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.wasm.map +57 -0
  131. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/package.json +100 -0
  132. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.cjs +4063 -0
  133. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.cjs.map +7 -0
  134. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.d.cts +1025 -0
  135. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.d.cts.map +58 -0
  136. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.d.ts +1025 -0
  137. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.d.ts.map +58 -0
  138. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.js +4007 -0
  139. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.js.map +7 -0
  140. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.wasm +0 -0
  141. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.wasm.map +55 -0
  142. package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +6 -12
  143. package/node_modules/@mrclrchtr/supi-tree-sitter/src/api.ts +29 -0
  144. package/node_modules/@mrclrchtr/supi-tree-sitter/src/index.ts +28 -0
  145. package/node_modules/@mrclrchtr/supi-tree-sitter/src/language.ts +5 -0
  146. package/node_modules/@mrclrchtr/supi-tree-sitter/src/provider/tree-sitter-provider.ts +14 -2
  147. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/runtime-controller.ts +157 -0
  148. package/node_modules/@mrclrchtr/supi-tree-sitter/src/session/session.ts +8 -1
  149. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/call-sites.ts +86 -0
  150. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/callees.ts +35 -16
  151. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/structure.ts +1 -0
  152. package/node_modules/@mrclrchtr/supi-tree-sitter/src/types.ts +10 -0
  153. package/package.json +14 -9
  154. package/src/{model.ts → analysis/architecture/discovery.ts} +15 -72
  155. package/src/analysis/architecture/model.ts +76 -0
  156. package/src/analysis/brief/directory.ts +324 -0
  157. package/src/analysis/brief/enrich.ts +157 -0
  158. package/src/analysis/brief/file.ts +84 -0
  159. package/src/analysis/brief/inventory.ts +177 -0
  160. package/src/analysis/brief/main.ts +176 -0
  161. package/src/analysis/brief/models.ts +75 -0
  162. package/src/{brief.ts → analysis/brief/public-brief.ts} +21 -26
  163. package/src/analysis/brief/summarize.ts +208 -0
  164. package/src/analysis/brief/types.ts +27 -0
  165. package/src/{use-case/generate-brief.ts → analysis/brief/use-case.ts} +67 -144
  166. package/src/analysis/coverage/coverage-warnings.ts +224 -0
  167. package/src/analysis/evidence.ts +91 -0
  168. package/src/{semantic-action-helpers.ts → analysis/helpers.ts} +4 -4
  169. package/src/analysis/provider.ts +186 -0
  170. package/src/analysis/read-next.ts +126 -0
  171. package/src/analysis/readiness.ts +73 -0
  172. package/src/{refactor → analysis/refactor}/safety.ts +1 -1
  173. package/src/{use-case/support/semantic-references.ts → analysis/references/semantic-refs.ts} +58 -26
  174. package/src/analysis/search/pattern.ts +345 -0
  175. package/src/analysis/search/ripgrep.ts +473 -0
  176. package/src/{git-context.ts → analysis/signals/git.ts} +20 -7
  177. package/src/{prioritization-signals.ts → analysis/signals/project.ts} +33 -19
  178. package/src/analysis/target/anchored.ts +349 -0
  179. package/src/analysis/target/bridge.ts +152 -0
  180. package/src/analysis/target/file-resolution.ts +125 -0
  181. package/src/{targeting/resolve-file.ts → analysis/target/file.ts} +40 -20
  182. package/src/{planner → analysis/target}/planner.ts +30 -20
  183. package/src/{targeting → analysis/target}/query.ts +17 -3
  184. package/src/analysis/target/resolve-common.ts +115 -0
  185. package/src/analysis/target/service.ts +229 -0
  186. package/src/analysis/target/symbol.ts +196 -0
  187. package/src/{targeting → analysis/target}/types.ts +17 -1
  188. package/src/analysis/tests/likely-tests.ts +174 -0
  189. package/src/analysis/tests/test-discovery.ts +540 -0
  190. package/src/analysis/tests/vitest.ts +87 -0
  191. package/src/api.ts +34 -41
  192. package/src/app/app.ts +125 -0
  193. package/src/app/manager.ts +65 -0
  194. package/src/extension.ts +132 -1
  195. package/src/index.ts +1 -57
  196. package/src/session/refactor-plans.ts +82 -0
  197. package/src/session/session.ts +300 -0
  198. package/src/session/target-store.ts +293 -0
  199. package/src/substrate/lsp/diagnostic-injection.ts +218 -0
  200. package/src/substrate/lsp/lifecycle.ts +66 -0
  201. package/src/substrate/lsp/overrides.ts +132 -0
  202. package/src/substrate/lsp/recovery.ts +55 -0
  203. package/src/substrate/lsp/settings.ts +286 -0
  204. package/src/substrate/lsp/state.ts +46 -0
  205. package/src/substrate/lsp/utils.ts +17 -0
  206. package/src/substrate/tree-sitter/lifecycle.ts +52 -0
  207. package/src/tool/find/execute.ts +118 -0
  208. package/src/{presentation/markdown/pattern.ts → tool/find/markdown.ts} +102 -53
  209. package/src/{use-case/generate-pattern.ts → tool/find/orchestrate.ts} +67 -33
  210. package/src/tool/find/semantic-search.ts +114 -0
  211. package/src/tool/find/tui.ts +39 -0
  212. package/src/tool/graph/callees.ts +87 -0
  213. package/src/tool/graph/calls-md.ts +54 -0
  214. package/src/tool/graph/collect-relation.ts +371 -0
  215. package/src/tool/graph/execute.ts +95 -0
  216. package/src/tool/graph/implementations-md.ts +79 -0
  217. package/src/tool/graph/implementations.ts +76 -0
  218. package/src/tool/graph/markdown-base.ts +243 -0
  219. package/src/tool/graph/orchestrate.ts +285 -0
  220. package/src/tool/graph/references-md.ts +34 -0
  221. package/src/tool/graph/references.ts +81 -0
  222. package/src/tool/graph/tui.ts +120 -0
  223. package/src/tool/graph/types.ts +97 -0
  224. package/src/tool/guidance.ts +96 -49
  225. package/src/tool/health/execute.ts +76 -0
  226. package/src/tool/health/markdown.ts +280 -0
  227. package/src/tool/health/orchestrate.ts +159 -0
  228. package/src/tool/health/sections/diagnostics.ts +182 -0
  229. package/src/tool/health/sections/recovery.ts +89 -0
  230. package/src/tool/health/sections/signals.ts +89 -0
  231. package/src/tool/health/tui.ts +137 -0
  232. package/src/tool/impact/analysis.ts +247 -0
  233. package/src/tool/impact/change-set-impact.ts +151 -0
  234. package/src/tool/impact/execute.ts +98 -0
  235. package/src/tool/impact/file-level-impact.ts +81 -0
  236. package/src/tool/impact/markdown.ts +283 -0
  237. package/src/tool/impact/orchestrate.ts +97 -0
  238. package/src/tool/impact/result.ts +21 -0
  239. package/src/tool/impact/single-impact.ts +89 -0
  240. package/src/tool/impact/tui.ts +39 -0
  241. package/src/tool/impact/types.ts +34 -0
  242. package/src/tool/infra/cross-field.ts +335 -0
  243. package/src/tool/infra/error-results.ts +199 -0
  244. package/src/tool/infra/pipeline.ts +311 -0
  245. package/src/tool/infra/progress.ts +21 -0
  246. package/src/tool/infra/readiness-message.ts +5 -0
  247. package/src/tool/infra/truncate.ts +49 -0
  248. package/src/tool/inspect/execute.ts +76 -0
  249. package/src/tool/inspect/markdown.ts +169 -0
  250. package/src/tool/inspect/orchestrate.ts +156 -0
  251. package/src/tool/inspect/tui.ts +36 -0
  252. package/src/tool/orientation/deps.ts +63 -0
  253. package/src/tool/orientation/execute.ts +50 -0
  254. package/src/tool/orientation/markdown.ts +35 -0
  255. package/src/tool/orientation/mode.ts +88 -0
  256. package/src/tool/orientation/orchestrate.ts +478 -0
  257. package/src/tool/orientation/precise-target.ts +257 -0
  258. package/src/tool/orientation/tui.ts +131 -0
  259. package/src/{refactor/apply-workspace-edit.ts → tool/refactor-apply/apply.ts} +39 -16
  260. package/src/tool/refactor-apply/execute.ts +20 -0
  261. package/src/tool/refactor-apply/markdown.ts +118 -0
  262. package/src/tool/refactor-apply/orchestrate.ts +89 -0
  263. package/src/tool/refactor-apply/tui.ts +51 -0
  264. package/src/tool/refactor-plan/execute.ts +73 -0
  265. package/src/tool/refactor-plan/markdown.ts +118 -0
  266. package/src/tool/refactor-plan/orchestrate.ts +363 -0
  267. package/src/tool/refactor-plan/tui.ts +42 -0
  268. package/src/tool/register.ts +123 -0
  269. package/src/tool/resolve/execute.ts +82 -0
  270. package/src/tool/resolve/markdown.ts +150 -0
  271. package/src/tool/resolve/orchestrate.ts +134 -0
  272. package/src/tool/resolve/tui.ts +40 -0
  273. package/src/tool/schemas.ts +337 -0
  274. package/src/tool/specs.ts +257 -0
  275. package/src/types/details.ts +188 -0
  276. package/src/types/execution.ts +60 -0
  277. package/src/types/index.ts +28 -0
  278. package/src/{intent/types.ts → types/tool-names.ts} +15 -14
  279. package/src/ui/footer.ts +52 -0
  280. package/src/ui/markdown/brief.ts +218 -0
  281. package/src/ui/markdown/gather.ts +177 -0
  282. package/src/{use-case/build-overview.ts → ui/markdown/overview-data.ts} +2 -2
  283. package/src/{presentation → ui}/markdown/overview.ts +2 -2
  284. package/src/ui/markdown/types.ts +80 -0
  285. package/{node_modules/@mrclrchtr/supi-lsp/src/ui/renderer.ts → src/ui/message-renderer.ts} +11 -10
  286. package/src/ui/status-command.ts +260 -0
  287. package/src/ui/status-overlay.ts +500 -0
  288. package/src/ui/tui/common.ts +220 -0
  289. package/src/ui/tui/index.ts +37 -0
  290. package/node_modules/@mrclrchtr/supi-lsp/src/extension.ts +0 -1
  291. package/node_modules/@mrclrchtr/supi-lsp/src/format.ts +0 -373
  292. package/node_modules/@mrclrchtr/supi-lsp/src/handlers/diagnostic-injection.ts +0 -182
  293. package/node_modules/@mrclrchtr/supi-lsp/src/handlers/session-lifecycle.ts +0 -149
  294. package/node_modules/@mrclrchtr/supi-lsp/src/handlers/status-command.ts +0 -38
  295. package/node_modules/@mrclrchtr/supi-lsp/src/handlers/workspace-recovery.ts +0 -92
  296. package/node_modules/@mrclrchtr/supi-lsp/src/lsp.ts +0 -37
  297. package/node_modules/@mrclrchtr/supi-lsp/src/session/lsp-state.ts +0 -93
  298. package/node_modules/@mrclrchtr/supi-lsp/src/session/settings-registration.ts +0 -296
  299. package/node_modules/@mrclrchtr/supi-lsp/src/session/tree-persist.ts +0 -75
  300. package/node_modules/@mrclrchtr/supi-lsp/src/tool/guidance.ts +0 -69
  301. package/node_modules/@mrclrchtr/supi-lsp/src/tool/names.ts +0 -27
  302. package/node_modules/@mrclrchtr/supi-lsp/src/tool/overrides.ts +0 -204
  303. package/node_modules/@mrclrchtr/supi-lsp/src/tool/register-tools.ts +0 -69
  304. package/node_modules/@mrclrchtr/supi-lsp/src/tool/service-actions.ts +0 -399
  305. package/node_modules/@mrclrchtr/supi-lsp/src/tool/tool-specs.ts +0 -248
  306. package/node_modules/@mrclrchtr/supi-lsp/src/ui/ui.ts +0 -360
  307. package/node_modules/@mrclrchtr/supi-lsp/src/workspace-change.ts +0 -40
  308. package/node_modules/@mrclrchtr/supi-tree-sitter/src/extension.ts +0 -1
  309. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/formatting.ts +0 -104
  310. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/guidance.ts +0 -35
  311. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/handlers.ts +0 -196
  312. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/register-tools.ts +0 -107
  313. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tool/tool-specs.ts +0 -117
  314. package/node_modules/@mrclrchtr/supi-tree-sitter/src/tree-sitter.ts +0 -47
  315. package/src/brief-focused.ts +0 -563
  316. package/src/code-intelligence.ts +0 -70
  317. package/src/pattern-structured.ts +0 -194
  318. package/src/presentation/markdown/affected.ts +0 -170
  319. package/src/presentation/markdown/brief.ts +0 -174
  320. package/src/presentation/markdown/map.ts +0 -54
  321. package/src/presentation/markdown/refactor.ts +0 -27
  322. package/src/presentation/markdown/relations.ts +0 -121
  323. package/src/resolve-target.ts +0 -130
  324. package/src/search-helpers.ts +0 -303
  325. package/src/substrates/types.ts +0 -30
  326. package/src/target-resolution.ts +0 -122
  327. package/src/targeting/resolve-anchored.ts +0 -80
  328. package/src/targeting/resolve-symbol.ts +0 -110
  329. package/src/tool/execute-affected.ts +0 -71
  330. package/src/tool/execute-brief.ts +0 -59
  331. package/src/tool/execute-map.ts +0 -35
  332. package/src/tool/execute-pattern.ts +0 -29
  333. package/src/tool/execute-refactor.ts +0 -101
  334. package/src/tool/execute-relations.ts +0 -79
  335. package/src/tool/register-tools.ts +0 -32
  336. package/src/tool/tool-specs.ts +0 -190
  337. package/src/tool/validation.ts +0 -43
  338. package/src/types.ts +0 -169
  339. package/src/use-case/generate-affected.ts +0 -297
  340. package/src/use-case/generate-map.ts +0 -176
  341. package/src/use-case/generate-relations.ts +0 -438
  342. package/src/use-case/types.ts +0 -43
  343. package/src/workspace/request-context.ts +0 -139
  344. /package/src/{query-params.ts → tool/params.ts} +0 -0
@@ -0,0 +1,473 @@
1
+ // biome-ignore-all lint/style/noExcessiveLinesPerFile: ripgrep abort/process handling, JSON parsing, and path/scope helpers are cohesive search infrastructure
2
+ // Shared search helpers for code-intelligence search and routing helpers.
3
+
4
+ import { type ChildProcess, spawn } from "node:child_process";
5
+ import { existsSync } from "node:fs";
6
+ import * as path from "node:path";
7
+ import { resolveToolPath, uriToFile as uriToFileShared } from "@mrclrchtr/supi-core/path";
8
+
9
+ const LOW_SIGNAL_DIRS = new Set([
10
+ "node_modules",
11
+ ".git",
12
+ ".pnpm",
13
+ "dist",
14
+ "build",
15
+ "out",
16
+ ".next",
17
+ ".nuxt",
18
+ "coverage",
19
+ ".turbo",
20
+ ".cache",
21
+ "__pycache__",
22
+ ".tsbuildinfo",
23
+ ]);
24
+
25
+ /** Check if a file path contains an obviously low-signal directory segment. */
26
+ export function isLowSignalPath(filePath: string): boolean {
27
+ const segments = filePath.split(path.sep);
28
+ return segments.some((s) => LOW_SIGNAL_DIRS.has(s));
29
+ }
30
+
31
+ /** Convert a file:// URI to a file path, matching the shared SuPi normalization. */
32
+ export const uriToFile = uriToFileShared;
33
+
34
+ /** Check whether a resolved file path is inside the current project (within cwd, not under node_modules or .pnpm). */
35
+ export function isInProjectPath(filePath: string, cwd: string): boolean {
36
+ const relativePath = path.relative(cwd, path.resolve(cwd, filePath));
37
+ if (relativePath.startsWith(`..${path.sep}`) || relativePath === "..") return false;
38
+ const normalized = relativePath.replaceAll("\\", "/");
39
+ return !(
40
+ normalized.includes("/node_modules/") ||
41
+ normalized.startsWith("node_modules/") ||
42
+ normalized.includes("/.pnpm/") ||
43
+ normalized.startsWith(".pnpm/")
44
+ );
45
+ }
46
+
47
+ /** Result of resolving a user-provided `scope` value to an absolute path. */
48
+ export type ScopeResolution = { kind: "ok"; path: string } | { kind: "error"; reason: string };
49
+
50
+ /**
51
+ * Resolve a `scope` value to an absolute path using pi scope semantics:
52
+ * - strip leading `@`
53
+ * - resolve relative paths from `cwd`
54
+ * - require the resolved path to exist
55
+ */
56
+ export function resolveScope(scope: string | undefined, cwd: string): ScopeResolution {
57
+ if (!scope) return { kind: "ok", path: cwd };
58
+ if (/[,;\s]/.test(scope)) {
59
+ return {
60
+ kind: "error",
61
+ reason: `Scope accepts a single directory or file path, not multiple: \`${scope}\``,
62
+ };
63
+ }
64
+ const resolved = normalizePath(scope, cwd);
65
+ if (!existsSync(resolved)) {
66
+ return { kind: "error", reason: `Scope path not found: \`${scope}\`` };
67
+ }
68
+ return { kind: "ok", path: resolved };
69
+ }
70
+
71
+ /** Escape regex special characters. */
72
+ export function escapeRegex(s: string): string {
73
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
74
+ }
75
+
76
+ /** Normalize a file/path value: strip leading @, resolve relative to cwd. */
77
+ export function normalizePath(input: string, cwd: string): string {
78
+ return resolveToolPath(cwd, input);
79
+ }
80
+
81
+ /** Render a file path relative to cwd when it is inside the workspace. */
82
+ export function toDisplayPath(cwd: string, filePath: string): string {
83
+ if (!path.isAbsolute(filePath)) {
84
+ return filePath.replaceAll("\\", "/");
85
+ }
86
+
87
+ const relativePath = path.relative(cwd, filePath);
88
+ if (!relativePath || relativePath === ".") {
89
+ return filePath;
90
+ }
91
+ if (relativePath.startsWith(`..${path.sep}`) || relativePath === "..") {
92
+ return filePath;
93
+ }
94
+
95
+ return relativePath.replaceAll("\\", "/");
96
+ }
97
+
98
+ export interface RgMatch {
99
+ file: string;
100
+ line: number;
101
+ text: string;
102
+ /** Context lines surrounding this match (from -C flag). */
103
+ context?: Array<{ line: number; text: string }>;
104
+ }
105
+
106
+ /** Result of a ripgrep invocation for callers that need both matches and execution errors. */
107
+ export interface RipgrepRunResult {
108
+ /** Parsed ripgrep matches, if any. */
109
+ matches: RgMatch[];
110
+ /** Non-no-match ripgrep execution error text, such as invalid regex syntax. */
111
+ error?: string;
112
+ }
113
+
114
+ /** Options for {@link runRipgrep} / {@link runRipgrepDetailed}. */
115
+ export interface RipgrepOptions {
116
+ maxMatches?: number;
117
+ contextLines?: number;
118
+ literal?: boolean;
119
+ filterLowSignal?: boolean;
120
+ /**
121
+ * Abort signal from the agent runtime. When aborted, the ripgrep child is
122
+ * killed and the call rejects with {@link RipgrepAbortedError} so the
123
+ * executor (and pi) can treat the tool call as cancelled rather than
124
+ * silently completing with partial matches.
125
+ */
126
+ signal?: AbortSignal;
127
+ }
128
+
129
+ /** Hard upper bound on a single ripgrep invocation, matching the prior `execFileSync` timeout. */
130
+ const RIPGREP_TIMEOUT_MS = 10_000;
131
+
132
+ /**
133
+ * Thrown by {@link runRipgrepDetailed} when the supplied `AbortSignal` fires.
134
+ * Propagates out of executors so pi cancels the tool call instead of returning
135
+ * partial results.
136
+ */
137
+ export class RipgrepAbortedError extends Error {
138
+ constructor(signal?: AbortSignal) {
139
+ const reason = signal?.reason;
140
+ super(reason instanceof Error ? reason.message : "ripgrep search was aborted");
141
+ this.name = "RipgrepAbortedError";
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Run ripgrep with JSON output and parse matches, filtering low-signal paths.
147
+ *
148
+ * Async and abort-aware: when `opts.signal` aborts, the ripgrep child is killed
149
+ * and the returned promise rejects with {@link RipgrepAbortedError}. Any
150
+ * non-abort ripgrep execution failure is still treated like an empty match set
151
+ * (or surfaces an error via {@link runRipgrepDetailed}).
152
+ */
153
+ export async function runRipgrep(
154
+ pattern: string,
155
+ scopePath: string,
156
+ cwd: string,
157
+ opts?: RipgrepOptions,
158
+ ): Promise<RgMatch[]> {
159
+ return (await runRipgrepDetailed(pattern, scopePath, cwd, opts)).matches;
160
+ }
161
+
162
+ /**
163
+ * Run ripgrep and preserve non-no-match execution errors for callers that need
164
+ * to distinguish invalid regex syntax from a genuine empty search result.
165
+ * Abort-aware: rejects with {@link RipgrepAbortedError} when `opts.signal` fires.
166
+ */
167
+ export async function runRipgrepDetailed(
168
+ pattern: string,
169
+ scopePath: string,
170
+ cwd: string,
171
+ opts?: RipgrepOptions,
172
+ ): Promise<RipgrepRunResult> {
173
+ const filter = opts?.filterLowSignal ?? true;
174
+ let proc: RgProcessResult;
175
+ try {
176
+ proc = await runRgProcess(
177
+ buildRipgrepArgs(pattern, scopePath, opts),
178
+ cwd,
179
+ RIPGREP_TIMEOUT_MS,
180
+ opts?.signal,
181
+ );
182
+ } catch (err: unknown) {
183
+ // Abort propagates so pi cancels the tool call. Any other unexpected spawn
184
+ // failure is treated like an empty match set, preserving prior behavior.
185
+ if (err instanceof RipgrepAbortedError) throw err;
186
+ return { matches: [] };
187
+ }
188
+
189
+ switch (proc.kind) {
190
+ case "missing":
191
+ return {
192
+ matches: [],
193
+ error:
194
+ "ripgrep (rg) is not available. Install it (e.g., `apt install ripgrep` or `brew install ripgrep`).",
195
+ };
196
+ case "ok":
197
+ case "nomatch":
198
+ return { matches: parseRgJson(proc.stdout, filter) };
199
+ case "timeout":
200
+ // Timeout: yield any partial stdout matches with no error surfaced — an
201
+ // improvement over the prior execFileSync path, which discarded partial
202
+ // output on timeout (the timeout error lacked a `status`, so the old
203
+ // handleRipgrepError returned an empty match set).
204
+ return { matches: proc.stdout ? parseRgJson(proc.stdout, filter) : [] };
205
+ case "error":
206
+ return {
207
+ matches: proc.stdout ? parseRgJson(proc.stdout, filter) : [],
208
+ ...(proc.stderr.trim() ? { error: proc.stderr.trim() } : {}),
209
+ };
210
+ }
211
+ }
212
+
213
+ function buildRipgrepArgs(
214
+ pattern: string,
215
+ scopePath: string,
216
+ opts?: { maxMatches?: number; contextLines?: number; literal?: boolean },
217
+ ): string[] {
218
+ const args = ["--json", "-m", String(opts?.maxMatches ?? 30)];
219
+ if ((opts?.contextLines ?? 0) > 0) {
220
+ args.push("-C", String(opts?.contextLines ?? 0));
221
+ }
222
+ if (opts?.literal) {
223
+ args.push("-F");
224
+ }
225
+ args.push("-e", pattern, scopePath);
226
+ return args;
227
+ }
228
+
229
+ /** Discriminated result of a single ripgrep process run (see {@link runRgProcess}). */
230
+ type RgProcessResult =
231
+ | { kind: "ok"; stdout: string; stderr: string; status: number }
232
+ | { kind: "nomatch"; stdout: string; stderr: string; status: 1 }
233
+ | { kind: "error"; stdout: string; stderr: string; status: number }
234
+ | { kind: "timeout"; stdout: string; stderr: string }
235
+ | { kind: "missing" };
236
+
237
+ /**
238
+ * Spawn ripgrep, collect stdout/stderr, and resolve a discriminated result.
239
+ * Rejects with {@link RipgrepAbortedError} when `signal` aborts (the child is
240
+ * killed with SIGKILL). Maps exit codes: 0 → ok, 1 → nomatch, 2+ → error;
241
+ * ENOENT → missing (rg not installed); timeout → timeout.
242
+ */
243
+ function runRgProcess(
244
+ args: string[],
245
+ cwd: string,
246
+ timeoutMs: number,
247
+ signal?: AbortSignal,
248
+ ): Promise<RgProcessResult> {
249
+ return new Promise<RgProcessResult>((resolve, reject) => {
250
+ let child: ChildProcess;
251
+ try {
252
+ child = spawn("rg", args, { cwd, stdio: ["pipe", "pipe", "pipe"] });
253
+ } catch (err: unknown) {
254
+ if (isCodeError(err, "ENOENT")) {
255
+ resolve({ kind: "missing" });
256
+ return;
257
+ }
258
+ reject(err);
259
+ return;
260
+ }
261
+
262
+ let stdout = "";
263
+ let stderr = "";
264
+ let timedOut = false;
265
+ let settled = false;
266
+ let timer: ReturnType<typeof setTimeout> | undefined;
267
+ let abortListener: (() => void) | null = null;
268
+
269
+ const cleanup = (): void => {
270
+ if (timer) clearTimeout(timer);
271
+ if (abortListener && signal) signal.removeEventListener("abort", abortListener);
272
+ };
273
+ const settle = (r: RgProcessResult): void => {
274
+ if (settled) return;
275
+ settled = true;
276
+ cleanup();
277
+ resolve(r);
278
+ };
279
+ const failAbort = (): void => {
280
+ if (settled) return;
281
+ settled = true;
282
+ cleanup();
283
+ try {
284
+ child.kill("SIGKILL");
285
+ } catch {
286
+ // Child may already have exited; ignore.
287
+ }
288
+ reject(new RipgrepAbortedError(signal));
289
+ };
290
+
291
+ // Fast path: signal already aborted before any work is scheduled.
292
+ if (signal?.aborted) {
293
+ failAbort();
294
+ return;
295
+ }
296
+
297
+ child.stdout?.setEncoding("utf-8");
298
+ child.stderr?.setEncoding("utf-8");
299
+ child.stdout?.on("data", (d: string) => {
300
+ stdout += d;
301
+ });
302
+ child.stderr?.on("data", (d: string) => {
303
+ stderr += d;
304
+ });
305
+
306
+ timer = setTimeout(() => {
307
+ timedOut = true;
308
+ try {
309
+ child.kill("SIGTERM");
310
+ } catch {
311
+ // Ignore; the close handler will still fire.
312
+ }
313
+ }, timeoutMs);
314
+
315
+ if (signal) {
316
+ abortListener = () => failAbort();
317
+ signal.addEventListener("abort", abortListener);
318
+ }
319
+
320
+ child.on("error", (err: NodeJS.ErrnoException) => {
321
+ if (settled) return;
322
+ if (isCodeError(err, "ENOENT")) {
323
+ settle({ kind: "missing" });
324
+ return;
325
+ }
326
+ settle({ kind: "error", stdout, stderr, status: -1 });
327
+ });
328
+
329
+ child.on("close", (status: number | null) => {
330
+ if (settled) return;
331
+ if (timedOut) {
332
+ settle({ kind: "timeout", stdout, stderr });
333
+ return;
334
+ }
335
+ if (status === 0) settle({ kind: "ok", stdout, stderr, status });
336
+ else if (status === 1) settle({ kind: "nomatch", stdout, stderr, status });
337
+ else settle({ kind: "error", stdout, stderr, status: status ?? -1 });
338
+ });
339
+ });
340
+ }
341
+
342
+ function isCodeError(err: unknown, code: string): boolean {
343
+ return (
344
+ typeof err === "object" &&
345
+ err !== null &&
346
+ "code" in err &&
347
+ (err as { code: unknown }).code === code
348
+ );
349
+ }
350
+
351
+ interface RawRgEvent {
352
+ type: string;
353
+ data?: {
354
+ path?: { text: string };
355
+ line_number?: number;
356
+ lines?: { text: string };
357
+ };
358
+ }
359
+
360
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: JSON ripgrep output parsing with context line collection
361
+ function parseRgJson(output: string, filterLowSignal: boolean): RgMatch[] {
362
+ const matches: RgMatch[] = [];
363
+ // Pending context lines that precede the next match
364
+ let pendingContext: Array<{ line: number; text: string }> = [];
365
+
366
+ for (const line of output.split("\n")) {
367
+ if (!line.trim()) continue;
368
+ let parsed: RawRgEvent;
369
+ try {
370
+ parsed = JSON.parse(line);
371
+ } catch {
372
+ continue;
373
+ }
374
+
375
+ if (parsed.type === "context" && parsed.data) {
376
+ const lineNum = parsed.data.line_number;
377
+ const text = (parsed.data.lines?.text ?? "").trim();
378
+ if (lineNum) pendingContext.push({ line: lineNum, text });
379
+ continue;
380
+ }
381
+
382
+ if (parsed.type === "match" && parsed.data) {
383
+ const filePath = parsed.data.path?.text;
384
+ const lineNum = parsed.data.line_number;
385
+ const text = (parsed.data.lines?.text ?? "").trim();
386
+ if (filePath && lineNum) {
387
+ // Split pendingContext: lines before this match are "before" context,
388
+ // lines from before this match line that trail the previous match stay with it.
389
+ const beforeCtx = pendingContext.filter((c) => c.line < lineNum);
390
+ const trailingCtx = pendingContext.filter((c) => c.line >= lineNum);
391
+
392
+ // Attach trailing context from previous match to the last accepted match
393
+ if (beforeCtx.length > 0 && matches.length > 0) {
394
+ const prev = matches[matches.length - 1];
395
+ const prevTrailing = beforeCtx.filter((c) => c.line > prev.line);
396
+ if (prevTrailing.length > 0) {
397
+ prev.context = [...(prev.context ?? []), ...prevTrailing];
398
+ }
399
+ }
400
+
401
+ if (filterLowSignal && isLowSignalPath(filePath)) {
402
+ pendingContext = [];
403
+ continue;
404
+ }
405
+
406
+ const match: RgMatch = { file: filePath, line: lineNum, text };
407
+ // Leading context: lines just before this match
408
+ const leadingCtx =
409
+ matches.length > 0
410
+ ? beforeCtx.filter(
411
+ (c) => c.line <= lineNum && c.line > (matches[matches.length - 1]?.line ?? 0),
412
+ )
413
+ : beforeCtx;
414
+ if (leadingCtx.length > 0) {
415
+ match.context = leadingCtx;
416
+ }
417
+ // Also include any pending context at/after this match's line (trailing from rg ordering)
418
+ pendingContext = trailingCtx;
419
+ matches.push(match);
420
+ } else {
421
+ pendingContext = [];
422
+ }
423
+ }
424
+ }
425
+
426
+ // Attach any trailing context lines to the last match
427
+ if (pendingContext.length > 0 && matches.length > 0) {
428
+ const last = matches[matches.length - 1];
429
+ last.context = [...(last.context ?? []), ...pendingContext];
430
+ }
431
+
432
+ return matches;
433
+ }
434
+
435
+ /**
436
+ * Minimal interface for a reference-like object with a URI and range start.
437
+ * Used by {@link filterOutDeclaration} to avoid coupling to a specific LspRef type.
438
+ */
439
+ export interface HasLspPosition {
440
+ uri: string;
441
+ range: { start: { line: number; character: number } };
442
+ }
443
+
444
+ /**
445
+ * Filter out the declaration/definition location from LSP references.
446
+ * LSP's `textDocument/references` includes the declaration by default;
447
+ * for callers/affected analysis, the declaration is not a call site or affected reference.
448
+ *
449
+ * Uses {@link uriToFile} for robust URI-to-path conversion.
450
+ */
451
+ export function filterOutDeclaration<T extends HasLspPosition>(
452
+ refs: T[],
453
+ targetFile: string,
454
+ targetPos: { line: number; character: number },
455
+ ): T[] {
456
+ return refs.filter((ref) => {
457
+ const filePath = uriToFile(ref.uri);
458
+ if (filePath !== targetFile) return true;
459
+ const start = ref.range.start;
460
+ return start.line !== targetPos.line || start.character !== targetPos.character;
461
+ });
462
+ }
463
+
464
+ /** Group matches by file. */
465
+ export function groupByFile(matches: RgMatch[]): Map<string, RgMatch[]> {
466
+ const byFile = new Map<string, RgMatch[]>();
467
+ for (const m of matches) {
468
+ const group = byFile.get(m.file) ?? [];
469
+ group.push(m);
470
+ byFile.set(m.file, group);
471
+ }
472
+ return byFile;
473
+ }
@@ -1,4 +1,5 @@
1
1
  import { execFileSync } from "node:child_process";
2
+ import { createEvidenceList, renderEvidenceListDisclosure } from "../evidence.ts";
2
3
 
3
4
  function scrubGitEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
4
5
  const next = { ...env };
@@ -32,10 +33,7 @@ export function gatherGitContext(cwd: string): GitContext | null {
32
33
 
33
34
  const status = execGit(cwd, ["status", "--porcelain"]).trim();
34
35
 
35
- const dirtyFiles = status
36
- .split("\n")
37
- .filter(Boolean)
38
- .map((line) => line.slice(3).trim());
36
+ const dirtyFiles = status.split("\n").filter(Boolean).map(parsePorcelainPath);
39
37
 
40
38
  let lastCommitMessage: string | null = null;
41
39
  try {
@@ -59,11 +57,17 @@ export function formatGitContext(ctx: GitContext): string {
59
57
  lines.push(
60
58
  `Uncommitted: ${ctx.dirtyFiles.length} file${ctx.dirtyFiles.length !== 1 ? "s" : ""}`,
61
59
  );
62
- for (const f of ctx.dirtyFiles.slice(0, 5)) {
60
+ const evidence = createEvidenceList({
61
+ key: "health.dirtyFiles",
62
+ items: ctx.dirtyFiles,
63
+ maxResults: 5,
64
+ });
65
+ for (const f of evidence.items) {
63
66
  lines.push(`- \`${f}\``);
64
67
  }
65
- if (ctx.dirtyFiles.length > 5) {
66
- lines.push(`- _+${ctx.dirtyFiles.length - 5} more_`);
68
+ const disclosure = renderEvidenceListDisclosure(evidence);
69
+ if (disclosure) {
70
+ lines.push(disclosure);
67
71
  }
68
72
  } else {
69
73
  lines.push("Working tree clean.");
@@ -74,3 +78,12 @@ export function formatGitContext(ctx: GitContext): string {
74
78
  lines.push("");
75
79
  return lines.join("\n");
76
80
  }
81
+
82
+ function parsePorcelainPath(line: string): string {
83
+ const rawPath = line[2] === " " ? line.slice(3) : line.slice(2);
84
+ const renameSeparator = " -> ";
85
+ const renamedPath = rawPath.includes(renameSeparator)
86
+ ? (rawPath.split(renameSeparator).at(-1) ?? rawPath)
87
+ : rawPath;
88
+ return renamedPath.trim();
89
+ }
@@ -1,6 +1,6 @@
1
1
  import * as path from "node:path";
2
2
  import { readJsonFile } from "@mrclrchtr/supi-core/config";
3
- import { getSessionLspService } from "@mrclrchtr/supi-lsp/api";
3
+ import type { SessionLspServiceState } from "@mrclrchtr/supi-lsp/api";
4
4
 
5
5
  export interface PrioritySignalsSummary {
6
6
  diagnosticsCount: number;
@@ -9,18 +9,24 @@ export interface PrioritySignalsSummary {
9
9
  warnings: string[];
10
10
  }
11
11
 
12
- interface LoadedSignals {
12
+ export interface LoadedSignals {
13
13
  diagnostics: Array<{ file: string; total: number; errors: number; warnings: number }>;
14
14
  coverageByFile: Map<string, number>;
15
15
  unusedFiles: Set<string>;
16
16
  unusedExports: Array<{ file: string; name: string }>;
17
17
  }
18
18
 
19
+ export interface LoadPrioritizationSignalsOptions {
20
+ coveragePath?: string;
21
+ unusedPath?: string;
22
+ }
23
+
19
24
  export function summarizePrioritySignalsForFiles(
20
25
  cwd: string,
21
26
  files: Iterable<string>,
27
+ lspService: SessionLspServiceState,
22
28
  ): PrioritySignalsSummary | null {
23
- const loaded = loadPrioritizationSignals(cwd);
29
+ const loaded = loadPrioritizationSignals(cwd, lspService);
24
30
  const relevantFiles = new Set([...files].map((file) => path.resolve(cwd, file)));
25
31
  if (relevantFiles.size === 0) return null;
26
32
 
@@ -69,12 +75,16 @@ export function summarizePrioritySignalsForFiles(
69
75
  : null;
70
76
  }
71
77
 
72
- export function loadPrioritizationSignals(cwd: string): LoadedSignals {
78
+ export function loadPrioritizationSignals(
79
+ cwd: string,
80
+ lspService: SessionLspServiceState,
81
+ options: LoadPrioritizationSignalsOptions = {},
82
+ ): LoadedSignals {
73
83
  return {
74
- diagnostics: loadDiagnostics(cwd),
75
- coverageByFile: loadCoverageSummary(cwd),
76
- unusedFiles: loadUnusedFiles(cwd),
77
- unusedExports: loadUnusedExports(cwd),
84
+ diagnostics: loadDiagnostics(cwd, lspService),
85
+ coverageByFile: loadCoverageSummary(cwd, options.coveragePath),
86
+ unusedFiles: loadUnusedFiles(cwd, options.unusedPath),
87
+ unusedExports: loadUnusedExports(cwd, options.unusedPath),
78
88
  };
79
89
  }
80
90
 
@@ -92,11 +102,12 @@ export function appendPrioritySignalsSection(
92
102
 
93
103
  function loadDiagnostics(
94
104
  cwd: string,
105
+ lspService: SessionLspServiceState,
95
106
  ): Array<{ file: string; total: number; errors: number; warnings: number }> {
96
- const lspState = getSessionLspService(cwd);
97
- if (lspState.kind !== "ready") return [];
107
+ if (lspService.kind !== "ready") return [];
108
+ if (typeof lspService.service.getOutstandingDiagnosticSummary !== "function") return [];
98
109
 
99
- return lspState.service.getOutstandingDiagnosticSummary(2).map((entry) => ({
110
+ return lspService.service.getOutstandingDiagnosticSummary(2).map((entry) => ({
100
111
  file: path.resolve(cwd, entry.file),
101
112
  total: entry.total,
102
113
  errors: entry.errors,
@@ -104,8 +115,8 @@ function loadDiagnostics(
104
115
  }));
105
116
  }
106
117
 
107
- function loadCoverageSummary(cwd: string): Map<string, number> {
108
- const coveragePath = path.join(cwd, "coverage", "coverage-summary.json");
118
+ function loadCoverageSummary(cwd: string, coveragePathInput?: string): Map<string, number> {
119
+ const coveragePath = path.resolve(cwd, coveragePathInput ?? "coverage/coverage-summary.json");
109
120
  const parsed = readJsonFile(coveragePath);
110
121
  if (!parsed) return new Map();
111
122
 
@@ -120,8 +131,8 @@ function loadCoverageSummary(cwd: string): Map<string, number> {
120
131
  return map;
121
132
  }
122
133
 
123
- function loadUnusedFiles(cwd: string): Set<string> {
124
- const parsed = loadKnipJson(cwd);
134
+ function loadUnusedFiles(cwd: string, unusedPath?: string): Set<string> {
135
+ const parsed = loadKnipJson(cwd, unusedPath);
125
136
  const values = Array.isArray(parsed?.files) ? parsed.files : [];
126
137
  const files = values
127
138
  .map((value) => toPathString(value))
@@ -130,8 +141,11 @@ function loadUnusedFiles(cwd: string): Set<string> {
130
141
  return new Set(files);
131
142
  }
132
143
 
133
- function loadUnusedExports(cwd: string): Array<{ file: string; name: string }> {
134
- const parsed = loadKnipJson(cwd);
144
+ function loadUnusedExports(
145
+ cwd: string,
146
+ unusedPath?: string,
147
+ ): Array<{ file: string; name: string }> {
148
+ const parsed = loadKnipJson(cwd, unusedPath);
135
149
  const values = Array.isArray(parsed?.exports) ? parsed.exports : [];
136
150
  const exports: Array<{ file: string; name: string }> = [];
137
151
 
@@ -152,8 +166,8 @@ function loadUnusedExports(cwd: string): Array<{ file: string; name: string }> {
152
166
  return exports;
153
167
  }
154
168
 
155
- function loadKnipJson(cwd: string): Record<string, unknown> | null {
156
- return readJsonFile(path.join(cwd, "knip.json"));
169
+ function loadKnipJson(cwd: string, unusedPath?: string): Record<string, unknown> | null {
170
+ return readJsonFile(path.resolve(cwd, unusedPath ?? "knip.json"));
157
171
  }
158
172
 
159
173
  function getPct(value: object, key: string): number | null {