@herbertgao/pi-extensions 2026.8.11 → 2026.8.13

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 (476) hide show
  1. package/README.md +23 -10
  2. package/{node_modules/@herbertgao/pi-mermaid-open/LICENSE → THIRD_PARTY_NOTICES.md} +19 -1
  3. package/node_modules/@czottmann/pi-automode/CHANGELOG.md +15 -0
  4. package/node_modules/@czottmann/pi-automode/README.md +5 -3
  5. package/node_modules/@czottmann/pi-automode/docs/adr/ADR-001-permission-precedence-and-trust-boundaries.md +2 -0
  6. package/node_modules/@czottmann/pi-automode/docs/adr/ADR-002-global-config-in-extension-data-directory.md +60 -0
  7. package/node_modules/@czottmann/pi-automode/docs/adr/INDEX.md +1 -0
  8. package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +4 -4
  9. package/node_modules/@czottmann/pi-automode/docs/configuration.md +20 -4
  10. package/node_modules/@czottmann/pi-automode/docs/observability-logging.md +1 -1
  11. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/bash.ts +692 -0
  12. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +181 -3
  13. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +4 -1
  14. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +143 -36
  15. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/hard-deny.ts +103 -148
  16. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/paths.ts +32 -6
  17. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/permissions.ts +344 -22
  18. package/node_modules/@czottmann/pi-automode/extensions/auto-mode.ts +1 -0
  19. package/node_modules/@czottmann/pi-automode/package.json +4 -1
  20. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +2 -1
  21. package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -1
  22. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +4 -0
  23. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +21 -1
  24. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/agent-summary/core.ts +1 -1
  25. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +19 -19
  26. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +4 -2
  27. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +2 -1
  28. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +10 -2
  29. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  30. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +10 -0
  31. package/node_modules/@herbertgao/pi-subagents/README.md +21 -15
  32. package/node_modules/@herbertgao/pi-subagents/package.json +3 -3
  33. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +11 -8
  34. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +184 -106
  35. package/node_modules/@herbertgao/pi-subagents/src/cross-extension-rpc.ts +31 -11
  36. package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +9 -1
  37. package/node_modules/@herbertgao/pi-subagents/src/index.ts +156 -31
  38. package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +17 -0
  39. package/node_modules/@herbertgao/pi-subagents/src/model-resolver.ts +14 -0
  40. package/node_modules/@herbertgao/pi-subagents/src/schedule.ts +8 -0
  41. package/node_modules/@herbertgao/pi-subagents/src/settings.ts +32 -1
  42. package/node_modules/@herbertgao/pi-subagents/src/types.ts +17 -2
  43. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +23 -2
  44. package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +259 -24
  45. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  46. package/node_modules/@luxusai/pi-hindsight/CHANGELOG.md +376 -0
  47. package/node_modules/@luxusai/pi-hindsight/README.md +92 -0
  48. package/node_modules/@luxusai/pi-hindsight/docs/adr/001-memory-lifecycle-and-scope.md +56 -0
  49. package/node_modules/@luxusai/pi-hindsight/docs/adr/002-explicit-routing-strategy-seam.md +169 -0
  50. package/node_modules/@luxusai/pi-hindsight/docs/adr/003-tui-memory-mode-vocabulary.md +107 -0
  51. package/node_modules/@luxusai/pi-hindsight/docs/adr/004-lifeos-dual-bank-design.md +89 -0
  52. package/node_modules/@luxusai/pi-hindsight/docs/adr/005-domain-banks-and-agent-first-surface.md +189 -0
  53. package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark.webp +0 -0
  54. package/node_modules/@luxusai/pi-hindsight/docs/assets/logos/pi-hindsight-logo-dark@2x.webp +0 -0
  55. package/node_modules/@luxusai/pi-hindsight/docs/coding-memory-evaluation.md +54 -0
  56. package/node_modules/@luxusai/pi-hindsight/docs/compatibility.md +75 -0
  57. package/node_modules/@luxusai/pi-hindsight/docs/hindsight-core-functions.md +300 -0
  58. package/node_modules/@luxusai/pi-hindsight/docs/mission-and-mental-model-quality.md +158 -0
  59. package/node_modules/@luxusai/pi-hindsight/docs/next-opt-out-design.md +164 -0
  60. package/node_modules/@luxusai/pi-hindsight/docs/risky-memory-modes.md +139 -0
  61. package/node_modules/@luxusai/pi-hindsight/docs/starter-mental-model-suggestions.md +74 -0
  62. package/node_modules/@luxusai/pi-hindsight/docs/surface-reference.md +261 -0
  63. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-operations.ts +151 -0
  64. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-selection.ts +18 -0
  65. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-settings-presenter.ts +46 -0
  66. package/node_modules/@luxusai/pi-hindsight/extensions/banks/bank-templates.ts +383 -0
  67. package/node_modules/@luxusai/pi-hindsight/extensions/banks/banking.ts +240 -0
  68. package/node_modules/@luxusai/pi-hindsight/extensions/banks/knowledge-page-seed.ts +176 -0
  69. package/node_modules/@luxusai/pi-hindsight/extensions/banks/retain-strategies.ts +178 -0
  70. package/node_modules/@luxusai/pi-hindsight/extensions/client/client-retry.ts +41 -0
  71. package/node_modules/@luxusai/pi-hindsight/extensions/client/client.ts +386 -0
  72. package/node_modules/@luxusai/pi-hindsight/extensions/client/fetch-compat.ts +39 -0
  73. package/node_modules/@luxusai/pi-hindsight/extensions/client/timeout.ts +34 -0
  74. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-defaults.ts +140 -0
  75. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-model.ts +61 -0
  76. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-editing-registry.ts +925 -0
  77. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-field-paths.ts +247 -0
  78. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-normalize.ts +547 -0
  79. package/node_modules/@luxusai/pi-hindsight/extensions/config/config-writer.ts +480 -0
  80. package/node_modules/@luxusai/pi-hindsight/extensions/config/config.ts +182 -0
  81. package/node_modules/@luxusai/pi-hindsight/extensions/config/setup-gate.ts +86 -0
  82. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-execute.ts +1010 -0
  83. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-parse.ts +175 -0
  84. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-plan.ts +425 -0
  85. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-presentation.ts +210 -0
  86. package/node_modules/@luxusai/pi-hindsight/extensions/imports/import-sessions.ts +817 -0
  87. package/node_modules/@luxusai/pi-hindsight/extensions/index.ts +25 -0
  88. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/git-seed.ts +319 -0
  89. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-recall.ts +196 -0
  90. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-retain.ts +189 -0
  91. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle-runtime.ts +65 -0
  92. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/memory-lifecycle.ts +260 -0
  93. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/mental-models.ts +244 -0
  94. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/observation-scopes.ts +59 -0
  95. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-cleanup.ts +82 -0
  96. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall-visibility.ts +45 -0
  97. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/recall.ts +331 -0
  98. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-cursor.ts +354 -0
  99. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-job-builder.ts +66 -0
  100. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain-receipts.ts +132 -0
  101. package/node_modules/@luxusai/pi-hindsight/extensions/lifecycle/retain.ts +228 -0
  102. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-bank-template-operations.ts +74 -0
  103. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-config-operations.ts +16 -0
  104. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-control-operations.ts +648 -0
  105. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-diagnostics-operations.ts +105 -0
  106. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-identity.ts +68 -0
  107. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-service.ts +71 -0
  108. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-operation-types.ts +13 -0
  109. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-recall-operations.ts +162 -0
  110. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-retain-operations.ts +131 -0
  111. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-scope.ts +104 -0
  112. package/node_modules/@luxusai/pi-hindsight/extensions/operations/memory-session-operations.ts +37 -0
  113. package/node_modules/@luxusai/pi-hindsight/extensions/operations/operation-catalog.ts +893 -0
  114. package/node_modules/@luxusai/pi-hindsight/extensions/operations/reflect-presenter.ts +35 -0
  115. package/node_modules/@luxusai/pi-hindsight/extensions/operations/scope-migrate.ts +177 -0
  116. package/node_modules/@luxusai/pi-hindsight/extensions/operations/tools.ts +7 -0
  117. package/node_modules/@luxusai/pi-hindsight/extensions/queue/flush-presenter.ts +21 -0
  118. package/node_modules/@luxusai/pi-hindsight/extensions/queue/jsonl-queue-store.ts +112 -0
  119. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-delivery.ts +111 -0
  120. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-lock.ts +214 -0
  121. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue-operations.ts +70 -0
  122. package/node_modules/@luxusai/pi-hindsight/extensions/queue/queue.ts +392 -0
  123. package/node_modules/@luxusai/pi-hindsight/extensions/tui/bank-template-presentation.ts +45 -0
  124. package/node_modules/@luxusai/pi-hindsight/extensions/tui/commands.ts +9 -0
  125. package/node_modules/@luxusai/pi-hindsight/extensions/tui/guided-setup.ts +860 -0
  126. package/node_modules/@luxusai/pi-hindsight/extensions/tui/prefill-input.ts +105 -0
  127. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-flow.ts +189 -0
  128. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-server-probe.ts +299 -0
  129. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-actions.ts +201 -0
  130. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-facts.ts +47 -0
  131. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-render.ts +239 -0
  132. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui-types.ts +50 -0
  133. package/node_modules/@luxusai/pi-hindsight/extensions/tui/setup-tui.ts +259 -0
  134. package/node_modules/@luxusai/pi-hindsight/extensions/tui/tool-presenters.ts +77 -0
  135. package/node_modules/@luxusai/pi-hindsight/extensions/types.ts +534 -0
  136. package/node_modules/@luxusai/pi-hindsight/extensions/utils/diagnostics.ts +319 -0
  137. package/node_modules/@luxusai/pi-hindsight/extensions/utils/messages.ts +325 -0
  138. package/node_modules/@luxusai/pi-hindsight/extensions/utils/sanitize.ts +42 -0
  139. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-memory-meta.ts +244 -0
  140. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session-operations.ts +56 -0
  141. package/node_modules/@luxusai/pi-hindsight/extensions/utils/session.ts +50 -0
  142. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-fields.ts +167 -0
  143. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status-health.ts +207 -0
  144. package/node_modules/@luxusai/pi-hindsight/extensions/utils/status.ts +120 -0
  145. package/node_modules/@luxusai/pi-hindsight/extensions/version.ts +8 -0
  146. package/node_modules/@luxusai/pi-hindsight/package.json +118 -0
  147. package/node_modules/@luxusai/pi-hindsight/skills/hindsight-memory-doctor/SKILL.md +75 -0
  148. package/node_modules/@narumitw/pi-btw/dist/index.ts +143 -46
  149. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +3 -3
  150. package/node_modules/@narumitw/pi-btw/package.json +6 -6
  151. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +136 -22
  152. package/node_modules/{@herbertgao → @tifan}/pi-copy-response/README.md +2 -4
  153. package/node_modules/{@herbertgao → @tifan}/pi-copy-response/package.json +5 -15
  154. package/node_modules/{@herbertgao → @tifan}/pi-handoff/README.md +4 -6
  155. package/node_modules/@tifan/pi-handoff/package.json +43 -0
  156. package/node_modules/{@herbertgao → @tifan}/pi-handoff/src/index.ts +1 -1
  157. package/node_modules/{@herbertgao → @tifan}/pi-inline-skills/README.md +2 -4
  158. package/node_modules/{@herbertgao → @tifan}/pi-inline-skills/package.json +5 -15
  159. package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/README.md +5 -7
  160. package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/package.json +5 -19
  161. package/node_modules/{@herbertgao → @tifan}/pi-preferred-thinking/README.md +4 -6
  162. package/node_modules/{@herbertgao → @tifan}/pi-preferred-thinking/package.json +6 -16
  163. package/node_modules/{@herbertgao → @tifan}/pi-preferred-thinking/src/index.ts +1 -6
  164. package/node_modules/{@herbertgao → @tifan}/pi-recap/README.md +4 -6
  165. package/node_modules/@tifan/pi-recap/package.json +42 -0
  166. package/node_modules/{@herbertgao → @tifan}/pi-recap/src/models.ts +1 -6
  167. package/node_modules/{@herbertgao → @tifan}/pi-rename/README.md +13 -8
  168. package/node_modules/@tifan/pi-rename/package.json +47 -0
  169. package/node_modules/@tifan/pi-rename/src/herdr-label.ts +4 -0
  170. package/node_modules/{@herbertgao → @tifan}/pi-rename/src/index.ts +4 -16
  171. package/node_modules/{@herbertgao → @tifan}/pi-rename/src/models.ts +1 -6
  172. package/node_modules/{@herbertgao → @tifan}/pi-titlebar-spinner/README.md +2 -4
  173. package/node_modules/{@herbertgao → @tifan}/pi-titlebar-spinner/package.json +5 -15
  174. package/node_modules/pi-lens/CHANGELOG.md +96 -1
  175. package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +2 -1
  176. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +14 -5
  177. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +48 -18
  178. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +1 -3
  179. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +16 -4
  180. package/node_modules/pi-lens/dist/clients/bash-file-access.js +3 -1
  181. package/node_modules/pi-lens/dist/clients/biome-client.js +1 -3
  182. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +21 -8
  183. package/node_modules/pi-lens/dist/clients/bounded-cache.js +24 -8
  184. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +4 -3
  185. package/node_modules/pi-lens/dist/clients/cache-manager.js +6 -7
  186. package/node_modules/pi-lens/dist/clients/cache-observability.js +461 -66
  187. package/node_modules/pi-lens/dist/clients/call-graph.js +238 -63
  188. package/node_modules/pi-lens/dist/clients/codebase-model.js +13 -5
  189. package/node_modules/pi-lens/dist/clients/complexity-client.js +1 -3
  190. package/node_modules/pi-lens/dist/clients/dead-code-client.js +19 -8
  191. package/node_modules/pi-lens/dist/clients/dead-code-logger.js +1 -2
  192. package/node_modules/pi-lens/dist/clients/deadline-utils.js +3 -1
  193. package/node_modules/pi-lens/dist/clients/debug-heap.js +8 -1
  194. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +1 -1
  195. package/node_modules/pi-lens/dist/clients/dependency-checker.js +11 -7
  196. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +39 -2
  197. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +5 -1
  198. package/node_modules/pi-lens/dist/clients/dispatch/auxiliary-lsp.js +2 -3
  199. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +13 -1
  200. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +3 -1
  201. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +2 -1
  202. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +1 -1
  203. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +9 -4
  204. package/node_modules/pi-lens/dist/clients/dispatch/rules/error-swallowing.js +3 -1
  205. package/node_modules/pi-lens/dist/clients/dispatch/rules/pass-through-wrappers.js +6 -2
  206. package/node_modules/pi-lens/dist/clients/dispatch/rules/unsafe-boundary.js +31 -7
  207. package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +5 -2
  208. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +10 -14
  209. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +5 -1
  210. package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +1 -1
  211. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +3 -1
  212. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +25 -6
  213. package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +1 -1
  214. package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +1 -1
  215. package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +3 -1
  216. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +13 -8
  217. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +4 -1
  218. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +25 -10
  219. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +1 -1
  220. package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +1 -1
  221. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +1 -1
  222. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +28 -4
  223. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +6 -8
  224. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +212 -11
  225. package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +1 -1
  226. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +8 -4
  227. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +10 -6
  228. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +23 -14
  229. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +1 -1
  230. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +7 -9
  231. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +5 -2
  232. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +7 -7
  233. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +6 -8
  234. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +13 -8
  235. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +13 -8
  236. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +17 -3
  237. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +7 -1
  238. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +24 -1
  239. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +35 -0
  240. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +1 -3
  241. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +6 -8
  242. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +1 -1
  243. package/node_modules/pi-lens/dist/clients/dispatch/suppress-writer.js +2 -1
  244. package/node_modules/pi-lens/dist/clients/dispatch/types.js +6 -1
  245. package/node_modules/pi-lens/dist/clients/dispatch/utils/lsp-diagnostics.js +6 -2
  246. package/node_modules/pi-lens/dist/clients/extension-log.js +5 -3
  247. package/node_modules/pi-lens/dist/clients/feature-hints.js +8 -1
  248. package/node_modules/pi-lens/dist/clients/file-kinds.js +34 -129
  249. package/node_modules/pi-lens/dist/clients/file-utils.js +17 -1
  250. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +57 -2
  251. package/node_modules/pi-lens/dist/clients/formatters.js +144 -27
  252. package/node_modules/pi-lens/dist/clients/freshness.js +38 -0
  253. package/node_modules/pi-lens/dist/clients/git-guard.js +43 -13
  254. package/node_modules/pi-lens/dist/clients/go-client.js +1 -3
  255. package/node_modules/pi-lens/dist/clients/grammar-source.js +1 -1
  256. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +30 -4
  257. package/node_modules/pi-lens/dist/clients/host-edit-normalize.js +1 -3
  258. package/node_modules/pi-lens/dist/clients/install-diagnostics.js +4 -2
  259. package/node_modules/pi-lens/dist/clients/installer/index.js +86 -77
  260. package/node_modules/pi-lens/dist/clients/instance-reaper.js +5 -2
  261. package/node_modules/pi-lens/dist/clients/instance-registry.js +4 -2
  262. package/node_modules/pi-lens/dist/clients/jscpd-client.js +6 -1
  263. package/node_modules/pi-lens/dist/clients/knip-client.js +29 -15
  264. package/node_modules/pi-lens/dist/clients/language-profile.js +4 -1
  265. package/node_modules/pi-lens/dist/clients/latency-logger.js +13 -2
  266. package/node_modules/pi-lens/dist/clients/lens-config.js +1 -1
  267. package/node_modules/pi-lens/dist/clients/lens-map.js +8 -3
  268. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +1 -1
  269. package/node_modules/pi-lens/dist/clients/lsp/config.js +4 -6
  270. package/node_modules/pi-lens/dist/clients/lsp/edits.js +119 -32
  271. package/node_modules/pi-lens/dist/clients/lsp/index.js +94 -35
  272. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +2 -1
  273. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +4 -1
  274. package/node_modules/pi-lens/dist/clients/lsp/launch.js +11 -3
  275. package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +152 -0
  276. package/node_modules/pi-lens/dist/clients/lsp/server.js +19 -7
  277. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +10 -2
  278. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +9 -4
  279. package/node_modules/pi-lens/dist/clients/lsp-document-symbols.js +1 -3
  280. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +10 -20
  281. package/node_modules/pi-lens/dist/clients/mcp/host-shim.js +1 -1
  282. package/node_modules/pi-lens/dist/clients/memory-sampler.js +73 -7
  283. package/node_modules/pi-lens/dist/clients/metrics-client.js +1 -3
  284. package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +8 -3
  285. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +7 -1
  286. package/node_modules/pi-lens/dist/clients/module-report.js +14 -17
  287. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +3 -5
  288. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +220 -0
  289. package/node_modules/pi-lens/dist/clients/package-manager.js +6 -1
  290. package/node_modules/pi-lens/dist/clients/pipeline.js +57 -9
  291. package/node_modules/pi-lens/dist/clients/project-conventions.js +2 -8
  292. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +10 -7
  293. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +2 -1
  294. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +3 -1
  295. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +13 -9
  296. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +3 -1
  297. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +5 -2
  298. package/node_modules/pi-lens/dist/clients/project-lens-config.js +12 -5
  299. package/node_modules/pi-lens/dist/clients/project-snapshot-fingerprint.js +48 -0
  300. package/node_modules/pi-lens/dist/clients/project-snapshot-persist-worker.js +15 -1
  301. package/node_modules/pi-lens/dist/clients/project-snapshot.js +472 -66
  302. package/node_modules/pi-lens/dist/clients/read-expansion.js +12 -2
  303. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +5 -4
  304. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +5 -2
  305. package/node_modules/pi-lens/dist/clients/read-guard.js +1 -1
  306. package/node_modules/pi-lens/dist/clients/resource-sampler.js +1 -1
  307. package/node_modules/pi-lens/dist/clients/reverse-deps.js +6 -5
  308. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +42 -17
  309. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +8 -2
  310. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +10 -1
  311. package/node_modules/pi-lens/dist/clients/review-graph/query.js +2 -1
  312. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +4 -2
  313. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +2 -2
  314. package/node_modules/pi-lens/dist/clients/ruff-client.js +6 -5
  315. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +63 -31
  316. package/node_modules/pi-lens/dist/clients/runtime-context.js +12 -4
  317. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +83 -4
  318. package/node_modules/pi-lens/dist/clients/runtime-session.js +14 -0
  319. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +59 -3
  320. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +148 -34
  321. package/node_modules/pi-lens/dist/clients/runtime-turn.js +147 -6
  322. package/node_modules/pi-lens/dist/clients/rust-client.js +1 -3
  323. package/node_modules/pi-lens/dist/clients/safe-spawn.js +150 -11
  324. package/node_modules/pi-lens/dist/clients/security-scan-client.js +1 -3
  325. package/node_modules/pi-lens/dist/clients/session-summary.js +3 -1
  326. package/node_modules/pi-lens/dist/clients/sg-runner.js +1 -3
  327. package/node_modules/pi-lens/dist/clients/source-filter.js +10 -6
  328. package/node_modules/pi-lens/dist/clients/source-walker.js +1 -1
  329. package/node_modules/pi-lens/dist/clients/spawn-timeout-cooldown.js +96 -0
  330. package/node_modules/pi-lens/dist/clients/startup-scan.js +4 -1
  331. package/node_modules/pi-lens/dist/clients/tool-definition.js +7 -0
  332. package/node_modules/pi-lens/dist/clients/tool-policy.js +26 -11
  333. package/node_modules/pi-lens/dist/clients/tool-render.js +2 -1
  334. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +10 -4
  335. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +2 -2
  336. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +12 -5
  337. package/node_modules/pi-lens/dist/clients/warm-attach.js +12 -5
  338. package/node_modules/pi-lens/dist/clients/widget-state.js +27 -11
  339. package/node_modules/pi-lens/dist/clients/word-index.js +3 -1
  340. package/node_modules/pi-lens/dist/clients/workspace-topology.js +8 -2
  341. package/node_modules/pi-lens/dist/clients/zizmor-config.js +9 -1
  342. package/node_modules/pi-lens/dist/i18n.js +13 -5
  343. package/node_modules/pi-lens/dist/index.js +10797 -8627
  344. package/node_modules/pi-lens/dist/mcp/server.js +3 -1
  345. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +68 -12
  346. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +21 -7
  347. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +164 -35
  348. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +24 -7
  349. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +3 -1
  350. package/node_modules/pi-lens/dist/tools/module-report.js +1 -1
  351. package/node_modules/pi-lens/dist/tools/project-report.js +1 -1
  352. package/node_modules/pi-lens/dist/tools/symbol-search.js +5 -2
  353. package/node_modules/pi-lens/docs/durable-store-audit-1202.md +1 -1
  354. package/node_modules/pi-lens/docs/servercapabilities.md +1 -1
  355. package/node_modules/pi-lens/package.json +160 -156
  356. package/node_modules/pi-lens/rules/typos/_typos.toml +2 -2
  357. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +31 -13
  358. package/node_modules/pi-lens/scripts/download-grammars.js +9 -3
  359. package/node_modules/pi-lens/scripts/rpc-load-check.mjs +30 -9
  360. package/node_modules/pi-mcp-adapter/CHANGELOG.md +47 -0
  361. package/node_modules/pi-mcp-adapter/README.md +42 -13
  362. package/node_modules/pi-mcp-adapter/commands.ts +4 -2
  363. package/node_modules/pi-mcp-adapter/config.ts +45 -5
  364. package/node_modules/pi-mcp-adapter/direct-tools.ts +103 -92
  365. package/node_modules/pi-mcp-adapter/dist/agent-dir.d.ts +10 -0
  366. package/node_modules/pi-mcp-adapter/dist/agent-dir.js +63 -0
  367. package/node_modules/pi-mcp-adapter/dist/agent-dir.js.map +1 -0
  368. package/node_modules/pi-mcp-adapter/dist/agent-plugin-loader.d.ts +8 -0
  369. package/node_modules/pi-mcp-adapter/dist/agent-plugin-loader.js +356 -0
  370. package/node_modules/pi-mcp-adapter/dist/agent-plugin-loader.js.map +1 -0
  371. package/node_modules/pi-mcp-adapter/dist/config.d.ts +123 -0
  372. package/node_modules/pi-mcp-adapter/dist/config.js +1087 -0
  373. package/node_modules/pi-mcp-adapter/dist/config.js.map +1 -0
  374. package/node_modules/pi-mcp-adapter/dist/metadata-cache.d.ts +19 -0
  375. package/node_modules/pi-mcp-adapter/dist/metadata-cache.js +319 -0
  376. package/node_modules/pi-mcp-adapter/dist/metadata-cache.js.map +1 -0
  377. package/node_modules/pi-mcp-adapter/dist/package-mcp-loader.d.ts +2 -0
  378. package/node_modules/pi-mcp-adapter/dist/package-mcp-loader.js +156 -0
  379. package/node_modules/pi-mcp-adapter/dist/package-mcp-loader.js.map +1 -0
  380. package/node_modules/pi-mcp-adapter/dist/resource-tools.d.ts +1 -0
  381. package/node_modules/pi-mcp-adapter/dist/resource-tools.js +15 -0
  382. package/node_modules/pi-mcp-adapter/dist/resource-tools.js.map +1 -0
  383. package/node_modules/pi-mcp-adapter/dist/types.d.ts +564 -0
  384. package/node_modules/pi-mcp-adapter/dist/types.js +287 -0
  385. package/node_modules/pi-mcp-adapter/dist/types.js.map +1 -0
  386. package/node_modules/pi-mcp-adapter/dist/ui-app-bridge-helpers.d.ts +6 -0
  387. package/node_modules/pi-mcp-adapter/dist/ui-app-bridge-helpers.js +37 -0
  388. package/node_modules/pi-mcp-adapter/dist/ui-app-bridge-helpers.js.map +1 -0
  389. package/node_modules/pi-mcp-adapter/dist/ui-stream-types.d.ts +104 -0
  390. package/node_modules/pi-mcp-adapter/dist/ui-stream-types.js +59 -0
  391. package/node_modules/pi-mcp-adapter/dist/ui-stream-types.js.map +1 -0
  392. package/node_modules/pi-mcp-adapter/dist/ui-tool-visibility.d.ts +4 -0
  393. package/node_modules/pi-mcp-adapter/dist/ui-tool-visibility.js +27 -0
  394. package/node_modules/pi-mcp-adapter/dist/ui-tool-visibility.js.map +1 -0
  395. package/node_modules/pi-mcp-adapter/dist/utils.d.ts +32 -0
  396. package/node_modules/pi-mcp-adapter/dist/utils.js +338 -0
  397. package/node_modules/pi-mcp-adapter/dist/utils.js.map +1 -0
  398. package/node_modules/pi-mcp-adapter/failure-backoff.ts +23 -0
  399. package/node_modules/pi-mcp-adapter/index.ts +204 -82
  400. package/node_modules/pi-mcp-adapter/init.ts +41 -30
  401. package/node_modules/pi-mcp-adapter/lifecycle.ts +16 -8
  402. package/node_modules/pi-mcp-adapter/mcp-code.ts +2 -0
  403. package/node_modules/pi-mcp-adapter/mcp-oauth-provider.ts +66 -16
  404. package/node_modules/pi-mcp-adapter/mcp-output-guard.ts +95 -7
  405. package/node_modules/pi-mcp-adapter/mcp-probe.ts +18 -4
  406. package/node_modules/pi-mcp-adapter/mcp-references.ts +368 -0
  407. package/node_modules/pi-mcp-adapter/mcp-status.ts +8 -19
  408. package/node_modules/pi-mcp-adapter/metadata-cache.ts +20 -12
  409. package/node_modules/pi-mcp-adapter/namespace-tools.ts +276 -0
  410. package/node_modules/pi-mcp-adapter/package.json +24 -6
  411. package/node_modules/pi-mcp-adapter/proxy-modes.ts +66 -10
  412. package/node_modules/pi-mcp-adapter/search-ranking.ts +2 -0
  413. package/node_modules/pi-mcp-adapter/server-manager.ts +63 -12
  414. package/node_modules/pi-mcp-adapter/state.ts +1 -3
  415. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +16 -2
  416. package/node_modules/pi-mcp-adapter/types.ts +48 -1
  417. package/node_modules/pi-mcp-adapter/ui-server.ts +3 -19
  418. package/node_modules/pi-mcp-adapter/ui-session.ts +2 -1
  419. package/node_modules/pi-mcp-adapter/utils.ts +21 -19
  420. package/node_modules/pi-web-access/CHANGELOG.md +26 -0
  421. package/node_modules/pi-web-access/README.md +71 -14
  422. package/node_modules/pi-web-access/chrome-cookies.ts +115 -35
  423. package/node_modules/pi-web-access/credential-source.ts +6 -2
  424. package/node_modules/pi-web-access/curator-page.ts +5 -3
  425. package/node_modules/pi-web-access/curator-server.ts +2 -1
  426. package/node_modules/pi-web-access/extract.ts +89 -9
  427. package/node_modules/pi-web-access/fetch-params.ts +13 -0
  428. package/node_modules/pi-web-access/gemini-adc.ts +298 -0
  429. package/node_modules/pi-web-access/gemini-api.ts +59 -15
  430. package/node_modules/pi-web-access/gemini-search.ts +58 -18
  431. package/node_modules/pi-web-access/gemini-url-context.ts +3 -2
  432. package/node_modules/pi-web-access/gemini-web-config.ts +57 -7
  433. package/node_modules/pi-web-access/gemini-web.ts +9 -3
  434. package/node_modules/pi-web-access/github-api.ts +5 -4
  435. package/node_modules/pi-web-access/github-issue-pr.ts +700 -0
  436. package/node_modules/pi-web-access/index.ts +403 -297
  437. package/node_modules/pi-web-access/kimi-search.ts +234 -0
  438. package/node_modules/pi-web-access/openai-search.ts +118 -21
  439. package/node_modules/pi-web-access/package.json +3 -2
  440. package/node_modules/pi-web-access/ssrf-protection.ts +4 -1
  441. package/node_modules/pi-web-access/utils.ts +307 -1
  442. package/node_modules/pi-web-access/youtube-extract.ts +2 -2
  443. package/package.json +46 -37
  444. package/node_modules/@herbertgao/pi-copy-response/CHANGELOG.md +0 -49
  445. package/node_modules/@herbertgao/pi-copy-response/LICENSE +0 -22
  446. package/node_modules/@herbertgao/pi-handoff/CHANGELOG.md +0 -83
  447. package/node_modules/@herbertgao/pi-handoff/LICENSE +0 -22
  448. package/node_modules/@herbertgao/pi-handoff/package.json +0 -60
  449. package/node_modules/@herbertgao/pi-inline-skills/CHANGELOG.md +0 -57
  450. package/node_modules/@herbertgao/pi-inline-skills/LICENSE +0 -22
  451. package/node_modules/@herbertgao/pi-mermaid-open/CHANGELOG.md +0 -39
  452. package/node_modules/@herbertgao/pi-preferred-thinking/CHANGELOG.md +0 -63
  453. package/node_modules/@herbertgao/pi-preferred-thinking/LICENSE +0 -22
  454. package/node_modules/@herbertgao/pi-recap/CHANGELOG.md +0 -101
  455. package/node_modules/@herbertgao/pi-recap/LICENSE +0 -22
  456. package/node_modules/@herbertgao/pi-recap/package.json +0 -55
  457. package/node_modules/@herbertgao/pi-rename/CHANGELOG.md +0 -49
  458. package/node_modules/@herbertgao/pi-rename/LICENSE +0 -22
  459. package/node_modules/@herbertgao/pi-rename/package.json +0 -63
  460. package/node_modules/@herbertgao/pi-titlebar-spinner/CHANGELOG.md +0 -25
  461. package/node_modules/@herbertgao/pi-titlebar-spinner/LICENSE +0 -22
  462. /package/node_modules/{@herbertgao → @tifan}/pi-copy-response/src/index.ts +0 -0
  463. /package/node_modules/{@herbertgao → @tifan}/pi-handoff/src/complete-text.ts +0 -0
  464. /package/node_modules/{@herbertgao → @tifan}/pi-handoff/src/session-query.ts +0 -0
  465. /package/node_modules/{@herbertgao → @tifan}/pi-inline-skills/src/index.ts +0 -0
  466. /package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/herdr-plugin/herdr-plugin.toml +0 -0
  467. /package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/herdr-plugin/viewer.mjs +0 -0
  468. /package/node_modules/{@herbertgao → @tifan}/pi-mermaid-open/src/index.ts +0 -0
  469. /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/index.ts +0 -0
  470. /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/model-picker.ts +0 -0
  471. /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/sanitize.ts +0 -0
  472. /package/node_modules/{@herbertgao → @tifan}/pi-recap/src/tui.ts +0 -0
  473. /package/node_modules/{@herbertgao → @tifan}/pi-rename/src/model-picker.ts +0 -0
  474. /package/node_modules/{@herbertgao → @tifan}/pi-rename/src/naming.ts +0 -0
  475. /package/node_modules/{@herbertgao → @tifan}/pi-rename/src/sanitize.ts +0 -0
  476. /package/node_modules/{@herbertgao → @tifan}/pi-titlebar-spinner/src/index.ts +0 -0
@@ -1257,7 +1257,9 @@ async function callTool(name, args) {
1257
1257
  `LSP: ${aliveClients} alive client(s)`,
1258
1258
  ...servers.flatMap((server) => [
1259
1259
  ` ${server.connected ? "✓" : "✗"} ${server.serverId} (${server.root})`,
1260
- ...server.pullFailureHistory.slice(-1).map((failure) => ` ⚠ diagnostics pull failed: ${failure.method}${failure.code !== undefined ? ` (${failure.code})` : ""} — ${failure.message.length > 200 ? `${failure.message.slice(0, 200)}…` : failure.message}`),
1260
+ ...server.pullFailureHistory
1261
+ .slice(-1)
1262
+ .map((failure) => ` ⚠ diagnostics pull failed: ${failure.method}${failure.code !== undefined ? ` (${failure.code})` : ""} — ${failure.message.length > 200 ? `${failure.message.slice(0, 200)}…` : failure.message}`),
1261
1263
  ]),
1262
1264
  ...renderLspBrokenStatusLines(brokenServers),
1263
1265
  ...renderDegradationLines(degradations),
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { Type } from "../clients/deps/typebox.js";
7
7
  import { astGrepRemediationHint, classifyAstGrepError, logAstGrepToolEvent, } from "../clients/ast-grep-tool-logger.js";
8
- import { hasStructuralIntent, synthesizeReplaceRule } from "../clients/ast-grep-yaml-synth.js";
8
+ import { hasStructuralIntent, synthesizeReplaceRule, } from "../clients/ast-grep-yaml-synth.js";
9
9
  import { compactRenderResult } from "./render-compact.js";
10
10
  /**
11
11
  * Build the agent-facing error text, appending a remediation hint derived from
@@ -66,15 +66,21 @@ export function createAstGrepReplaceTool(astGrepClient) {
66
66
  description: "Target language",
67
67
  }),
68
68
  paths: Type.Optional(Type.Array(Type.String(), { description: "Specific files/folders" })),
69
- insideKind: Type.Optional(Type.String({ description: "Restrict matches to nodes inside an ancestor of this AST node kind. Synthesizes a YAML rule." })),
69
+ insideKind: Type.Optional(Type.String({
70
+ description: "Restrict matches to nodes inside an ancestor of this AST node kind. Synthesizes a YAML rule.",
71
+ })),
70
72
  hasKind: Type.Optional(Type.String({
71
73
  description: 'Restrict matches to nodes whose immediate child has this AST node kind (ast-grep default stopBy: neighbor). Example: `hasKind: "await_expression"`.',
72
74
  })),
73
75
  hasDescendantKind: Type.Optional(Type.String({
74
76
  description: "Restrict matches to nodes containing this AST node kind anywhere in their descendants. Explicit recursive form (`stopBy: end`); use this instead of `hasKind` when nesting is not immediate.",
75
77
  })),
76
- follows: Type.Optional(Type.String({ description: "Restrict matches to nodes that immediately follow a sibling matching this pattern." })),
77
- precedes: Type.Optional(Type.String({ description: "Restrict matches to nodes that immediately precede a sibling matching this pattern." })),
78
+ follows: Type.Optional(Type.String({
79
+ description: "Restrict matches to nodes that immediately follow a sibling matching this pattern.",
80
+ })),
81
+ precedes: Type.Optional(Type.String({
82
+ description: "Restrict matches to nodes that immediately precede a sibling matching this pattern.",
83
+ })),
78
84
  apply: Type.Optional(Type.Boolean({ description: "Apply changes (default: false)" })),
79
85
  strictness: Type.Optional(Type.String({
80
86
  enum: ["smart", "relaxed", "ast", "cst", "signature", "template"],
@@ -83,7 +89,7 @@ export function createAstGrepReplaceTool(astGrepClient) {
83
89
  }),
84
90
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
85
91
  const startedAt = Date.now();
86
- const { pattern, rewrite, paths, apply, strictness, insideKind, hasKind, hasDescendantKind, follows, precedes } = params;
92
+ const { pattern, rewrite, paths, apply, strictness, insideKind, hasKind, hasDescendantKind, follows, precedes, } = params;
87
93
  const lang = (params.lang ?? "").replace(/^"|"$/g, "");
88
94
  const pathsCount = paths?.length ?? 1;
89
95
  const applyFlag = apply ?? false;
@@ -127,27 +133,77 @@ export function createAstGrepReplaceTool(astGrepClient) {
127
133
  }
128
134
  const searchPaths = paths?.length ? paths : [ctx.cwd || "."];
129
135
  // Phase 3: structural-intent params → synthesize YAML with fix: field
130
- if (hasStructuralIntent({ insideKind, hasKind, hasDescendantKind, follows, precedes })) {
136
+ if (hasStructuralIntent({
137
+ insideKind,
138
+ hasKind,
139
+ hasDescendantKind,
140
+ follows,
141
+ precedes,
142
+ })) {
131
143
  let ruleYaml;
132
144
  try {
133
- ruleYaml = synthesizeReplaceRule({ pattern, lang, rewrite, insideKind, hasKind, hasDescendantKind, follows, precedes });
145
+ ruleYaml = synthesizeReplaceRule({
146
+ pattern,
147
+ lang,
148
+ rewrite,
149
+ insideKind,
150
+ hasKind,
151
+ hasDescendantKind,
152
+ follows,
153
+ precedes,
154
+ });
134
155
  }
135
156
  catch (err) {
136
157
  logOutcome("error", { errorRaw: String(err) });
137
- return { content: [{ type: "text", text: `Error synthesizing rule: ${err}` }], isError: true, details: {} };
158
+ return {
159
+ content: [
160
+ {
161
+ type: "text",
162
+ text: `Error synthesizing rule: ${err}`,
163
+ },
164
+ ],
165
+ isError: true,
166
+ details: {},
167
+ };
138
168
  }
139
169
  const ruleResult = await astGrepClient.replaceWithRule(ruleYaml, searchPaths, applyFlag);
140
170
  if (ruleResult.stalePreview) {
141
171
  logOutcome("error", { errorRaw: "stale_preview" });
142
- return { content: [{ type: "text", text: "Stale preview — pattern no longer matches. Re-run with apply: false." }], isError: true, details: { stalePreview: true } };
172
+ return {
173
+ content: [
174
+ {
175
+ type: "text",
176
+ text: "Stale preview — pattern no longer matches. Re-run with apply: false.",
177
+ },
178
+ ],
179
+ isError: true,
180
+ details: { stalePreview: true },
181
+ };
143
182
  }
144
183
  if (ruleResult.error) {
145
184
  logOutcome("error", { errorRaw: ruleResult.error });
146
- return { content: [{ type: "text", text: errorTextWithHint(ruleResult.error) }], isError: true, details: {} };
185
+ return {
186
+ content: [
187
+ {
188
+ type: "text",
189
+ text: errorTextWithHint(ruleResult.error),
190
+ },
191
+ ],
192
+ isError: true,
193
+ details: {},
194
+ };
147
195
  }
148
196
  const output = astGrepClient.formatMatches(ruleResult.matches, !applyFlag, true);
149
- logOutcome(ruleResult.matches.length === 0 ? "no_matches" : "success", { matchCount: ruleResult.matches.length });
150
- return { content: [{ type: "text", text: output }], details: { matchCount: ruleResult.matches.length, applied: applyFlag } };
197
+ logOutcome(ruleResult.matches.length === 0 ? "no_matches" : "success", {
198
+ matchCount: ruleResult.matches.length,
199
+ });
200
+ return {
201
+ content: [{ type: "text", text: output }],
202
+ details: {
203
+ matchCount: ruleResult.matches.length,
204
+ applied: applyFlag,
205
+ },
206
+ };
151
207
  }
152
208
  const result = await astGrepClient.replace(pattern, rewrite, lang, searchPaths, applyFlag, { strictness });
153
209
  if (result.stalePreview) {
@@ -45,8 +45,13 @@ import * as path from "node:path";
45
45
  import { Type } from "../clients/deps/typebox.js";
46
46
  import { markDisposition, normalizeMessage, } from "../clients/diagnostic-dispositions.js";
47
47
  import { insertSuppressComment } from "../clients/dispatch/suppress-writer.js";
48
- import { getFileDiagnostics } from "../clients/widget-state.js";
49
- const DISPOSITIONS = ["false-positive", "suppress", "defer", "flagged"];
48
+ import { getFileDiagnostics, } from "../clients/widget-state.js";
49
+ const DISPOSITIONS = [
50
+ "false-positive",
51
+ "suppress",
52
+ "defer",
53
+ "flagged",
54
+ ];
50
55
  // How far ± the caller's line the fuzzy fallback searches for a plausible
51
56
  // (non-blank) line when there's no widget-state match to reanchor from.
52
57
  const FUZZY_SEARCH_RADIUS = 5;
@@ -84,7 +89,9 @@ function widgetCrossCheck(absPath, tool, rule, message, callerLine) {
84
89
  return undefined;
85
90
  if (matches.length === 1)
86
91
  return { line: matches[0].line, ambiguous: false };
87
- const closest = matches.reduce((best, d) => (Math.abs(d.line - callerLine) < Math.abs(best.line - callerLine) ? d : best), matches[0]);
92
+ const closest = matches.reduce((best, d) => Math.abs(d.line - callerLine) < Math.abs(best.line - callerLine)
93
+ ? d
94
+ : best, matches[0]);
88
95
  return { line: closest.line, ambiguous: true };
89
96
  }
90
97
  /**
@@ -135,7 +142,9 @@ function verifyLine(content, absPath, tool, rule, message, callerLine) {
135
142
  reanchored,
136
143
  note: reanchored
137
144
  ? `reanchored from line ${callerLine} to ${widgetResult.line}` +
138
- (widgetResult.ambiguous ? " (multiple live matches, chose nearest)" : "") +
145
+ (widgetResult.ambiguous
146
+ ? " (multiple live matches, chose nearest)"
147
+ : "") +
139
148
  " against current diagnostics"
140
149
  : undefined,
141
150
  };
@@ -193,12 +202,16 @@ getIdentity) {
193
202
  rule: Type.Optional(Type.String({
194
203
  description: "The diagnostic's rule id, if it has one (shown in lens_diagnostics as [rule]). Required for disposition=suppress.",
195
204
  })),
196
- tool: Type.Optional(Type.String({ description: "The tool that produced the diagnostic, if known." })),
205
+ tool: Type.Optional(Type.String({
206
+ description: "The tool that produced the diagnostic, if known.",
207
+ })),
197
208
  disposition: Type.String({
198
209
  enum: DISPOSITIONS,
199
210
  description: "false-positive = the rule misfired. suppress = real finding, won't fix (writes an inline ignore comment). defer = fix later, this session only. flagged = mark for you to fix.",
200
211
  }),
201
- reason: Type.Optional(Type.String({ description: "Optional short reason, kept alongside the disposition." })),
212
+ reason: Type.Optional(Type.String({
213
+ description: "Optional short reason, kept alongside the disposition.",
214
+ })),
202
215
  }),
203
216
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
204
217
  const cwd = ctx.cwd ?? getCwd();
@@ -304,8 +317,9 @@ getIdentity) {
304
317
  if (disposition === "suppress") {
305
318
  let updated;
306
319
  try {
320
+ updated = insertSuppressComment(content, absPath, verifiedLine,
307
321
  // biome-ignore lint/style/noNonNullAssertion: validated above
308
- updated = insertSuppressComment(content, absPath, verifiedLine, rule);
322
+ rule);
309
323
  }
310
324
  catch (err) {
311
325
  return {
@@ -12,16 +12,17 @@ import { promises as fs } from "node:fs";
12
12
  import * as fsSync from "node:fs";
13
13
  import * as path from "node:path";
14
14
  import { Type } from "../clients/deps/typebox.js";
15
- import { anchorsForDiagnostic, applyDispositions, applyWeakDispositions, getDisposition, } from "../clients/diagnostic-dispositions.js";
15
+ import { anchorsForDiagnostic, applyDispositions, applyWeakDispositions, hasAnyDispositionMarks, hasStrictDispositionMarks, getDisposition, } from "../clients/diagnostic-dispositions.js";
16
+ import { freshnessFromMtime } from "../clients/freshness.js";
16
17
  import { applyInlineSuppressions } from "../clients/dispatch/inline-suppressions.js";
17
18
  import { gateFindingsByPathFreshness } from "../clients/advisory-provenance.js";
18
19
  import { normalizeRuleId } from "../clients/dispatch/rule-id-normalize.js";
19
- import { applyRulePolicy, rulePolicyMapFromConfig } from "../clients/dispatch/rule-policy.js";
20
+ import { applyRulePolicy, rulePolicyMapFromConfig, } from "../clients/dispatch/rule-policy.js";
20
21
  import { loadPiLensProjectConfig } from "../clients/project-lens-config.js";
21
22
  import { compactRenderResult } from "./render-compact.js";
22
23
  import { combineAbortSignals } from "../clients/deadline-utils.js";
23
24
  import { getProjectIgnoreMatcher } from "../clients/file-utils.js";
24
- import { isAtOrAboveHomeDir, normalizeFilePath, } from "../clients/path-utils.js";
25
+ import { isAtOrAboveHomeDir, normalizeEphemeralMapKey, normalizeFilePath, } from "../clients/path-utils.js";
25
26
  import { getLSPService } from "../clients/lsp/index.js";
26
27
  import { primaryServerId } from "../clients/lsp/config.js";
27
28
  import { getFullScanWallClockMs } from "../clients/lsp/workspace-sweep-hold.js";
@@ -243,7 +244,7 @@ captureLspStatusRepaint, getRuntime) {
243
244
  description: `Restrict any mode to an explicit file/directory list (max ${MAX_PATHS_ENTRIES} entries; ` +
244
245
  "more errors instead of silently truncating). Entries may be relative " +
245
246
  "(resolved against cwd) or absolute, and a directory entry matches all " +
246
- "files under it (e.g. \"src/\"). mode=delta/all are a pure post-filter " +
247
+ 'files under it (e.g. "src/"). mode=delta/all are a pure post-filter ' +
247
248
  "of cached/session state — they can only show findings for files pi-lens " +
248
249
  "has already dispatched, so an unseen file shows nothing (use mode=full " +
249
250
  "for an active scan). mode=full actively scans exactly these paths (LSP " +
@@ -407,12 +408,108 @@ function appendProjectDiagnosticsDeltaLines(lines, cwd, report, severity, includ
407
408
  }
408
409
  return diagnostics.length;
409
410
  }
411
+ /**
412
+ * Bounded content memo for {@link applyCachedDispositions}' strict-immediate
413
+ * path: one read per (file revision), not per query. Keyed through
414
+ * `normalizeEphemeralMapKey` (cheap slash-fold + win32-lowercase — these keys
415
+ * are produced and consumed inside this process only) and validated against a
416
+ * fresh stat's mtimeMs+size on every hit, so an edit invalidates without a
417
+ * TTL. Insertion-ordered LRU cap bounds resident source bytes; repeated
418
+ * queries and multi-file reports that cite the same file reuse one read.
419
+ */
420
+ const CACHED_CONTENT_MEMO_CAP = 64;
421
+ const cachedContentMemo = new Map();
422
+ function readContentForAnchors(filePath, stat) {
423
+ const key = normalizeEphemeralMapKey(filePath);
424
+ const hit = cachedContentMemo.get(key);
425
+ if (hit && hit.mtimeMs === stat.mtimeMs && hit.size === stat.size) {
426
+ // Refresh LRU position.
427
+ cachedContentMemo.delete(key);
428
+ cachedContentMemo.set(key, hit);
429
+ return hit.content;
430
+ }
431
+ let content;
432
+ try {
433
+ content = fsSync.readFileSync(filePath, "utf-8");
434
+ }
435
+ catch {
436
+ return undefined;
437
+ }
438
+ if (cachedContentMemo.size >= CACHED_CONTENT_MEMO_CAP) {
439
+ const oldest = cachedContentMemo.keys().next().value;
440
+ if (oldest !== undefined)
441
+ cachedContentMemo.delete(oldest);
442
+ }
443
+ cachedContentMemo.set(key, {
444
+ mtimeMs: stat.mtimeMs,
445
+ size: stat.size,
446
+ content,
447
+ });
448
+ return content;
449
+ }
450
+ /**
451
+ * ONE disposition seam for every cache-only lens_diagnostics surface —
452
+ * mode=all summaries, mode=delta's actionable/quality warnings, the delta
453
+ * project-diagnostics report, and the empty-delta carried-over note. Cached
454
+ * findings predate any lens_diagnostic_mark, so each surface must re-apply
455
+ * dispositions at query time; before this seam each site hand-picked its own
456
+ * variant and three of them served stale STRICT false-positive marks via the
457
+ * weak-only filter (a weak filter can never drop a strict-anchored mark, nor
458
+ * any blocking finding — #1625 F1).
459
+ *
460
+ * Strict-immediate path: stat the file once, then compare its mtime against
461
+ * the newest cached diagnostic's own observation stamp through the freshness
462
+ * kernel (`freshnessFromMtime`). Fresh or stamp-less means the current bytes
463
+ * still describe what these findings were observed against, so the content is
464
+ * read (memoized per revision above) and the FULL applyDispositions filter
465
+ * runs — a fresh false-positive mark converges immediately, including on
466
+ * blocking findings.
467
+ *
468
+ * Weak fallback (zero further I/O): a file that is gone/unreadable, or whose
469
+ * mtime moved AFTER these diagnostics were observed. Stale-content edge: the
470
+ * cached findings describe a superseded revision, so their line numbers may no
471
+ * longer align with the lines a mark hashed; deriving strict anchors from the
472
+ * new content could match a DIFFERENT occurrence that merely shares the line
473
+ * number and identical text, so the mark waits for the next real dispatch to
474
+ * re-derive both sides against matching revisions. Weak suppress/defer marks
475
+ * are intent-level and never look at content, so they keep applying here.
476
+ */
477
+ function applyCachedDispositions(cachedDiagnostics, cwd, filePath) {
478
+ // Zero-I/O fast paths (#1625 F2 precedent): with no marks at all there is
479
+ // nothing to filter; with only weak suppress/defer marks a strict anchor
480
+ // can never match, so the weak filter serves them without any stat/read.
481
+ if (!hasAnyDispositionMarks(cwd))
482
+ return cachedDiagnostics;
483
+ if (!hasStrictDispositionMarks(cwd)) {
484
+ return applyWeakDispositions(cachedDiagnostics, cwd, filePath);
485
+ }
486
+ let stat;
487
+ try {
488
+ stat = fsSync.statSync(filePath);
489
+ }
490
+ catch {
491
+ return applyWeakDispositions(cachedDiagnostics, cwd, filePath);
492
+ }
493
+ const referenceMs = cachedDiagnostics.reduce((latest, d) => Math.max(latest, d.observedAt ?? 0), 0);
494
+ if (referenceMs > 0 &&
495
+ freshnessFromMtime({ mtimeMs: stat.mtimeMs, referenceMs }).verdict ===
496
+ "stale") {
497
+ return applyWeakDispositions(cachedDiagnostics, cwd, filePath);
498
+ }
499
+ const content = readContentForAnchors(filePath, stat);
500
+ if (content === undefined) {
501
+ return applyWeakDispositions(cachedDiagnostics, cwd, filePath);
502
+ }
503
+ return applyDispositions(cachedDiagnostics, cwd, filePath, content);
504
+ }
410
505
  /**
411
506
  * #755: drop project-diagnostics-delta findings disposed suppress/defer before
412
507
  * delta mode re-serves them. Anchored via `projectDiagnosticToWidget` so the
413
508
  * (tool, rule) an agent's mark binds to matches mode=full's own project-runner
414
509
  * filter (`applyInlineSuppressionsToSummaries`), keeping the two paths in
415
- * agreement. Weak-anchored → no file read. Also applies the project's
510
+ * agreement. Goes through the shared {@link applyCachedDispositions} seam so
511
+ * strict false-positive anchors apply immediately, like every other cache-only
512
+ * surface. Also applies the project's
416
513
  * `.pi-lens.json` `rules.<id>.disable`/`select` policy so a project's policy
417
514
  * overlays the same delta report cache; the cache is otherwise insensitive to
418
515
  * a project-config edit (the per-edit path picks it up immediately, but a
@@ -421,8 +518,7 @@ function appendProjectDiagnosticsDeltaLines(lines, cwd, report, severity, includ
421
518
  function filterDeltaReportDispositions(report, cwd, policyMap) {
422
519
  if (!report?.diagnostics.length)
423
520
  return report;
424
- const kept = report.diagnostics.filter((d) => applyWeakDispositions([projectDiagnosticToWidget(d, d.filePath)], cwd, d.filePath)
425
- .length === 1);
521
+ const kept = report.diagnostics.filter((d) => applyCachedDispositions([projectDiagnosticToWidget(d, d.filePath)], cwd, d.filePath).length === 1);
426
522
  const policyKept = applyRulePolicy(kept, policyMap);
427
523
  if (policyKept.length === report.diagnostics.length)
428
524
  return report;
@@ -508,14 +604,14 @@ function formatDeltaMode(cacheManager, cwd, severity, pathsScope) {
508
604
  const includeFile = (filePath) => ignoreFile(filePath) && (!pathsScope || pathsScope.includeFile(filePath));
509
605
  // #755: delta re-serves the actionable/quality caches verbatim, but those
510
606
  // were filtered at DISPATCH time — before any lens_diagnostic_mark. Re-apply
511
- // the weak disposition filter (suppress/defer) here so a mark converges
512
- // immediately, not only on the next edit. Weak-anchored → zero file I/O, so
513
- // this stays "instant" (see applyWeakDispositions).
607
+ // dispositions here so a mark converges immediately, not only on the next
608
+ // edit — through the shared {@link applyCachedDispositions} seam, so strict
609
+ // false-positive marks land as fast as suppress/defer.
514
610
  const visibleWarningFiles = (files) => (files ?? [])
515
611
  .filter((file) => includeFile(file.filePath))
516
612
  .map((file) => ({
517
613
  filePath: file.filePath,
518
- warnings: applyRulePolicy(applyWeakDispositions(file.warnings ?? [], cwd, file.filePath), policyMap),
614
+ warnings: applyRulePolicy(applyCachedDispositions(file.warnings ?? [], cwd, file.filePath), policyMap),
519
615
  }))
520
616
  .filter((file) => file.warnings.length > 0);
521
617
  const actionableFiles = applyDeltaFreshnessGate(visibleWarningFiles(actionable?.files), cwd, actionable?.generatedAt);
@@ -556,7 +652,7 @@ function formatDeltaMode(cacheManager, cwd, severity, pathsScope) {
556
652
  .filter((f) => includeFile(f.filePath))
557
653
  .map((f) => ({
558
654
  ...f,
559
- diagnostics: applyRulePolicy(applyWeakDispositions(f.diagnostics, cwd, f.filePath), policyMap),
655
+ diagnostics: applyRulePolicy(applyCachedDispositions(f.diagnostics, cwd, f.filePath), policyMap),
560
656
  }))
561
657
  .filter((f) => f.diagnostics.length > 0);
562
658
  const carriedIssues = carried.reduce((n, f) => n + f.diagnostics.length, 0);
@@ -699,7 +795,10 @@ function filterProjectDiagnosticsDeltaReport(report, includeFile) {
699
795
  function applyProjectRulePolicy(value, policyMap) {
700
796
  if (!value)
701
797
  return undefined;
702
- return { ...value, diagnostics: applyRulePolicy(value.diagnostics, policyMap) };
798
+ return {
799
+ ...value,
800
+ diagnostics: applyRulePolicy(value.diagnostics, policyMap),
801
+ };
703
802
  }
704
803
  /** A diagnostic counts as error-like when it blocks or has error severity.
705
804
  * A `stale` (#1641 past-EOF) entry is excluded — its cited line no longer
@@ -971,11 +1070,29 @@ function tallyLspPrimaryVsAuxiliary(results) {
971
1070
  }
972
1071
  return { primary, auxiliary };
973
1072
  }
974
- function mergeDiagnosticsWithWidgetSummaries(widgetSummaries, lspResults, projectSnapshot, projectDelta) {
1073
+ export function mergeDiagnosticsWithWidgetSummaries(widgetSummaries, lspResults, projectSnapshot, projectDelta,
1074
+ /**
1075
+ * #1993: resolved paths covered by a CONFIRMED, fully-covered LSP result
1076
+ * in `lspResults`. The fresh sweep is AUTHORITATIVE for these files - any
1077
+ * widget-store diagnostics seeded for them predate the sweep and must not
1078
+ * survive it (an additive-only merge let mid-edit stale 🔴 entries render
1079
+ * forever beside a clean sweep). Files absent from this set keep today's
1080
+ * additive behavior (fail-open: unconfirmed/timed-out sweeps never retire
1081
+ * widget state they did not actually re-check).
1082
+ */
1083
+ authoritativeLspFiles) {
975
1084
  const byFile = new Map();
976
1085
  const seen = new Set();
977
1086
  for (const summary of widgetSummaries) {
978
1087
  const filePath = path.resolve(summary.filePath);
1088
+ // NOTE (#1993 review): dispositions recorded against a CACHED copy's
1089
+ // message text may not match this file's fresh sweep copy (weak
1090
+ // anchors key on message). Both copies derive from the same LSP
1091
+ // diagnostic via convertLspDiagnostics, so identity is stable in
1092
+ // practice; inline pi-lens-ignore comments are the primary
1093
+ // suppression mechanism.
1094
+ if (authoritativeLspFiles?.has(filePath))
1095
+ continue;
979
1096
  const diagnostics = (summary.diagnostics ?? []).map((d) => ({ ...d }));
980
1097
  byFile.set(filePath, { ...summary, filePath, diagnostics });
981
1098
  for (const diagnostic of diagnostics) {
@@ -1167,7 +1284,9 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
1167
1284
  // signal from the same starting point instead of stacking.
1168
1285
  const projectRunnersRequested = shouldIncludeProjectRunners(options.refreshRunners);
1169
1286
  const analyzersPromise = projectRunnersRequested
1170
- ? loadBootstrapClients().then((clients) => fetchFreshProjectDiagnostics(cacheManager, cwd, clients, signal, { runtime: options.runtime }))
1287
+ ? loadBootstrapClients().then((clients) => fetchFreshProjectDiagnostics(cacheManager, cwd, clients, signal, {
1288
+ runtime: options.runtime,
1289
+ }))
1171
1290
  : Promise.resolve({
1172
1291
  diagnostics: [],
1173
1292
  runners: [],
@@ -1225,14 +1344,10 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
1225
1344
  // the unfiltered `lspResults` in, so a timed-out file's placeholder `[]`
1226
1345
  // read as "0 diagnostics" — false-clean — in the rendered/`details`
1227
1346
  // output (#630).
1228
- const confirmedLspResults = lspResults.filter((result) => !result.timedOut &&
1229
- !result.error &&
1230
- !mismatchedLspResults.has(result));
1347
+ const confirmedLspResults = lspResults.filter((result) => !result.timedOut && !result.error && !mismatchedLspResults.has(result));
1231
1348
  const fullyCoveredLspResults = confirmedLspResults.filter((result) => (result.unconfirmedServerIds?.length ?? 0) === 0);
1232
1349
  const partiallyCoveredLspResults = confirmedLspResults.filter((result) => (result.unconfirmedServerIds?.length ?? 0) > 0);
1233
- const unconfirmedLspResults = lspResults.filter((result) => result.timedOut ||
1234
- result.error ||
1235
- mismatchedLspResults.has(result));
1350
+ const unconfirmedLspResults = lspResults.filter((result) => result.timedOut || result.error || mismatchedLspResults.has(result));
1236
1351
  // #571: reconcile this scan's fresh, CONFIRMED per-file results into the
1237
1352
  // footer cache. A footer write is never allowed to fail the tool call, so
1238
1353
  // any unexpected throw is swallowed.
@@ -1301,7 +1416,25 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
1301
1416
  // read as "0 issues, clean" via its LSP contribution. It can still
1302
1417
  // legitimately show diagnostics from widgetSummaries/project-runner state
1303
1418
  // below if those independently have entries for it.
1304
- const summaries = await applyInlineSuppressionsToSummaries(mergeDiagnosticsWithWidgetSummaries(getFileDiagnosticSummaries().filter((summary) => includeFile(summary.filePath)), confirmedLspResults, projectSnapshot, projectDelta), cwd, policyMap);
1419
+ // #1993: files with a CONFIRMED, fully-covered LSP result are authoritative
1420
+ // - the fresh sweep replaces their widget-store state instead of merging
1421
+ // additively beside it.
1422
+ const authoritativeLspFiles = new Set(fullyCoveredLspResults.map((result) => path.resolve(result.filePath)));
1423
+ // #1993 review: retirement must be observable - if a future regression
1424
+ // makes the set falsely authoritative, findings would vanish silently.
1425
+ const authoritativeRetiredCount = getFileDiagnosticSummaries().filter((summary) => includeFile(summary.filePath) &&
1426
+ authoritativeLspFiles.has(path.resolve(summary.filePath)) &&
1427
+ (summary.diagnostics?.length ?? 0) > 0).length;
1428
+ if (authoritativeRetiredCount > 0) {
1429
+ logLatency({
1430
+ type: "phase",
1431
+ phase: "lsp_authoritative_widget_retire",
1432
+ filePath: "",
1433
+ durationMs: 0,
1434
+ metadata: { files: authoritativeRetiredCount },
1435
+ });
1436
+ }
1437
+ const summaries = await applyInlineSuppressionsToSummaries(mergeDiagnosticsWithWidgetSummaries(getFileDiagnosticSummaries().filter((summary) => includeFile(summary.filePath)), confirmedLspResults, projectSnapshot, projectDelta, authoritativeLspFiles), cwd, policyMap);
1305
1438
  // #1888: the full-mode summary above is the first seam where every
1306
1439
  // producing lane is correlated. The earlier footer loop intentionally writes
1307
1440
  // only CONFIRMED LSP results, so an ast-grep backpressure failure left
@@ -1520,7 +1653,8 @@ async function formatFullMode(cwd, severity, lspService, cacheManager, options =
1520
1653
  const cheapScanStatusNote = !projectRunnersRequested
1521
1654
  ? `\n\ncheap project scan (tree-sitter/fact-rules/ast-grep): not run this call (${NOT_REQUESTED_REASON}).`
1522
1655
  : options.refreshRunners === "cached"
1523
- ? cheapScanScannedAtMs !== undefined && Number.isFinite(cheapScanScannedAtMs)
1656
+ ? cheapScanScannedAtMs !== undefined &&
1657
+ Number.isFinite(cheapScanScannedAtMs)
1524
1658
  ? `\n\ncheap project scan (tree-sitter/fact-rules/ast-grep): served from cache, ${formatCacheAgeOld(Date.now() - cheapScanScannedAtMs)} — not re-run this call.`
1525
1659
  : `\n\ncheap project scan (tree-sitter/fact-rules/ast-grep): not run (no cached scan; refresh with refreshRunners=cheap/all to populate).`
1526
1660
  : "";
@@ -1716,24 +1850,19 @@ function formatAllMode(cwd, severity, summaries = getFileDiagnosticSummaries(),
1716
1850
  const isFullMode = detailOverrides.mode === "full";
1717
1851
  const ignoreFile = createCurrentIgnoreFilter(cwd);
1718
1852
  const includeFile = (filePath) => ignoreFile(filePath) && (!pathsScope || pathsScope.includeFile(filePath));
1719
- // #755: mode=full already ran the full disposition + inline-suppression
1720
- // filter (applyInlineSuppressionsToSummaries, file content in hand); mode=all
1721
- // re-serves the widget summaries verbatim from dispatch time, so a
1722
- // post-dispatch lens_diagnostic_mark (suppress/defer) would otherwise still
1723
- // show here. Re-apply the weak filter (zero I/O) for the cache-only path and
1724
- // re-summarize so blocking/error/warning counts reflect the drop.
1725
- // Same project rule policy (`.pi-lens.json` `rules.<id>.disable`/`select`)
1726
- // overlays both modes: mode=full re-applies it after inline suppression /
1727
- // disposition (zero I/O), mode=all applies it here on the cache-only path.
1728
- // The full path's policyMover is loaded below in `applyInlineSuppressionsToSummaries`.
1853
+ // Cached summaries predate marks. Every cache-only surface re-applies
1854
+ // dispositions through the shared applyCachedDispositions seam — strict
1855
+ // false-positive anchors against current content when the file is
1856
+ // unchanged since observation, weak-only fallback otherwise.
1729
1857
  const policyMap = loadProjectRulePolicyMap(cwd);
1730
1858
  const dispositioned = isFullMode
1731
1859
  ? summaries
1732
1860
  : summaries.map((s) => {
1733
- const kept = applyWeakDispositions(s.diagnostics ?? [], cwd, s.filePath);
1861
+ const diagnostics = s.diagnostics ?? [];
1862
+ const kept = applyCachedDispositions(diagnostics, cwd, s.filePath);
1734
1863
  const policyKept = applyRulePolicy(kept, policyMap);
1735
1864
  if (policyKept.length === kept.length &&
1736
- kept.length === (s.diagnostics?.length ?? 0))
1865
+ kept.length === diagnostics.length)
1737
1866
  return s;
1738
1867
  return summarizeDiagnostics(s.filePath, policyKept, s.hasFinalSnapshot);
1739
1868
  });
@@ -11,15 +11,15 @@ import { getProjectIgnoreMatcher, isExcludedDirName, } from "../clients/file-uti
11
11
  import { getLSPService, groupFilesByPrimaryServer, runPerServerGroups, } from "../clients/lsp/index.js";
12
12
  import { buildScopeKey, createWorkspaceDiagnosticsCacheContext, } from "../clients/lsp/workspace-diagnostics-cache.js";
13
13
  import { getServersForFileWithConfig, primaryServerId, } from "../clients/lsp/config.js";
14
- import { combineAbortSignals, withDeadline } from "../clients/deadline-utils.js";
14
+ import { combineAbortSignals, withDeadline, } from "../clients/deadline-utils.js";
15
15
  import { applyAuxiliarySuppressions, retagAuxiliaryDiagnostics, } from "../clients/dispatch/auxiliary-lsp.js";
16
16
  import { detectFileRole } from "../clients/file-role.js";
17
17
  import { hashDiagnosticContent, touchCompletedConfirmationPolicy, touchCoverageGap, } from "../clients/lsp/diagnostic-binding.js";
18
18
  import { classifyCascadeWaitTier } from "../clients/lsp/wait-policy/index.js";
19
- import { attemptTsserverSyncDiagnostics, } from "../clients/lsp/tsserver-sync.js";
19
+ import { attemptTsserverSyncDiagnostics } from "../clients/lsp/tsserver-sync.js";
20
20
  import { convertLspDiagnostics } from "../clients/dispatch/utils/lsp-diagnostics.js";
21
21
  import { demoteInferredProjectDiagnostics } from "../clients/lsp/inferred-project.js";
22
- import { isBlocking, reconcileScanDiagnostics } from "../clients/widget-state.js";
22
+ import { isBlocking, reconcileScanDiagnostics, } from "../clients/widget-state.js";
23
23
  import { baseName, compactRenderResult } from "./render-compact.js";
24
24
  import { makeProgressReporter, scanningSummaryLine } from "./scan-progress.js";
25
25
  import { isWarmAttached, tryWarmAttachedDiagnostics, } from "../clients/warm-attach.js";
@@ -367,10 +367,12 @@ onConfirmedNoBlockers) {
367
367
  if (Array.isArray(typedParams.paths) && typedParams.paths.length > 0) {
368
368
  if (typedParams.paths.length > MAX_BATCH_FILES) {
369
369
  return {
370
- content: [{
370
+ content: [
371
+ {
371
372
  type: "text",
372
373
  text: `paths accepts at most ${MAX_BATCH_FILES} files; received ${typedParams.paths.length}.`,
373
- }],
374
+ },
375
+ ],
374
376
  isError: true,
375
377
  details: { mode: "batch", filesChecked: 0 },
376
378
  };
@@ -378,7 +380,12 @@ onConfirmedNoBlockers) {
378
380
  const rawPaths = typedParams.paths.filter((entry) => typeof entry === "string" && entry.trim().length > 0);
379
381
  if (rawPaths.length !== typedParams.paths.length) {
380
382
  return {
381
- content: [{ type: "text", text: "paths must contain non-empty file paths." }],
383
+ content: [
384
+ {
385
+ type: "text",
386
+ text: "paths must contain non-empty file paths.",
387
+ },
388
+ ],
382
389
  isError: true,
383
390
  details: { mode: "batch", filesChecked: 0 },
384
391
  };
@@ -1206,7 +1213,17 @@ async function collectBatchDiagnostics(files, severity, lspService, options) {
1206
1213
  for (const result of results) {
1207
1214
  result.outcome = classifyBatchFileOutcome(result);
1208
1215
  }
1209
- const outcomeCounts = Object.fromEntries(["clean", "findings", "unsupported", "unavailable", "failed", "inconclusive"].map((outcome) => [outcome, results.filter((result) => result.outcome === outcome).length]));
1216
+ const outcomeCounts = Object.fromEntries([
1217
+ "clean",
1218
+ "findings",
1219
+ "unsupported",
1220
+ "unavailable",
1221
+ "failed",
1222
+ "inconclusive",
1223
+ ].map((outcome) => [
1224
+ outcome,
1225
+ results.filter((result) => result.outcome === outcome).length,
1226
+ ]));
1210
1227
  // Per-file primary-server lookup so a flattened multi-file `display` list
1211
1228
  // can still be split into "primary findings" vs "auxiliary findings" —
1212
1229
  // `clean`/`unconfirmed` above already reflect ONLY the primary server's
@@ -1098,7 +1098,9 @@ getFlag, mutationDeps) {
1098
1098
  edit,
1099
1099
  };
1100
1100
  }
1101
- const applied = await applyWorkspaceEdit(edit, ctx.cwd || ".", { mutationContext });
1101
+ const applied = await applyWorkspaceEdit(edit, ctx.cwd || ".", {
1102
+ mutationContext,
1103
+ });
1102
1104
  for (const touchedFile of applied.files) {
1103
1105
  try {
1104
1106
  await openFileBestEffort(lspService, touchedFile, false);
@@ -29,7 +29,7 @@ export function createModuleReportTool(getProjectRoot) {
29
29
  description: "Structured, navigable overview of a source module — a token-efficient substitute for reading the whole file. Returns each symbol's name/kind/signature/line-range (plus a first-line `doc` summary when a doc comment is attached), important inline callbacks/closures/lambdas with stable handles, plus who-uses-this, risk flags, and ranked recommendedReads. To read a symbol's body: call read/read_symbol with offset=startLine, limit=endLine-startLine+1 on THIS report's `path` — those aren't repeated per symbol. Prefer this before a full read; then use read_symbol (or read) for the exact body you need.\n" +
30
30
  "Single mode: language-uniform tree-sitter outline + review-graph who-uses-this + inline executable extraction; degrades to outline-only when no cached graph is available. `semantic.source` reports whether graph data was used.\n" +
31
31
  'Pass `blastRadius: true` to also get the cross-file blast radius — the transitive dependents of this module aggregated to ranked file `read` args ("if you change this, verify these files"). Read-only over the cached graph; omitted on a cold cache. Supersedes the standalone impact query.\n' +
32
- 'Pass `callGraph: true` to include bounded derived callers/callees from the cached FunctionCallGraph; unavailable cache state is explicit and never reported as zero calls.\n' +
32
+ "Pass `callGraph: true` to include bounded derived callers/callees from the cached FunctionCallGraph; unavailable cache state is explicit and never reported as zero calls.\n" +
33
33
  '`view: "compact"` returns a line-oriented text rendering (one line per symbol/callback, cheapest option) instead of JSON — same data, roughly a quarter of the token cost; use it for a quick skim. Default view returns JSON. An outline shows shape, not bodies — it does NOT count as having read a symbol\'s body for editing; use read_symbol for that.',
34
34
  promptSnippet: "Navigable file outline — a cheap substitute for reading a whole file",
35
35
  renderResult: compactRenderResult(({ details, args, isError }) => {
@@ -40,7 +40,7 @@ export function createProjectReportTool(getProjectRoot) {
40
40
  })),
41
41
  view: Type.Optional(Type.String({
42
42
  enum: ["default", "compact"],
43
- description: 'Payload tier. compact (cheapest) returns a line-oriented TEXT rendering instead of JSON. Default returns JSON.',
43
+ description: "Payload tier. compact (cheapest) returns a line-oriented TEXT rendering instead of JSON. Default returns JSON.",
44
44
  })),
45
45
  }),
46
46
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {