@herbertgao/pi-extensions 2026.9.6 → 2026.9.8

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 (304) hide show
  1. package/README.md +3 -8
  2. package/THIRD_PARTY_NOTICES.md +0 -4
  3. package/node_modules/@narumitw/pi-btw/README.md +2 -0
  4. package/node_modules/@narumitw/pi-btw/dist/index.ts +284 -365
  5. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +3 -3
  6. package/node_modules/@narumitw/pi-btw/package.json +52 -53
  7. package/node_modules/@narumitw/pi-btw/src/bring-to-main.ts +494 -547
  8. package/node_modules/@narumitw/pi-btw/src/btw.ts +814 -856
  9. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +673 -674
  10. package/node_modules/@narumitw/pi-btw/src/keybindings.ts +228 -270
  11. package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +309 -318
  12. package/node_modules/@narumitw/pi-btw/src/menu.ts +416 -454
  13. package/node_modules/@narumitw/pi-btw/src/settings.ts +203 -219
  14. package/node_modules/@narumitw/pi-btw/src/side-thread.ts +173 -201
  15. package/node_modules/@narumitw/pi-btw/src/text.ts +21 -23
  16. package/node_modules/@narumitw/pi-btw/src/transcript-markdown.ts +65 -0
  17. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +611 -662
  18. package/node_modules/grok-mermaid/CHANGELOG.md +46 -0
  19. package/node_modules/grok-mermaid/LICENSE +205 -0
  20. package/node_modules/grok-mermaid/README.md +191 -0
  21. package/node_modules/grok-mermaid/dist/ansi.d.ts +16 -0
  22. package/node_modules/grok-mermaid/dist/ansi.d.ts.map +1 -0
  23. package/node_modules/grok-mermaid/dist/ansi.js +23 -0
  24. package/node_modules/grok-mermaid/dist/ansi.js.map +1 -0
  25. package/node_modules/grok-mermaid/dist/canvas.d.ts +87 -0
  26. package/node_modules/grok-mermaid/dist/canvas.d.ts.map +1 -0
  27. package/node_modules/grok-mermaid/dist/canvas.js +366 -0
  28. package/node_modules/grok-mermaid/dist/canvas.js.map +1 -0
  29. package/node_modules/grok-mermaid/dist/graph.d.ts +74 -0
  30. package/node_modules/grok-mermaid/dist/graph.d.ts.map +1 -0
  31. package/node_modules/grok-mermaid/dist/graph.js +91 -0
  32. package/node_modules/grok-mermaid/dist/graph.js.map +1 -0
  33. package/node_modules/grok-mermaid/dist/index.d.ts +32 -0
  34. package/node_modules/grok-mermaid/dist/index.d.ts.map +1 -0
  35. package/node_modules/grok-mermaid/dist/index.js +100 -0
  36. package/node_modules/grok-mermaid/dist/index.js.map +1 -0
  37. package/node_modules/grok-mermaid/dist/labels.d.ts +62 -0
  38. package/node_modules/grok-mermaid/dist/labels.d.ts.map +1 -0
  39. package/node_modules/grok-mermaid/dist/labels.js +324 -0
  40. package/node_modules/grok-mermaid/dist/labels.js.map +1 -0
  41. package/node_modules/grok-mermaid/dist/layout-seq.d.ts +12 -0
  42. package/node_modules/grok-mermaid/dist/layout-seq.d.ts.map +1 -0
  43. package/node_modules/grok-mermaid/dist/layout-seq.js +194 -0
  44. package/node_modules/grok-mermaid/dist/layout-seq.js.map +1 -0
  45. package/node_modules/grok-mermaid/dist/layout.d.ts +87 -0
  46. package/node_modules/grok-mermaid/dist/layout.d.ts.map +1 -0
  47. package/node_modules/grok-mermaid/dist/layout.js +881 -0
  48. package/node_modules/grok-mermaid/dist/layout.js.map +1 -0
  49. package/node_modules/grok-mermaid/dist/parse.d.ts +83 -0
  50. package/node_modules/grok-mermaid/dist/parse.d.ts.map +1 -0
  51. package/node_modules/grok-mermaid/dist/parse.js +1151 -0
  52. package/node_modules/grok-mermaid/dist/parse.js.map +1 -0
  53. package/node_modules/grok-mermaid/dist/source-box.d.ts +18 -0
  54. package/node_modules/grok-mermaid/dist/source-box.d.ts.map +1 -0
  55. package/node_modules/grok-mermaid/dist/source-box.js +78 -0
  56. package/node_modules/grok-mermaid/dist/source-box.js.map +1 -0
  57. package/node_modules/grok-mermaid/dist/types.d.ts +42 -0
  58. package/node_modules/grok-mermaid/dist/types.d.ts.map +1 -0
  59. package/node_modules/grok-mermaid/dist/types.js +1 -0
  60. package/node_modules/grok-mermaid/dist/types.js.map +1 -0
  61. package/node_modules/grok-mermaid/dist/width-data.d.ts +2 -0
  62. package/node_modules/grok-mermaid/dist/width-data.d.ts.map +1 -0
  63. package/node_modules/grok-mermaid/dist/width-data.js +994 -0
  64. package/node_modules/grok-mermaid/dist/width-data.js.map +1 -0
  65. package/node_modules/grok-mermaid/dist/width.d.ts +18 -0
  66. package/node_modules/grok-mermaid/dist/width.d.ts.map +1 -0
  67. package/node_modules/grok-mermaid/dist/width.js +76 -0
  68. package/node_modules/grok-mermaid/dist/width.js.map +1 -0
  69. package/node_modules/grok-mermaid/package.json +49 -0
  70. package/node_modules/grok-mermaid/src/ansi.ts +34 -0
  71. package/node_modules/grok-mermaid/src/canvas.ts +373 -0
  72. package/node_modules/grok-mermaid/src/graph.ts +142 -0
  73. package/node_modules/grok-mermaid/src/index.ts +104 -0
  74. package/node_modules/grok-mermaid/src/labels.ts +326 -0
  75. package/node_modules/grok-mermaid/src/layout-seq.ts +203 -0
  76. package/node_modules/grok-mermaid/src/layout.ts +1015 -0
  77. package/node_modules/grok-mermaid/src/parse.ts +1189 -0
  78. package/node_modules/grok-mermaid/src/source-box.ts +89 -0
  79. package/node_modules/grok-mermaid/src/types.ts +43 -0
  80. package/node_modules/grok-mermaid/src/width-data.ts +993 -0
  81. package/node_modules/grok-mermaid/src/width.ts +74 -0
  82. package/node_modules/pi-lens/CHANGELOG.md +239 -0
  83. package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +3 -0
  84. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +30 -4
  85. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +2 -0
  86. package/node_modules/pi-lens/dist/clients/bash-file-access.js +26 -0
  87. package/node_modules/pi-lens/dist/clients/biome-client.js +1 -1
  88. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +403 -35
  89. package/node_modules/pi-lens/dist/clients/bootstrap.js +6 -1
  90. package/node_modules/pi-lens/dist/clients/cascade-format.js +200 -4
  91. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +10 -2
  92. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +16 -1
  93. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +12 -1
  94. package/node_modules/pi-lens/dist/clients/dispatch/ast-grep-catalog.js +65 -0
  95. package/node_modules/pi-lens/dist/clients/dispatch/auxiliary-lsp.js +28 -0
  96. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +9 -2
  97. package/node_modules/pi-lens/dist/clients/dispatch/finding-policy.js +222 -0
  98. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +389 -13
  99. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +175 -25
  100. package/node_modules/pi-lens/dist/clients/dispatch/rule-ignores.js +62 -0
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +21 -41
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +6 -1
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +7 -7
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -12
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +2 -21
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +1 -1
  107. package/node_modules/pi-lens/dist/clients/dispatch/types.js +4 -1
  108. package/node_modules/pi-lens/dist/clients/disposition-publish.js +1 -0
  109. package/node_modules/pi-lens/dist/clients/effective-config.js +1 -1
  110. package/node_modules/pi-lens/dist/clients/file-kinds.js +26 -1
  111. package/node_modules/pi-lens/dist/clients/file-role.js +21 -21
  112. package/node_modules/pi-lens/dist/clients/file-utils.js +156 -10
  113. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +56 -9
  114. package/node_modules/pi-lens/dist/clients/format-service.js +39 -21
  115. package/node_modules/pi-lens/dist/clients/formatters.js +60 -13
  116. package/node_modules/pi-lens/dist/clients/generation-guard.js +2 -2
  117. package/node_modules/pi-lens/dist/clients/git-guard.js +11 -3
  118. package/node_modules/pi-lens/dist/clients/indent-retarget.js +78 -8
  119. package/node_modules/pi-lens/dist/clients/installer/index.js +333 -114
  120. package/node_modules/pi-lens/dist/clients/instance-reaper-state.js +7 -0
  121. package/node_modules/pi-lens/dist/clients/instance-reaper.js +20 -10
  122. package/node_modules/pi-lens/dist/clients/language-profile.js +23 -1
  123. package/node_modules/pi-lens/dist/clients/language-registry.js +5 -1
  124. package/node_modules/pi-lens/dist/clients/latency-logger.js +4 -1
  125. package/node_modules/pi-lens/dist/clients/lens-engine.js +12 -3
  126. package/node_modules/pi-lens/dist/clients/lens-events.js +2 -1
  127. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +79 -0
  128. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +2 -1
  129. package/node_modules/pi-lens/dist/clients/lsp/client.js +25 -21
  130. package/node_modules/pi-lens/dist/clients/lsp/config.js +2 -2
  131. package/node_modules/pi-lens/dist/clients/lsp/index.js +7 -0
  132. package/node_modules/pi-lens/dist/clients/lsp/launch.js +16 -4
  133. package/node_modules/pi-lens/dist/clients/lsp/server.js +19 -2
  134. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +2 -1
  135. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +5 -3
  136. package/node_modules/pi-lens/dist/clients/map-with-concurrency.js +12 -8
  137. package/node_modules/pi-lens/dist/clients/mcp/session.js +36 -4
  138. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +24 -7
  139. package/node_modules/pi-lens/dist/clients/observed-mutation.js +40 -2
  140. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +23 -3
  141. package/node_modules/pi-lens/dist/clients/opengrep-client.js +110 -15
  142. package/node_modules/pi-lens/dist/clients/path-utils.js +123 -3
  143. package/node_modules/pi-lens/dist/clients/performance-report.js +5 -1
  144. package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +1 -1
  145. package/node_modules/pi-lens/dist/clients/pipeline.js +74 -5
  146. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +37 -5
  147. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +145 -18
  148. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/dead-code.js +4 -1
  149. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +59 -3
  150. package/node_modules/pi-lens/dist/clients/project-lens-config.js +45 -2
  151. package/node_modules/pi-lens/dist/clients/read-guard.js +70 -11
  152. package/node_modules/pi-lens/dist/clients/resource-sampler.js +147 -9
  153. package/node_modules/pi-lens/dist/clients/ruff-client.js +1 -1
  154. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +33 -5
  155. package/node_modules/pi-lens/dist/clients/runtime-context.js +6 -2
  156. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +77 -7
  157. package/node_modules/pi-lens/dist/clients/runtime-session.js +21 -2
  158. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +43 -12
  159. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +330 -85
  160. package/node_modules/pi-lens/dist/clients/runtime-turn.js +147 -17
  161. package/node_modules/pi-lens/dist/clients/safe-spawn.js +258 -5
  162. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +6 -0
  163. package/node_modules/pi-lens/dist/clients/session-event-guard.js +50 -5
  164. package/node_modules/pi-lens/dist/clients/sg-runner.js +23 -11
  165. package/node_modules/pi-lens/dist/clients/sgconfig.js +79 -2
  166. package/node_modules/pi-lens/dist/clients/test-runner-client.js +6 -41
  167. package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +43 -0
  168. package/node_modules/pi-lens/dist/clients/tool-agreement.js +423 -0
  169. package/node_modules/pi-lens/dist/clients/tool-config.js +50 -0
  170. package/node_modules/pi-lens/dist/clients/tool-cwd.js +47 -76
  171. package/node_modules/pi-lens/dist/clients/tool-policy.js +163 -7
  172. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +120 -0
  173. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +127 -189
  174. package/node_modules/pi-lens/dist/clients/widget-state.js +98 -0
  175. package/node_modules/pi-lens/dist/clients/word-index.js +5 -2
  176. package/node_modules/pi-lens/dist/clients/write-ordering-guard.js +7 -0
  177. package/node_modules/pi-lens/dist/index.js +27416 -24153
  178. package/node_modules/pi-lens/dist/mcp/server.js +5 -2
  179. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +7 -1
  180. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +168 -53
  181. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +244 -72
  182. package/node_modules/pi-lens/docs/audit1.md +5 -5
  183. package/node_modules/pi-lens/docs/dependencies.md +11 -0
  184. package/node_modules/pi-lens/docs/dispositions.md +52 -0
  185. package/node_modules/pi-lens/docs/environment-variables.md +2 -2
  186. package/node_modules/pi-lens/docs/features.md +4 -4
  187. package/node_modules/pi-lens/docs/globalconfig.md +3 -1
  188. package/node_modules/pi-lens/docs/language-coverage.md +1 -0
  189. package/node_modules/pi-lens/docs/pi-lens-fixer.md +53 -94
  190. package/node_modules/pi-lens/docs/pi-lens-investigator.md +43 -38
  191. package/node_modules/pi-lens/docs/pi-lens-retro.md +97 -0
  192. package/node_modules/pi-lens/docs/pi-lens-reviewer.md +53 -66
  193. package/node_modules/pi-lens/docs/release-qa-baseline.md +22 -0
  194. package/node_modules/pi-lens/docs/settings.md +7 -4
  195. package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +1 -1
  196. package/node_modules/pi-lens/docs/usage.md +2 -0
  197. package/node_modules/pi-lens/package.json +1 -1
  198. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/sql-injection.yml +24 -12
  199. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +40 -0
  200. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +15 -0
  201. package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +7 -0
  202. package/package.json +6 -11
  203. package/node_modules/@luxusai/pi-hindsight/CHANGELOG.md +0 -376
  204. package/node_modules/@luxusai/pi-hindsight/README.md +0 -92
  205. package/node_modules/@luxusai/pi-hindsight/docs/adr/001-memory-lifecycle-and-scope.md +0 -56
  206. package/node_modules/@luxusai/pi-hindsight/docs/adr/002-explicit-routing-strategy-seam.md +0 -169
  207. package/node_modules/@luxusai/pi-hindsight/docs/adr/003-tui-memory-mode-vocabulary.md +0 -107
  208. package/node_modules/@luxusai/pi-hindsight/docs/adr/004-lifeos-dual-bank-design.md +0 -89
  209. package/node_modules/@luxusai/pi-hindsight/docs/adr/005-domain-banks-and-agent-first-surface.md +0 -189
  210. package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark.webp +0 -0
  211. package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark@2x.webp +0 -0
  212. package/node_modules/@luxusai/pi-hindsight/docs/coding-memory-evaluation.md +0 -54
  213. package/node_modules/@luxusai/pi-hindsight/docs/compatibility.md +0 -75
  214. package/node_modules/@luxusai/pi-hindsight/docs/hindsight-core-functions.md +0 -300
  215. package/node_modules/@luxusai/pi-hindsight/docs/mission-and-mental-model-quality.md +0 -158
  216. package/node_modules/@luxusai/pi-hindsight/docs/next-opt-out-design.md +0 -164
  217. package/node_modules/@luxusai/pi-hindsight/docs/risky-memory-modes.md +0 -139
  218. package/node_modules/@luxusai/pi-hindsight/docs/starter-mental-model-suggestions.md +0 -74
  219. package/node_modules/@luxusai/pi-hindsight/docs/surface-reference.md +0 -261
  220. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-operations.ts +0 -151
  221. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-selection.ts +0 -18
  222. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-settings-presenter.ts +0 -46
  223. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-templates.ts +0 -383
  224. package/node_modules/@luxusai/pi-hindsight/extensions/banks/banking.ts +0 -240
  225. package/node_modules/@luxusai/pi-hindsight/extensions/banks/knowledge-page-seed.ts +0 -176
  226. package/node_modules/@luxusai/pi-hindsight/extensions/banks/retain-strategies.ts +0 -178
  227. package/node_modules/@luxusai/pi-hindsight/extensions/client/client-retry.ts +0 -41
  228. package/node_modules/@luxusai/pi-hindsight/extensions/client/client.ts +0 -386
  229. package/node_modules/@luxusai/pi-hindsight/extensions/client/fetch-compat.ts +0 -39
  230. package/node_modules/@luxusai/pi-hindsight/extensions/client/timeout.ts +0 -34
  231. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-defaults.ts +0 -140
  232. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-model.ts +0 -61
  233. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-registry.ts +0 -925
  234. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-field-paths.ts +0 -247
  235. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-normalize.ts +0 -547
  236. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-writer.ts +0 -480
  237. package/node_modules/@luxusai/pi-hindsight/extensions/config/config.ts +0 -182
  238. package/node_modules/@luxusai/pi-hindsight/extensions/config/setup-gate.ts +0 -86
  239. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-execute.ts +0 -1010
  240. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-parse.ts +0 -175
  241. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-plan.ts +0 -425
  242. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-presentation.ts +0 -210
  243. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-sessions.ts +0 -817
  244. package/node_modules/@luxusai/pi-hindsight/extensions/index.ts +0 -25
  245. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/git-seed.ts +0 -319
  246. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-recall.ts +0 -196
  247. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-retain.ts +0 -189
  248. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-runtime.ts +0 -65
  249. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle.ts +0 -260
  250. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/mental-models.ts +0 -244
  251. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/observation-scopes.ts +0 -59
  252. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-cleanup.ts +0 -82
  253. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-visibility.ts +0 -45
  254. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall.ts +0 -331
  255. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-cursor.ts +0 -354
  256. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-job-builder.ts +0 -66
  257. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-receipts.ts +0 -132
  258. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain.ts +0 -228
  259. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-bank-template-operations.ts +0 -74
  260. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-config-operations.ts +0 -16
  261. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-control-operations.ts +0 -648
  262. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-diagnostics-operations.ts +0 -105
  263. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-identity.ts +0 -68
  264. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-service.ts +0 -71
  265. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-types.ts +0 -13
  266. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-recall-operations.ts +0 -162
  267. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-retain-operations.ts +0 -131
  268. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-scope.ts +0 -104
  269. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-session-operations.ts +0 -37
  270. package/node_modules/@luxusai/pi-hindsight/extensions/operations/operation-catalog.ts +0 -893
  271. package/node_modules/@luxusai/pi-hindsight/extensions/operations/reflect-presenter.ts +0 -35
  272. package/node_modules/@luxusai/pi-hindsight/extensions/operations/scope-migrate.ts +0 -177
  273. package/node_modules/@luxusai/pi-hindsight/extensions/operations/tools.ts +0 -7
  274. package/node_modules/@luxusai/pi-hindsight/extensions/queue/flush-presenter.ts +0 -21
  275. package/node_modules/@luxusai/pi-hindsight/extensions/queue/jsonl-queue-store.ts +0 -112
  276. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-delivery.ts +0 -111
  277. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-lock.ts +0 -214
  278. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-operations.ts +0 -70
  279. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue.ts +0 -392
  280. package/node_modules/@luxusai/pi-hindsight/extensions/tui/bank-template-presentation.ts +0 -45
  281. package/node_modules/@luxusai/pi-hindsight/extensions/tui/commands.ts +0 -9
  282. package/node_modules/@luxusai/pi-hindsight/extensions/tui/guided-setup.ts +0 -860
  283. package/node_modules/@luxusai/pi-hindsight/extensions/tui/prefill-input.ts +0 -105
  284. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-flow.ts +0 -189
  285. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-server-probe.ts +0 -299
  286. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-actions.ts +0 -201
  287. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-facts.ts +0 -47
  288. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-render.ts +0 -239
  289. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-types.ts +0 -50
  290. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui.ts +0 -259
  291. package/node_modules/@luxusai/pi-hindsight/extensions/tui/tool-presenters.ts +0 -77
  292. package/node_modules/@luxusai/pi-hindsight/extensions/types.ts +0 -534
  293. package/node_modules/@luxusai/pi-hindsight/extensions/utils/diagnostics.ts +0 -319
  294. package/node_modules/@luxusai/pi-hindsight/extensions/utils/messages.ts +0 -325
  295. package/node_modules/@luxusai/pi-hindsight/extensions/utils/sanitize.ts +0 -42
  296. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-memory-meta.ts +0 -244
  297. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-operations.ts +0 -56
  298. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session.ts +0 -50
  299. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-fields.ts +0 -167
  300. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-health.ts +0 -207
  301. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status.ts +0 -120
  302. package/node_modules/@luxusai/pi-hindsight/extensions/version.ts +0 -8
  303. package/node_modules/@luxusai/pi-hindsight/package.json +0 -118
  304. package/node_modules/@luxusai/pi-hindsight/skills/hindsight-memory-doctor/SKILL.md +0 -75
@@ -0,0 +1,423 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { BoundedFifoMap } from "./bounded-cache.js";
4
+ import { findNearestMarkerRoot } from "./path-utils.js";
5
+ import { getDegradationLedgerGeneration } from "./degradation-ledger.js";
6
+ import { hasBlackConfig, hasClangFormatConfig, hasCljfmtConfig, hasCmakeFormatConfig, hasCsharpierConfig, hasDetektConfig, hasFantomasConfig, hasGoogleJavaFormatConfig, hasGradleKtlintPlugin, hasGolangciConfig, hasKtfmtConfig, hasKtlintConfig, hasMarkdownlintConfig, hasMixFormatConfig, hasOcamlformatConfig, hasOrmoluConfig, hasPhpCsFixerConfig, hasRubocopConfig, hasRuffConfig, hasSqlfluffConfig, hasStandardrbConfig, hasStyluaConfig, hasSwiftformatConfig, hasTaploConfig, hasTerraformConfig, } from "./tool-policy.js";
7
+ const NODE_PACKAGES = {
8
+ biome: "@biomejs/biome",
9
+ eslint: "eslint",
10
+ markdownlint: "markdownlint-cli2",
11
+ oxfmt: "oxfmt",
12
+ oxlint: "oxlint",
13
+ prettier: "prettier",
14
+ stylelint: "stylelint",
15
+ };
16
+ /**
17
+ * The complete autonomous writer population. Keep this table declarative: a
18
+ * caller may ask about an LSP warning tool that is not in the autofix or
19
+ * formatter tables, and that must take the unknown-tool default below rather
20
+ * than accidentally becoming established (#3005).
21
+ *
22
+ * Config evidence is deliberately presence-based. The existing policy
23
+ * detectors own each format's syntax and scope; agreement only answers the
24
+ * narrower question of whether this project elected the tool. Node tools use
25
+ * the stronger lockfile identity check in `nodeAgreement`.
26
+ */
27
+ export const TOOL_AGREEMENT_POLICIES = {
28
+ biome: { bucket: "node-lockfile", withoutEvidence: "decline" },
29
+ eslint: { bucket: "node-lockfile", withoutEvidence: "decline" },
30
+ markdownlint: {
31
+ bucket: "node-lockfile",
32
+ withoutEvidence: "decline",
33
+ check: hasMarkdownlintConfig,
34
+ },
35
+ oxfmt: { bucket: "node-lockfile", withoutEvidence: "decline" },
36
+ oxlint: { bucket: "node-lockfile", withoutEvidence: "decline" },
37
+ prettier: { bucket: "node-lockfile", withoutEvidence: "decline" },
38
+ stylelint: { bucket: "node-lockfile", withoutEvidence: "decline" },
39
+ ruff: {
40
+ bucket: "project-config",
41
+ withoutEvidence: "decline",
42
+ check: hasRuffConfig,
43
+ },
44
+ black: {
45
+ bucket: "project-config",
46
+ withoutEvidence: "decline",
47
+ check: hasBlackConfig,
48
+ },
49
+ sqlfluff: {
50
+ bucket: "project-config",
51
+ withoutEvidence: "decline",
52
+ check: hasSqlfluffConfig,
53
+ },
54
+ rubocop: {
55
+ bucket: "project-config",
56
+ withoutEvidence: "decline",
57
+ check: hasRubocopConfig,
58
+ },
59
+ standardrb: {
60
+ bucket: "project-config",
61
+ withoutEvidence: "decline",
62
+ check: hasStandardrbConfig,
63
+ },
64
+ ktlint: { bucket: "standalone-cli", withoutEvidence: "decline" },
65
+ // typstyle is a standalone formatter binary. Its smart-default policy is
66
+ // autonomous, so PATH or managed-install availability is sufficient
67
+ // agreement; it is not owned by a project manifest (#3037).
68
+ typstyle: { bucket: "standalone-cli", withoutEvidence: "decline" },
69
+ ktfmt: {
70
+ bucket: "project-config",
71
+ withoutEvidence: "decline",
72
+ check: hasKtfmtConfig,
73
+ },
74
+ "rust-clippy": {
75
+ bucket: "project-config",
76
+ withoutEvidence: "decline",
77
+ check: (cwd) => hasMarker(cwd, ["Cargo.toml"]),
78
+ },
79
+ "dart-analyze": {
80
+ bucket: "project-config",
81
+ withoutEvidence: "decline",
82
+ check: (cwd) => hasMarker(cwd, ["pubspec.yaml"]),
83
+ },
84
+ "golangci-lint": {
85
+ bucket: "project-config",
86
+ withoutEvidence: "decline",
87
+ check: hasGolangciConfig,
88
+ },
89
+ detekt: {
90
+ bucket: "project-config",
91
+ withoutEvidence: "decline",
92
+ check: hasDetektConfig,
93
+ },
94
+ gofmt: {
95
+ bucket: "project-config",
96
+ withoutEvidence: "decline",
97
+ check: (cwd) => hasMarker(cwd, ["go.mod"]),
98
+ },
99
+ rustfmt: {
100
+ bucket: "project-config",
101
+ withoutEvidence: "decline",
102
+ check: (cwd) => hasMarker(cwd, ["Cargo.toml"]),
103
+ },
104
+ zig: {
105
+ bucket: "project-config",
106
+ withoutEvidence: "decline",
107
+ check: (cwd) => hasMarker(cwd, ["build.zig"]),
108
+ },
109
+ dart: {
110
+ bucket: "project-config",
111
+ withoutEvidence: "decline",
112
+ check: (cwd) => hasMarker(cwd, ["pubspec.yaml"]),
113
+ },
114
+ shfmt: {
115
+ bucket: "project-config",
116
+ withoutEvidence: "decline",
117
+ check: (cwd) => hasMarker(cwd, [".editorconfig"]),
118
+ },
119
+ // nixfmt has no honest project marker. It remains in the population and is
120
+ // declined by the conservative absent-evidence path below.
121
+ nixfmt: { bucket: "project-config", withoutEvidence: "decline" },
122
+ mix: {
123
+ bucket: "project-config",
124
+ withoutEvidence: "decline",
125
+ check: hasMixFormatConfig,
126
+ },
127
+ ocamlformat: {
128
+ bucket: "project-config",
129
+ withoutEvidence: "decline",
130
+ check: hasOcamlformatConfig,
131
+ },
132
+ "clang-format": {
133
+ bucket: "project-config",
134
+ withoutEvidence: "decline",
135
+ check: hasClangFormatConfig,
136
+ },
137
+ gleam: {
138
+ bucket: "project-config",
139
+ withoutEvidence: "decline",
140
+ check: (cwd) => hasMarker(cwd, ["gleam.toml"]),
141
+ },
142
+ terraform: {
143
+ bucket: "project-config",
144
+ withoutEvidence: "decline",
145
+ check: hasTerraformConfig,
146
+ },
147
+ "terragrunt-hcl": {
148
+ bucket: "project-config",
149
+ withoutEvidence: "decline",
150
+ check: (cwd) => hasMarker(cwd, ["terragrunt.hcl", "terragrunt.hcl.json"]),
151
+ },
152
+ "php-cs-fixer": {
153
+ bucket: "project-config",
154
+ withoutEvidence: "decline",
155
+ check: hasPhpCsFixerConfig,
156
+ },
157
+ csharpier: {
158
+ bucket: "project-config",
159
+ withoutEvidence: "decline",
160
+ check: hasCsharpierConfig,
161
+ },
162
+ fantomas: {
163
+ bucket: "project-config",
164
+ withoutEvidence: "decline",
165
+ check: hasFantomasConfig,
166
+ },
167
+ swiftformat: {
168
+ bucket: "project-config",
169
+ withoutEvidence: "decline",
170
+ check: hasSwiftformatConfig,
171
+ },
172
+ stylua: {
173
+ bucket: "project-config",
174
+ withoutEvidence: "decline",
175
+ check: hasStyluaConfig,
176
+ },
177
+ ormolu: {
178
+ bucket: "project-config",
179
+ withoutEvidence: "decline",
180
+ check: hasOrmoluConfig,
181
+ },
182
+ taplo: {
183
+ bucket: "project-config",
184
+ withoutEvidence: "decline",
185
+ check: hasTaploConfig,
186
+ },
187
+ "google-java-format": {
188
+ bucket: "project-config",
189
+ withoutEvidence: "decline",
190
+ check: hasGoogleJavaFormatConfig,
191
+ },
192
+ cljfmt: {
193
+ bucket: "project-config",
194
+ withoutEvidence: "decline",
195
+ check: hasCljfmtConfig,
196
+ },
197
+ "cmake-format": {
198
+ bucket: "project-config",
199
+ withoutEvidence: "decline",
200
+ check: hasCmakeFormatConfig,
201
+ },
202
+ "psscriptanalyzer-format": {
203
+ bucket: "project-config",
204
+ withoutEvidence: "decline",
205
+ check: (cwd) => hasMarker(cwd, [
206
+ "PSScriptAnalyzerSettings.psd1",
207
+ "ScriptAnalyzerSettings.psd1",
208
+ ]),
209
+ },
210
+ cue: {
211
+ bucket: "project-config",
212
+ withoutEvidence: "decline",
213
+ check: (cwd) => hasMarker(cwd, ["cue.mod"]),
214
+ },
215
+ };
216
+ function hasMarker(cwd, markers) {
217
+ return (findNearestMarkerRoot(cwd, markers, {
218
+ boundaries: [".git", ".hg", ".svn"],
219
+ }) !== null);
220
+ }
221
+ function readJson(filePath) {
222
+ if (!fs.existsSync(filePath))
223
+ return { kind: "missing" };
224
+ try {
225
+ const value = JSON.parse(fs.readFileSync(filePath, "utf8"));
226
+ return value && typeof value === "object"
227
+ ? { kind: "value", value: value }
228
+ : { kind: "unparseable" };
229
+ }
230
+ catch (error) {
231
+ return {
232
+ kind: error instanceof SyntaxError ? "unparseable" : "unreadable",
233
+ };
234
+ }
235
+ }
236
+ function declaredRange(pkg, name) {
237
+ for (const field of [
238
+ "dependencies",
239
+ "devDependencies",
240
+ "optionalDependencies",
241
+ ]) {
242
+ const deps = pkg[field];
243
+ if (deps && typeof deps === "object") {
244
+ const range = deps[name];
245
+ if (typeof range === "string")
246
+ return range;
247
+ }
248
+ }
249
+ return undefined;
250
+ }
251
+ function parseCoreVersion(version) {
252
+ const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version);
253
+ if (!match)
254
+ return undefined;
255
+ const parts = match.slice(1).map(Number);
256
+ if (parts.some((part) => !Number.isSafeInteger(part)))
257
+ return undefined;
258
+ return parts;
259
+ }
260
+ function exactOrSimpleRangeMatches(range, version) {
261
+ const clean = range.trim().replace(/^v/, "");
262
+ const actual = parseCoreVersion(version);
263
+ if (!actual)
264
+ return { matches: false, unsupported: version.includes("+") };
265
+ if (/^\d+\.\d+\.\d+$/.test(clean))
266
+ return { matches: clean === version, unsupported: false };
267
+ const caret = clean.match(/^\^(\d+)\.(\d+)\.(\d+)$/);
268
+ if (caret) {
269
+ const [major, minor, patch] = caret.slice(1).map(Number);
270
+ return {
271
+ matches: actual[0] === major &&
272
+ (major !== 0 || actual[1] === minor) &&
273
+ (major !== 0 || minor !== 0 || actual[2] === patch) &&
274
+ (actual[1] > minor || (actual[1] === minor && actual[2] >= patch)),
275
+ unsupported: false,
276
+ };
277
+ }
278
+ const tilde = clean.match(/^~(\d+)\.(\d+)\.(\d+)$/);
279
+ if (tilde) {
280
+ const [major, minor, patch] = tilde.slice(1).map(Number);
281
+ return {
282
+ matches: actual[0] === major && actual[1] === minor && actual[2] >= patch,
283
+ unsupported: false,
284
+ };
285
+ }
286
+ return { matches: false, unsupported: true };
287
+ }
288
+ function nodeAgreement(tool, root) {
289
+ const packageName = NODE_PACKAGES[tool];
290
+ if (!packageName)
291
+ return undefined;
292
+ const pkg = readJson(path.join(root, "package.json"));
293
+ if (pkg.kind === "unreadable" || pkg.kind === "unparseable") {
294
+ return {
295
+ decision: "decline",
296
+ subject: `node:${tool}`,
297
+ reason: `the project package.json is ${pkg.kind}; tool agreement cannot be established`,
298
+ reasonCode: `evidence-${pkg.kind}`,
299
+ };
300
+ }
301
+ const range = pkg.kind === "value" ? declaredRange(pkg.value, packageName) : undefined;
302
+ if (!range)
303
+ return undefined;
304
+ const lock = readJson(path.join(root, "package-lock.json"));
305
+ if (lock.kind === "unreadable" || lock.kind === "unparseable") {
306
+ return {
307
+ decision: "decline",
308
+ subject: `node:${tool}`,
309
+ reason: `the project package-lock.json is ${lock.kind}; tool agreement cannot be established`,
310
+ reasonCode: `evidence-${lock.kind}`,
311
+ };
312
+ }
313
+ const packages = lock.kind === "value" ? lock.value.packages : undefined;
314
+ const entry = packages && typeof packages === "object"
315
+ ? packages[`node_modules/${packageName}`]
316
+ : undefined;
317
+ const version = entry && typeof entry === "object"
318
+ ? entry.version
319
+ : undefined;
320
+ const comparison = typeof version === "string"
321
+ ? exactOrSimpleRangeMatches(range, version)
322
+ : { matches: false, unsupported: false };
323
+ if (typeof version !== "string" || !comparison.matches) {
324
+ const reasonCode = typeof version === "string" && comparison.unsupported
325
+ ? "evidence-unsupported"
326
+ : typeof version === "string" && version.includes("+")
327
+ ? "evidence-unsupported"
328
+ : "evidence-unparseable";
329
+ const reason = typeof version === "string" && comparison.unsupported
330
+ ? `the project declares ${packageName}@${range}, but the lockfile shape ${packageName}@${version} or its range is unsupported; tool agreement cannot be established`
331
+ : typeof version === "string" && parseCoreVersion(version)
332
+ ? `the project declares ${packageName}@${range} in package.json, but the lockfile resolves ${packageName}@${version} in package-lock.json; agreement disagrees`
333
+ : `the project declares ${packageName}@${range} in package.json, but package-lock.json does not establish its resolved version; tool agreement cannot be established`;
334
+ return {
335
+ decision: "decline",
336
+ subject: `node:${tool}`,
337
+ reason,
338
+ reasonCode,
339
+ };
340
+ }
341
+ return { decision: "established" };
342
+ }
343
+ /** Decide whether autofix has project evidence to act on. Never infers a CLI
344
+ * version from build-plugin metadata (#3000). */
345
+ export function establishToolAgreement(tool, cwd) {
346
+ const key = `${getDegradationLedgerGeneration()}\0${path.resolve(cwd)}\0${tool}`;
347
+ const cached = agreementCache.get(key);
348
+ if (cached)
349
+ return cached;
350
+ agreementResolutionCount += 1;
351
+ const policy = TOOL_AGREEMENT_POLICIES[tool];
352
+ if (!policy) {
353
+ const agreement = {
354
+ decision: "decline",
355
+ subject: `tool:${tool}`,
356
+ reason: "the autonomous writer is not registered with a project-evidence policy; tool agreement cannot be established",
357
+ reasonCode: "evidence-unsupported",
358
+ };
359
+ agreementCache.set(key, agreement);
360
+ return agreement;
361
+ }
362
+ let agreement = { decision: "established" };
363
+ if (tool === "ktlint") {
364
+ const ownership = hasGradleKtlintPlugin(cwd);
365
+ if (ownership.kind === "owned" || hasKtlintConfig(cwd)) {
366
+ agreement = {
367
+ decision: "decline",
368
+ subject: "kotlin:gradle-ktlint",
369
+ reason: "the project resolves ktlint through Gradle, so CLI agreement cannot be established from project data",
370
+ reasonCode: "evidence-unsupported",
371
+ };
372
+ }
373
+ else if (ownership.kind === "indeterminate") {
374
+ agreement = {
375
+ decision: "decline",
376
+ subject: "kotlin:gradle-ktlint",
377
+ reason: "Gradle ownership evidence is unreadable or exceeded its scan budget; tool agreement cannot be established",
378
+ reasonCode: "evidence-unreadable",
379
+ };
380
+ }
381
+ }
382
+ if (agreement.decision === "established" &&
383
+ policy.bucket === "node-lockfile") {
384
+ const root = findNearestMarkerRoot(cwd, ["package.json"], {
385
+ boundaries: [".git", ".hg", ".svn"],
386
+ });
387
+ const node = root ? nodeAgreement(tool, root) : undefined;
388
+ agreement = node ?? {
389
+ decision: "decline",
390
+ subject: `node:${tool}`,
391
+ reason: "the project has no package declaration and lockfile evidence for this tool",
392
+ reasonCode: "evidence-absent",
393
+ };
394
+ }
395
+ else if (agreement.decision === "established" &&
396
+ policy.bucket === "project-config" &&
397
+ (!policy.check || !policy.check(cwd))) {
398
+ agreement = {
399
+ decision: "decline",
400
+ subject: `project:${tool}`,
401
+ reason: "the project has no readable configuration or manifest evidence selecting this tool",
402
+ reasonCode: "evidence-absent",
403
+ };
404
+ }
405
+ /* Keep the branch below as a final assertion that no policy can bypass the
406
+ * registry. It also makes future bucket additions fail closed at runtime. */
407
+ if (agreement.decision === "established" && !policy.bucket) {
408
+ agreement = {
409
+ decision: "decline",
410
+ subject: `tool:${tool}`,
411
+ reason: "the tool evidence bucket is unsupported",
412
+ reasonCode: "evidence-unsupported",
413
+ };
414
+ }
415
+ agreementCache.set(key, agreement);
416
+ return agreement;
417
+ }
418
+ const agreementCache = new BoundedFifoMap(512);
419
+ let agreementResolutionCount = 0;
420
+ /** Test-only counter for the bounded hot-path resolution. */
421
+ export function _getAgreementResolutionCountForTests() {
422
+ return agreementResolutionCount;
423
+ }
@@ -1,5 +1,6 @@
1
1
  /** Shared resolver for model-facing tool availability (#2800). */
2
2
  import { readFlagConfigValue } from "./lens-flag-registry.js";
3
+ import { escapeRegExp } from "./string-utils.js";
3
4
  /** The complete model-facing tool population on pi and MCP. */
4
5
  export const TOOL_REGISTRY = [
5
6
  {
@@ -140,6 +141,55 @@ export const TOOL_REGISTRY = [
140
141
  },
141
142
  ];
142
143
  export const LENS_TOOL_NAMES = TOOL_REGISTRY.map((tool) => tool.name);
144
+ /**
145
+ * Registry tools with a pi name but no MCP name are pi-only BY DECLARATION
146
+ * here, never by omission (#2535 F3). A missing entry used to degrade
147
+ * silently into the pi name on MCP, sending the agent to a dead call — the
148
+ * guard in tests/clients/adapter-aware-tool-names.test.ts fails on any
149
+ * pi-only row absent from this map, and `resolveLensToolName` resolves a
150
+ * known-but-unmapped host to `undefined` so callers omit instead of naming.
151
+ */
152
+ export const PI_ONLY_TOOL_REASONS = {
153
+ ast_grep_outline: "pi situational tool with no MCP mirror; MCP parity deferred like read_enclosing was.",
154
+ lens_diagnostic_mark: "pi-lens-internal disposition tool; MCP has no equivalent surface (needs its own engine seam and tool route).",
155
+ pi_lens_activate_tools: "pi dynamic-tooling loader; MCP lists every tool statically, so there is nothing to activate.",
156
+ };
157
+ /**
158
+ * Resolve the name an agent can call on the delivery host. Unknown names
159
+ * pass through unchanged (no registry identity). A known tool WITHOUT a
160
+ * mapping on the requested host resolves to `undefined` — the caller must
161
+ * omit or rephrase, never print a name the host cannot resolve.
162
+ */
163
+ export function resolveLensToolName(name, host = "pi") {
164
+ const entry = TOOL_REGISTRY.find((tool) => tool.name === name || tool.piName === name || tool.mcpName === name);
165
+ if (!entry)
166
+ return name;
167
+ if (host === "mcp")
168
+ return entry.mcpName;
169
+ return entry.piName;
170
+ }
171
+ /**
172
+ * Render already-written advisory text for the delivery host (#2535). The pi
173
+ * host reads it back unchanged. For MCP, every whole-word pi tool name with
174
+ * an MCP mapping becomes its callable MCP name (driven by TOOL_REGISTRY,
175
+ * longest first — never a hand-maintained second map), and the pi-only
176
+ * activation clause is rephrased since MCP lists every tool statically.
177
+ * A pi-only name with no MCP surface never survives translation: it is
178
+ * either rephrased here or caught by the adapter-aware guard.
179
+ */
180
+ export function translateGuidanceToolNames(content, host) {
181
+ if (host === "pi")
182
+ return content;
183
+ let text = content;
184
+ const byLength = [...TOOL_REGISTRY].sort((a, b) => (b.piName?.length ?? 0) - (a.piName?.length ?? 0));
185
+ for (const entry of byLength) {
186
+ if (typeof entry.piName !== "string" || typeof entry.mcpName !== "string") {
187
+ continue;
188
+ }
189
+ text = text.replace(new RegExp(`\\b${escapeRegExp(entry.piName)}\\b`, "g"), entry.mcpName);
190
+ }
191
+ return text.replace("activate via pi_lens_activate_tools", "call directly");
192
+ }
143
193
  export function toolRegistryEntryForPi(name) {
144
194
  return TOOL_REGISTRY.find((tool) => tool.piName === name);
145
195
  }
@@ -5,6 +5,7 @@ import { logExtension } from "./extension-log.js";
5
5
  import { isRealGitMarker, isAtOrAboveHomeDir, isUnderDir, isWindowsPath, nameMatchesMarkerGlob, normalizeEphemeralMapKey, } from "./path-utils.js";
6
6
  import { getDegradationLedgerGeneration, recordDegradationOnce, } from "./degradation-ledger.js";
7
7
  import { createGenerationMap, createGenerationSource, } from "./generation-guard.js";
8
+ import { rootMarkersForFile } from "./language-profile.js";
8
9
  export const FORMATTER_MARKERS = {
9
10
  biome: ["biome.json", "biome.jsonc", "package.json", ".gitignore"],
10
11
  prettier: [
@@ -82,70 +83,24 @@ export const FORMATTER_MARKERS = {
82
83
  "settings.gradle.kts",
83
84
  ".gitignore",
84
85
  ],
85
- };
86
- const RUNNER_MARKERS = {
87
- yamllint: [".yamllint", "yamllint.yaml", "yamllint.yml", "pyproject.toml"],
88
- ruff: ["pyproject.toml", "ruff.toml", ".ruff.toml"],
89
- "spellcheck/typos": ["_typos.toml", "typos.toml"],
90
- biome: ["biome.json", "biome.jsonc", "package.json"],
91
- oxlint: [".oxlintrc.json", "oxlint.config.js", "package.json"],
92
- sqlfluff: [".sqlfluff", "pyproject.toml", "setup.cfg"],
93
- prettier: [".prettierignore", "package.json"],
94
- // #2894: cargo must run at the package root. This is the marker walk
95
- // `rust-clippy.ts` used to do for itself with `findNearestContaining`.
96
- "rust-clippy": ["Cargo.toml"],
86
+ typstyle: [".gitignore"],
97
87
  };
98
88
  const toolCwdGeneration = createGenerationSource("tool-cwd");
99
89
  const logged = createGenerationMap("tool-cwd-resolution-log");
100
- const markerWalks = new Map();
101
- const markerWalkGenerations = createGenerationMap("tool-cwd-marker-walks");
102
- let markerWalkCount = 0;
103
- /** Pure key seam for ephemeral tool-cwd memo and log identity. */
90
+ /** Pure key seam for resolution-log and runner-advisory identity. */
104
91
  export function _toolCwdEphemeralKey(parts) {
105
92
  return parts.map(normalizeEphemeralMapKey).join("\0");
106
93
  }
107
- /** Test probe for the per-generation walk memo; not part of runtime behavior. */
108
- export function _getToolCwdMarkerWalkCount() {
109
- return markerWalkCount;
110
- }
111
94
  function syncGeneration() {
112
95
  if (toolCwdGeneration.current() === getDegradationLedgerGeneration())
113
96
  return;
114
- markerWalks.clear();
115
- markerWalkGenerations.clear();
116
97
  logged.clear();
117
98
  while (toolCwdGeneration.current() < getDegradationLedgerGeneration()) {
118
99
  toolCwdGeneration.bump();
119
100
  }
120
101
  }
121
- function findMarkerRoot(startDir, markers, homeDir) {
122
- syncGeneration();
123
- const key = _toolCwdEphemeralKey([
124
- path.resolve(startDir),
125
- ...markers,
126
- path.resolve(homeDir),
127
- ]);
128
- const cached = markerWalks.get(key);
129
- if (cached && markerWalkGenerations.current(key) !== 0) {
130
- // A negative walk is not stable: a project marker can be created after
131
- // the first resolution, so do not cache absence across calls. Positive
132
- // results remain memoized and are still revalidated when their marker is
133
- // deleted (#2894).
134
- if (!cached.marker || !cached.root) {
135
- markerWalks.delete(key);
136
- markerWalkGenerations.forget(key);
137
- }
138
- else {
139
- // #2777: a marker can disappear during a session; do not reuse a stale root.
140
- if (existsSync(path.join(cached.root, cached.marker)))
141
- return cached;
142
- markerWalks.delete(key);
143
- markerWalkGenerations.forget(key);
144
- }
145
- }
146
- markerWalkCount++;
102
+ function walkMarkerRoot(startDir, markers, homeDir) {
147
103
  let current = path.resolve(startDir);
148
- let result = { root: null };
149
104
  for (let depth = 0; depth < 64; depth++) {
150
105
  if (isAtOrAboveHomeDir(current, homeDir))
151
106
  break;
@@ -169,32 +124,27 @@ function findMarkerRoot(startDir, markers, homeDir) {
169
124
  else {
170
125
  found = existsSync(path.join(target, basename));
171
126
  }
172
- if (found) {
173
- result = { root: current, marker };
174
- markerWalks.set(key, result);
175
- markerWalkGenerations.bump(key);
176
- return result;
177
- }
127
+ if (found)
128
+ return { root: current, marker };
178
129
  }
179
130
  const parentDir = path.dirname(current);
180
131
  if (parentDir === current)
181
132
  break;
182
133
  current = parentDir;
183
134
  }
184
- markerWalks.set(key, result);
185
- markerWalkGenerations.bump(key);
186
- return result;
135
+ return { root: null };
136
+ }
137
+ function findMarkerRoot(startDir, markers, homeDir) {
138
+ syncGeneration();
139
+ return walkMarkerRoot(startDir, markers, homeDir);
187
140
  }
188
- function markersFor(kind, tool, ctx) {
141
+ function markersFor(kind, tool, file, ctx) {
189
142
  if (kind === "lsp")
190
143
  return ctx.rootMarkers ?? [];
191
- // #2871: caller-supplied markers count for runners too. `RUNNER_MARKERS`
192
- // covers the linter/formatter-shaped runners this module has always known;
193
- // a caller that owns its own marker table — the test runner, whose
194
- // `RUNNERS[x].configFiles` IS that table — passes it here rather than
195
- // registering a second copy of the same data in this file.
144
+ // #2965: runner fallback uses the language table that also anchors the
145
+ // dispatch context. A caller-owned table remains an explicit override.
196
146
  if (kind === "runner")
197
- return ctx.rootMarkers ?? RUNNER_MARKERS[tool] ?? [];
147
+ return ctx.rootMarkers ?? rootMarkersForFile(file, tool);
198
148
  return FORMATTER_MARKERS[tool] ?? [".gitignore"];
199
149
  }
200
150
  function emitResolution(kind, tool, cwd, reason) {
@@ -239,9 +189,9 @@ export function resolveToolCwd(kind, tool, file, ctx) {
239
189
  const serverRoot = rootPath.resolve(ctx.serverRoot);
240
190
  if (!ctx.suppressTelemetry)
241
191
  emitResolution(kind, tool, serverRoot, "server-root");
242
- return serverRoot;
192
+ return { cwd: serverRoot };
243
193
  }
244
- const markers = markersFor(kind, tool, ctx);
194
+ const markers = markersFor(kind, tool, absoluteFile, ctx);
245
195
  const markerResult = markers.length
246
196
  ? findMarkerRoot(fileDir, markers, ctx.allowHomeMarker ? path.parse(homeDir).root : homeDir)
247
197
  : { root: null };
@@ -251,16 +201,34 @@ export function resolveToolCwd(kind, tool, file, ctx) {
251
201
  const finalReason = `marker:${markerResult.marker ?? markers[0]}`;
252
202
  if (!ctx.suppressTelemetry)
253
203
  emitResolution(kind, tool, markerRoot, finalReason);
254
- return markerRoot;
204
+ return {
205
+ cwd: markerRoot,
206
+ ...(markerResult.marker !== undefined
207
+ ? { marker: markerResult.marker }
208
+ : {}),
209
+ };
210
+ }
211
+ const memo = ctx.toolCwdMemo;
212
+ if (memo && memo.gitRoot === undefined) {
213
+ const gitResult = findMarkerRoot(fileDir, [".git"], homeDir);
214
+ memo.gitRoot =
215
+ gitResult.root && isRealGitMarker(path.join(gitResult.root, ".git"))
216
+ ? gitResult.root
217
+ : null;
255
218
  }
256
- const gitResult = findMarkerRoot(fileDir, [".git"], homeDir);
257
- const gitRoot = gitResult.root && isRealGitMarker(path.join(gitResult.root, ".git"))
258
- ? gitResult.root
259
- : null;
219
+ const gitRoot = memo && memo.gitRoot !== undefined
220
+ ? memo.gitRoot
221
+ : (() => {
222
+ const gitResult = findMarkerRoot(fileDir, [".git"], homeDir);
223
+ return gitResult.root &&
224
+ isRealGitMarker(path.join(gitResult.root, ".git"))
225
+ ? gitResult.root
226
+ : null;
227
+ })();
260
228
  if (gitRoot && (insideDispatch ? isUnderDir(gitRoot, dispatchRoot) : true)) {
261
229
  if (!ctx.suppressTelemetry)
262
230
  emitResolution(kind, tool, gitRoot, "git-root");
263
- return gitRoot;
231
+ return { cwd: gitRoot, marker: ".git" };
264
232
  }
265
233
  if (insideDispatch) {
266
234
  if (kind === "formatter") {
@@ -273,11 +241,11 @@ export function resolveToolCwd(kind, tool, file, ctx) {
273
241
  reason: `${kind}:home-cap:${absoluteFile}`,
274
242
  });
275
243
  }
276
- return fileDir;
244
+ return { cwd: fileDir };
277
245
  }
278
246
  if (!ctx.suppressTelemetry)
279
247
  emitResolution(kind, tool, dispatchRoot, "dispatch-root");
280
- return dispatchRoot;
248
+ return { cwd: dispatchRoot };
281
249
  }
282
250
  const reason = isUnderDir(fileDir, homeDir)
283
251
  ? "file-dir-fallback"
@@ -291,9 +259,12 @@ export function resolveToolCwd(kind, tool, file, ctx) {
291
259
  });
292
260
  if (!ctx.suppressTelemetry)
293
261
  emitResolution(kind, tool, fallback, reason);
294
- return fallback;
262
+ return { cwd: fallback };
295
263
  }
296
264
  /** Runner-shaped adapter kept at the same seam for every runner consumer. */
297
265
  export function resolveRunnerCwd(ctx, tool) {
266
+ return resolveToolCwd("runner", tool, ctx.filePath, ctx).cwd;
267
+ }
268
+ export function resolveRunnerCwdWithReason(ctx, tool) {
298
269
  return resolveToolCwd("runner", tool, ctx.filePath, ctx);
299
270
  }