@herbertgao/pi-extensions 2026.8.6 → 2026.8.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 (385) hide show
  1. package/README.md +8 -6
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +2 -2
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -2
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +19 -7
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +30 -9
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +320 -22
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +79 -17
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +27 -0
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +66 -17
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +41 -2
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +75 -6
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +7 -3
  14. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +64 -1
  15. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  16. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
  17. package/node_modules/@herbertgao/pi-subagents/README.md +30 -22
  18. package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +5 -5
  19. package/node_modules/@herbertgao/pi-subagents/package.json +7 -7
  20. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +7 -1
  21. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +48 -19
  22. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +17 -13
  23. package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +26 -2
  24. package/node_modules/@herbertgao/pi-subagents/src/index.ts +219 -40
  25. package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +101 -3
  26. package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +18 -4
  27. package/node_modules/@herbertgao/pi-subagents/src/settings.ts +99 -0
  28. package/node_modules/@herbertgao/pi-subagents/src/types.ts +22 -3
  29. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +51 -3
  30. package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +20 -2
  31. package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +21 -6
  32. package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
  33. package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +20 -0
  34. package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +5 -4
  35. package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +174 -100
  36. package/node_modules/@juicesharp/rpiv-ask-user-question/config.ts +25 -0
  37. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/configuration.md +13 -4
  38. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +5 -1
  39. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +10 -2
  40. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +10 -6
  41. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/tool-schema.md +11 -5
  42. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +5 -2
  43. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/zh.json +2 -2
  44. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +3 -2
  45. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +10 -0
  46. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +140 -97
  47. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +63 -28
  48. package/node_modules/@juicesharp/rpiv-ask-user-question/state/selectors/projections.ts +22 -15
  49. package/node_modules/@juicesharp/rpiv-ask-user-question/state/state-reducer.ts +11 -1
  50. package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
  51. package/node_modules/@juicesharp/rpiv-ask-user-question/tool/response-envelope.ts +11 -0
  52. package/node_modules/@juicesharp/rpiv-ask-user-question/tool/types.ts +11 -0
  53. package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/multi-select-view.ts +31 -17
  54. package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/preview/preview-block-renderer.ts +15 -6
  55. package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/wrapping-select.ts +15 -6
  56. package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +86 -38
  57. package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +76 -9
  58. package/node_modules/@narumitw/pi-btw/README.md +120 -111
  59. package/node_modules/@narumitw/pi-btw/dist/index.ts +2898 -0
  60. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +7 -0
  61. package/node_modules/@narumitw/pi-btw/package.json +10 -6
  62. package/node_modules/@narumitw/pi-btw/src/btw.ts +36 -40
  63. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +55 -10
  64. package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +390 -0
  65. package/node_modules/@narumitw/pi-btw/src/menu.ts +45 -2
  66. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
  67. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +44 -1856
  68. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
  69. package/node_modules/@pi-plugins/fast-mode/package.json +4 -6
  70. package/node_modules/pi-lens/CHANGELOG.md +999 -0
  71. package/node_modules/pi-lens/README.md +117 -3
  72. package/node_modules/pi-lens/config/ruff/core.toml +42 -0
  73. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +130 -27
  74. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +126 -13
  75. package/node_modules/pi-lens/dist/clients/agent-nudge.js +67 -11
  76. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +9 -3
  77. package/node_modules/pi-lens/dist/clients/atomic-write.js +9 -3
  78. package/node_modules/pi-lens/dist/clients/bash-file-access.js +381 -13
  79. package/node_modules/pi-lens/dist/clients/biome-client.js +61 -30
  80. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
  81. package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +129 -0
  82. package/node_modules/pi-lens/dist/clients/bootstrap.js +12 -1
  83. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +12 -3
  84. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +206 -0
  85. package/node_modules/pi-lens/dist/clients/cache-observability.js +353 -76
  86. package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
  87. package/node_modules/pi-lens/dist/clients/cascade-format.js +20 -1
  88. package/node_modules/pi-lens/dist/clients/cascade-types.js +9 -1
  89. package/node_modules/pi-lens/dist/clients/child-unref.js +54 -6
  90. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +76 -24
  91. package/node_modules/pi-lens/dist/clients/dead-code-client.js +123 -31
  92. package/node_modules/pi-lens/dist/clients/deadline-utils.js +8 -1
  93. package/node_modules/pi-lens/dist/clients/debug-handles.js +5 -0
  94. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +84 -14
  95. package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +155 -0
  96. package/node_modules/pi-lens/dist/clients/dependency-checker.js +25 -3
  97. package/node_modules/pi-lens/dist/clients/deps/pi-tui.js +8 -2
  98. package/node_modules/pi-lens/dist/clients/deps/typebox.js +8 -3
  99. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +147 -33
  100. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
  101. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +52 -2
  102. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +256 -88
  103. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +7 -4
  104. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +5 -0
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +234 -18
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +187 -19
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +6 -3
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +11 -9
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +398 -0
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +9 -6
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +11 -3
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +12 -7
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +18 -0
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +9 -7
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +8 -6
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +4 -0
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +16 -3
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +60 -53
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -2
  121. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +25 -2
  122. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +20 -5
  123. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +44 -11
  124. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +331 -55
  125. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +38 -5
  126. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +97 -19
  127. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +17 -8
  128. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +32 -4
  129. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +47 -3
  130. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +14 -4
  131. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +127 -28
  132. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +12 -7
  133. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +73 -12
  134. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +275 -13
  135. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +21 -6
  136. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +260 -27
  137. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +734 -64
  138. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +86 -11
  139. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +188 -0
  140. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +9 -0
  141. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +21 -10
  142. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -2
  143. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
  144. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
  145. package/node_modules/pi-lens/dist/clients/extension-log.js +22 -1
  146. package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
  147. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +316 -0
  148. package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
  149. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +3 -2
  150. package/node_modules/pi-lens/dist/clients/formatters.js +500 -115
  151. package/node_modules/pi-lens/dist/clients/generation-guard.js +216 -0
  152. package/node_modules/pi-lens/dist/clients/git-guard.js +31 -0
  153. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
  154. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +109 -9
  155. package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
  156. package/node_modules/pi-lens/dist/clients/host-ports.js +8 -0
  157. package/node_modules/pi-lens/dist/clients/installer/index.js +1114 -100
  158. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +58 -0
  159. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +715 -0
  160. package/node_modules/pi-lens/dist/clients/instance-reaper.js +643 -97
  161. package/node_modules/pi-lens/dist/clients/instance-registry.js +87 -17
  162. package/node_modules/pi-lens/dist/clients/jscpd-client.js +87 -8
  163. package/node_modules/pi-lens/dist/clients/knip-client.js +310 -10
  164. package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
  165. package/node_modules/pi-lens/dist/clients/language-profile.js +9 -2
  166. package/node_modules/pi-lens/dist/clients/latency-logger.js +440 -11
  167. package/node_modules/pi-lens/dist/clients/lazy-import.js +21 -0
  168. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -0
  169. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
  170. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +128 -8
  171. package/node_modules/pi-lens/dist/clients/lsp/client.js +1660 -164
  172. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +83 -1
  173. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
  174. package/node_modules/pi-lens/dist/clients/lsp/index.js +2423 -151
  175. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +215 -0
  176. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +146 -14
  177. package/node_modules/pi-lens/dist/clients/lsp/language.js +48 -4
  178. package/node_modules/pi-lens/dist/clients/lsp/server.js +277 -16
  179. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +22 -0
  180. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +43 -0
  181. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +79 -3
  182. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +43 -0
  183. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +422 -28
  184. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +30 -0
  185. package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +175 -0
  186. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +3 -2
  187. package/node_modules/pi-lens/dist/clients/mcp/session.js +10 -2
  188. package/node_modules/pi-lens/dist/clients/module-report.js +22 -1
  189. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +114 -23
  190. package/node_modules/pi-lens/dist/clients/opengrep-client.js +15 -1
  191. package/node_modules/pi-lens/dist/clients/package-manager.js +170 -14
  192. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +27 -0
  193. package/node_modules/pi-lens/dist/clients/path-utils.js +160 -0
  194. package/node_modules/pi-lens/dist/clients/pipeline.js +154 -33
  195. package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +37 -0
  196. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +17 -3
  197. package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +89 -22
  198. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +84 -14
  199. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +15 -3
  200. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +50 -2
  201. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +23 -9
  202. package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
  203. package/node_modules/pi-lens/dist/clients/project-report.js +62 -27
  204. package/node_modules/pi-lens/dist/clients/project-snapshot.js +299 -0
  205. package/node_modules/pi-lens/dist/clients/quiet-window-config.js +47 -0
  206. package/node_modules/pi-lens/dist/clients/quiet-window.js +11 -25
  207. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +8 -3
  208. package/node_modules/pi-lens/dist/clients/read-guard.js +253 -10
  209. package/node_modules/pi-lens/dist/clients/resource-sampler.js +49 -17
  210. package/node_modules/pi-lens/dist/clients/reverse-deps.js +50 -11
  211. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +194 -31
  212. package/node_modules/pi-lens/dist/clients/review-graph/query.js +52 -4
  213. package/node_modules/pi-lens/dist/clients/review-graph/revision-drift.js +21 -0
  214. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +6 -3
  215. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +96 -7
  216. package/node_modules/pi-lens/dist/clients/runtime-context.js +8 -1
  217. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +352 -45
  218. package/node_modules/pi-lens/dist/clients/runtime-session.js +373 -9
  219. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
  220. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +212 -79
  221. package/node_modules/pi-lens/dist/clients/runtime-turn.js +620 -67
  222. package/node_modules/pi-lens/dist/clients/safe-spawn.js +220 -7
  223. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +161 -0
  224. package/node_modules/pi-lens/dist/clients/search-read-registration.js +34 -6
  225. package/node_modules/pi-lens/dist/clients/security-scan-client.js +157 -24
  226. package/node_modules/pi-lens/dist/clients/session-event-guard.js +184 -0
  227. package/node_modules/pi-lens/dist/clients/sg-runner.js +116 -22
  228. package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
  229. package/node_modules/pi-lens/dist/clients/source-filter.js +6 -2
  230. package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
  231. package/node_modules/pi-lens/dist/clients/startup-scan.js +5 -2
  232. package/node_modules/pi-lens/dist/clients/startup-timing.js +19 -1
  233. package/node_modules/pi-lens/dist/clients/test-runner-client.js +151 -16
  234. package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
  235. package/node_modules/pi-lens/dist/clients/tool-policy.js +125 -20
  236. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +75 -1
  237. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +769 -64
  238. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +1 -0
  239. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +11 -0
  240. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +90 -0
  241. package/node_modules/pi-lens/dist/clients/trivy-client.js +19 -1
  242. package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
  243. package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
  244. package/node_modules/pi-lens/dist/index.js +61407 -48577
  245. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +476 -57
  246. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +132 -43
  247. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
  248. package/node_modules/pi-lens/docs/agent-guide.md +6 -1
  249. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +515 -506
  250. package/node_modules/pi-lens/docs/dispositions.md +21 -0
  251. package/node_modules/pi-lens/docs/features.md +19 -5
  252. package/node_modules/pi-lens/docs/globalconfig.md +3 -0
  253. package/node_modules/pi-lens/docs/language-coverage.md +71 -5
  254. package/node_modules/pi-lens/docs/mcp.md +2 -2
  255. package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
  256. package/node_modules/pi-lens/docs/settings.md +19 -1
  257. package/node_modules/pi-lens/docs/usage.md +1 -0
  258. package/node_modules/pi-lens/package.json +27 -10
  259. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-js-snapshot.yml +23 -0
  260. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-snapshot.yml +23 -0
  261. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/ts-void-zero-snapshot.yml +23 -0
  262. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-object-param-test.yml +16 -0
  263. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +15 -1
  264. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-compile-call-test.yml +29 -1
  265. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-dupe-class-members-test.yml +33 -0
  266. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-js-test.yml +7 -1
  267. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-test.yml +7 -1
  268. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-known-value-widening-test.yml +9 -0
  269. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml +216 -0
  270. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +2 -0
  271. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +2 -0
  272. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +2 -1
  273. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +2 -1
  274. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-return-value-in-generator-test.yml +12 -0
  275. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-runtime-typeof-test.yml +33 -0
  276. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-server-bind-wildcard-test.yml +9 -0
  277. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-shape-in-symbol-names-test.yml +13 -0
  278. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-js-test.yml +5 -1
  279. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-test.yml +5 -1
  280. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-parameters-test.yml +12 -0
  281. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-returns-test.yml +16 -0
  282. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-any-test.yml +10 -0
  283. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-unknown-test.yml +8 -0
  284. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/redundant-unsafe-function-test.yml +35 -0
  285. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/require-safety-comment-for-as-unknown-as-test.yml +177 -0
  286. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ts-void-zero-test.yml +1 -0
  287. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member-js.yml +13 -2
  288. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member.yml +13 -2
  289. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +2 -0
  290. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-object-param.yml +60 -0
  291. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +57 -12
  292. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-compile-call.yml +63 -5
  293. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-dupe-class-members.yml +52 -8
  294. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html-js.yml +27 -2
  295. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html.yml +27 -2
  296. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-known-value-widening.yml +71 -0
  297. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-non-null-assertion.yml +316 -0
  298. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +7 -0
  299. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +22 -2
  300. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +23 -2
  301. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +33 -5
  302. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +34 -8
  303. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-return-value-in-generator.yml +22 -5
  304. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-runtime-typeof.yml +121 -0
  305. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-server-bind-wildcard.yml +23 -7
  306. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-shape-in-symbol-names.yml +68 -0
  307. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +41 -2
  308. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code.yml +41 -2
  309. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +6 -1
  310. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-parameters.yml +67 -0
  311. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-returns.yml +106 -0
  312. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-any.yml +50 -0
  313. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-unknown.yml +56 -0
  314. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +2 -0
  315. package/node_modules/pi-lens/rules/ast-grep-rules/rules/redundant-unsafe-function.yml +32 -0
  316. package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml +184 -0
  317. package/node_modules/pi-lens/rules/ast-grep-rules/rules/ts-void-zero.yml +5 -0
  318. package/node_modules/pi-lens/rules/ast-grep-rules/self-scan-baseline.json +5 -0
  319. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +53 -1
  320. package/node_modules/pi-lens/scripts/download-grammars.js +25 -0
  321. package/node_modules/pi-lens/scripts/grammars.lock.json +9 -0
  322. package/node_modules/pi-lens/scripts/install-selftest.mjs +99 -11
  323. package/node_modules/pi-lens/scripts/lib/host-provided-deps.mjs +75 -0
  324. package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +285 -0
  325. package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +233 -0
  326. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +2 -0
  327. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +80 -3
  328. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +41 -0
  329. package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
  330. package/node_modules/pi-mcp-adapter/CHANGELOG.md +36 -0
  331. package/node_modules/pi-mcp-adapter/README.md +47 -5
  332. package/node_modules/pi-mcp-adapter/cli.js +163 -1
  333. package/node_modules/pi-mcp-adapter/commands.ts +128 -22
  334. package/node_modules/pi-mcp-adapter/config.ts +25 -7
  335. package/node_modules/pi-mcp-adapter/direct-tools.ts +5 -4
  336. package/node_modules/pi-mcp-adapter/index.ts +219 -32
  337. package/node_modules/pi-mcp-adapter/init.ts +36 -4
  338. package/node_modules/pi-mcp-adapter/lifecycle.ts +315 -24
  339. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +39 -6
  340. package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +387 -0
  341. package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +27 -3
  342. package/node_modules/pi-mcp-adapter/mcp-code.ts +4 -0
  343. package/node_modules/pi-mcp-adapter/mcp-panel.ts +42 -13
  344. package/node_modules/pi-mcp-adapter/metadata-cache.ts +32 -21
  345. package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
  346. package/node_modules/pi-mcp-adapter/package.json +3 -1
  347. package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
  348. package/node_modules/pi-mcp-adapter/request-headers-command.ts +31 -37
  349. package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
  350. package/node_modules/pi-mcp-adapter/server-manager.ts +140 -2
  351. package/node_modules/pi-mcp-adapter/session-recovery.ts +7 -0
  352. package/node_modules/pi-mcp-adapter/tool-approval.ts +15 -2
  353. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
  354. package/node_modules/pi-mcp-adapter/types.ts +2 -0
  355. package/node_modules/pi-mcp-adapter/ui-server.ts +18 -16
  356. package/node_modules/pi-mcp-adapter/utils.ts +70 -0
  357. package/node_modules/pi-web-access/CHANGELOG.md +37 -0
  358. package/node_modules/pi-web-access/README.md +32 -13
  359. package/node_modules/pi-web-access/anysearch.ts +4 -2
  360. package/node_modules/pi-web-access/brave.ts +16 -4
  361. package/node_modules/pi-web-access/chrome-cookies.ts +86 -15
  362. package/node_modules/pi-web-access/curator-page.ts +6 -3
  363. package/node_modules/pi-web-access/curator-server.ts +4 -1
  364. package/node_modules/pi-web-access/data-uri-sanitize.ts +406 -0
  365. package/node_modules/pi-web-access/exa.ts +18 -7
  366. package/node_modules/pi-web-access/extract.ts +40 -5
  367. package/node_modules/pi-web-access/firecrawl.ts +18 -2
  368. package/node_modules/pi-web-access/gemini-search.ts +16 -4
  369. package/node_modules/pi-web-access/github-extract.ts +65 -36
  370. package/node_modules/pi-web-access/index.ts +60 -61
  371. package/node_modules/pi-web-access/openai-search.ts +17 -6
  372. package/node_modules/pi-web-access/package.json +1 -1
  373. package/node_modules/pi-web-access/page-query.ts +4 -2
  374. package/node_modules/pi-web-access/parallel-mcp.ts +249 -0
  375. package/node_modules/pi-web-access/parallel.ts +2 -2
  376. package/node_modules/pi-web-access/pdf-extract.ts +18 -5
  377. package/node_modules/pi-web-access/query-rewrite.ts +51 -0
  378. package/node_modules/pi-web-access/serper.ts +211 -0
  379. package/node_modules/pi-web-access/ssrf-protection.ts +12 -2
  380. package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
  381. package/node_modules/pi-web-access/summary-review.ts +44 -22
  382. package/node_modules/pi-web-access/tavily.ts +16 -4
  383. package/node_modules/pi-web-access/utils.ts +87 -0
  384. package/node_modules/pi-web-access/valyu.ts +199 -0
  385. package/package.json +14 -14
@@ -13,7 +13,7 @@
13
13
  */
14
14
  import * as nodeFs from "node:fs";
15
15
  import * as path from "node:path";
16
- import { findNearestContaining } from "./path-utils.js";
16
+ import { findNearestContaining, normalizeEphemeralMapKey } from "./path-utils.js";
17
17
  import { recordFromDispatchDiagnostic, } from "./actionable-warnings.js";
18
18
  import { recordFromCodeQualityDiagnostic, } from "./code-quality-warnings.js";
19
19
  import { recordDiagnostics } from "./widget-state.js";
@@ -21,7 +21,7 @@ import { getDiagnosticLogger } from "./diagnostic-logger.js";
21
21
  import { getDiagnosticTracker } from "./diagnostic-tracker.js";
22
22
  import { loadDispatchIntegration } from "./dispatch/lazy.js";
23
23
  import { toRunnerDisplayPath } from "./dispatch/runner-context.js";
24
- import { createAvailabilityChecker, resolveAvailableOrInstall, resolveCommandArgsWithInstallFallback, resolveToolCommand, resolveToolCommandWithInstallFallback, } from "./dispatch/runners/utils/runner-helpers.js";
24
+ import { classifyProbeFailure, createAvailabilityChecker, createAvailabilityLatch, describeProbeEvidence, logAvailabilityDecision, startHostStallSampler, resolveAvailableOrInstall, resolveCommandArgsWithInstallFallback, resolveToolCommand, resolveToolCommandWithInstallFallback, } from "./dispatch/runners/utils/runner-helpers.js";
25
25
  import { findDetektConfig } from "./dispatch/runners/detekt.js";
26
26
  import { detectFileKind, getFileKindLabel } from "./file-kinds.js";
27
27
  import { detectFileChangedAfterCommand, getProjectIgnoreMatcher, isExcludedDirName, } from "./file-utils.js";
@@ -178,6 +178,13 @@ function createPhaseTracker(toolName, filePath) {
178
178
  }
179
179
  // --- ESLint autofix helpers ---
180
180
  export { hasEslintConfig, hasRubocopConfig, hasSqlfluffConfig, hasStylelintConfig, };
181
+ /**
182
+ * eslint autofix availability, per cwd + PATH. The verdict is owned by the
183
+ * shared availability latch (#1494): a `missing` / `non-installable` outcome
184
+ * sticks for the session, a timeout expires on a cooldown and is re-probed, so
185
+ * one stalled probe cannot silently stop autofixing a project's JS/TS.
186
+ */
187
+ const ESLINT_FIX_PROBE_BUDGET_MS = 5000;
181
188
  const _eslintCache = new BoundedLruCache(32);
182
189
  /**
183
190
  * Run eslint --fix on a file. Runs a single spawn and diffs the file before/after,
@@ -196,18 +203,70 @@ async function tryEslintFix(filePath, cwd) {
196
203
  const cacheKey = `${path.resolve(cwd)}|${process.env.PATH ?? ""}`;
197
204
  let cached = _eslintCache.get(cacheKey);
198
205
  if (!cached) {
199
- const candidate = resolveToolCommand(cwd, "eslint") ?? "eslint";
200
- const check = await safeSpawnAsync(candidate, ["--version"], {
201
- timeout: 5000,
202
- cwd,
203
- });
204
- cached = {
205
- available: !check.error && check.status === 0,
206
- bin: !check.error && check.status === 0 ? candidate : null,
207
- };
206
+ cached = { latch: createAvailabilityLatch(), bin: null };
208
207
  _eslintCache.set(cacheKey, cached);
209
208
  }
210
- if (!cached.available || !cached.bin)
209
+ if (cached.latch.read() === null) {
210
+ const candidate = resolveToolCommand(cwd, "eslint") ?? "eslint";
211
+ // The budget is enforced by a HOST-side timer, so a stalled event loop
212
+ // expires it while eslint is still healthy. Measure the overlapping stall
213
+ // and hand it to the classifier, exactly like the runner path: without it a
214
+ // host-stall timeout is re-caused as `probe-timeout` and gets the escalating
215
+ // 30s→300s cooldown instead of the 5s host-stall one (#1467).
216
+ const stallSampler = startHostStallSampler();
217
+ const startedAt = Date.now();
218
+ let check;
219
+ let hostStallMs;
220
+ try {
221
+ check = await safeSpawnAsync(candidate, ["--version"], {
222
+ timeout: ESLINT_FIX_PROBE_BUDGET_MS,
223
+ cwd,
224
+ });
225
+ }
226
+ finally {
227
+ hostStallMs = stallSampler.stop();
228
+ }
229
+ const elapsedMs = Date.now() - startedAt;
230
+ const decisionCwd = path.resolve(cwd);
231
+ if (!check.error && check.status === 0) {
232
+ cached.bin = candidate;
233
+ cached.latch.noteAvailable();
234
+ logAvailabilityDecision({
235
+ tool: "eslint",
236
+ verdict: "available",
237
+ outcome: "success",
238
+ cause: "ok",
239
+ elapsedMs,
240
+ latched: true,
241
+ hostStallMs,
242
+ budgetMs: ESLINT_FIX_PROBE_BUDGET_MS,
243
+ classifiedBy: "probe",
244
+ evidence: describeProbeEvidence(check, "eslint"),
245
+ }, decisionCwd);
246
+ }
247
+ else {
248
+ cached.bin = null;
249
+ const { outcome, cause, evidence } = classifyProbeFailure(check, {
250
+ hostStallMs,
251
+ command: "eslint",
252
+ });
253
+ const retryAfterMs = cached.latch.noteUnavailable(outcome, cause);
254
+ logAvailabilityDecision({
255
+ tool: "eslint",
256
+ verdict: "unavailable",
257
+ outcome,
258
+ cause,
259
+ elapsedMs,
260
+ latched: retryAfterMs === 0,
261
+ hostStallMs,
262
+ ...(retryAfterMs > 0 && { retryAfterMs }),
263
+ budgetMs: ESLINT_FIX_PROBE_BUDGET_MS,
264
+ classifiedBy: "probe",
265
+ evidence,
266
+ }, decisionCwd);
267
+ }
268
+ }
269
+ if (cached.latch.read() !== true || !cached.bin)
211
270
  return 0;
212
271
  const cmd = cached.bin;
213
272
  return detectFileChangedAfterCommand(filePath, cmd, ["--fix", "--no-error-on-unmatched-pattern", filePath], cwd, [1]);
@@ -650,6 +709,24 @@ export async function resyncLspFile(filePath, fileContent, needsContentRefresh,
650
709
  if (outcome === "bailed") {
651
710
  // Abandon the still-pending write; the edit continues. Log it so this
652
711
  // stall — previously an invisible hang — is queryable in latency.log.
712
+ //
713
+ // #1766: a resync deadline can expire while the target server's FIRST
714
+ // spawn is still in flight (cold spawn > budget). That is not the same
715
+ // state as a running server that stalled on a write — the server the
716
+ // old wording blamed as "slow/wedged" did not exist yet. Distinguish
717
+ // the two via a fresh, synchronous inFlight lookup so the record keeps
718
+ // the discriminating identity (which server, which lifecycle state).
719
+ // Guarded: a test double or future service shape lacking the method
720
+ // must degrade to the old "timeout"/slow-wedged wording, not throw
721
+ // into the catch below and suppress this record entirely (#1766 F3).
722
+ const spawnInFlight = !abort?.aborted &&
723
+ typeof lspService.isSpawnInFlight === "function" &&
724
+ lspService.isSpawnInFlight(filePath);
725
+ const reason = abort?.aborted
726
+ ? "aborted"
727
+ : spawnInFlight
728
+ ? "spawn-in-flight"
729
+ : "timeout";
653
730
  logLatency({
654
731
  type: "phase",
655
732
  phase: "lsp_sync_abandoned",
@@ -657,11 +734,16 @@ export async function resyncLspFile(filePath, fileContent, needsContentRefresh,
657
734
  durationMs: Date.now() - startedAt,
658
735
  metadata: {
659
736
  source: "lsp_sync",
660
- reason: abort?.aborted ? "aborted" : "timeout",
737
+ reason,
661
738
  budgetMs,
662
739
  },
663
740
  });
664
- dbg(`LSP resync ${abort?.aborted ? "aborted (Escape)" : `timed out after ${budgetMs}ms`}; server slow/wedged for ${filePath}`);
741
+ const cause = abort?.aborted
742
+ ? "aborted (Escape)"
743
+ : spawnInFlight
744
+ ? `timed out after ${budgetMs}ms; reason: spawn-in-flight (server still cold-spawning)`
745
+ : `timed out after ${budgetMs}ms; server slow/wedged`;
746
+ dbg(`LSP resync ${cause} for ${filePath}`);
665
747
  }
666
748
  }
667
749
  }
@@ -1007,24 +1089,16 @@ export async function runPipeline(ctx, deps) {
1007
1089
  : "";
1008
1090
  output += `\n\n⚠️ Auto-format failed: ${details}${suffix}`;
1009
1091
  }
1010
- if (formatChanged || fixedCount > 0) {
1011
- const changedList = [...piChangedFiles].map((changedFile) => toRunnerDisplayPath(cwd, changedFile));
1012
- const topFiles = changedList
1013
- .slice(0, 8)
1014
- .map((f) => " - " + f)
1015
- .join("\n");
1016
- const overflow = changedList.length > 8
1017
- ? "\n - ... and " + (changedList.length - 8) + " more"
1018
- : "";
1019
- const fileList = changedList.length
1020
- ? "\nModified files:\n" + topFiles + overflow
1021
- : "";
1022
- const targetHasAuthoritativeAttachment = ctx.autofixMode !== "deferred" &&
1023
- autofixChangedFiles.some((changedFile) => path.resolve(changedFile) === path.resolve(filePath));
1024
- output += targetHasAuthoritativeAttachment
1025
- ? `\n\n⚠️ **The attached full content for ${toRunnerDisplayPath(cwd, filePath)} is authoritative after autofix. You MUST re-read any other modified side-effect files before editing them.**${fileList}`
1026
- : `\n\n⚠️ **File was modified by auto-format/fix. You MUST re-read modified file(s) before making any further edits — the content on disk has changed (whitespace, indentation, quotes, or code). Editing from memory will produce mismatches.**${fileList}`;
1027
- }
1092
+ // #1590: the notice sentence itself is NOT rendered here. This layer cannot
1093
+ // see the attachment cap or the aggregate budget, so it hands the display
1094
+ // paths to `handleToolResult`, which owns the decision and renders the one
1095
+ // sentence with `renderPostAutofixNotice`.
1096
+ const postAutofixNotice = formatChanged || fixedCount > 0
1097
+ ? {
1098
+ targetPath: toRunnerDisplayPath(cwd, filePath),
1099
+ changedFiles: [...piChangedFiles].map((changedFile) => toRunnerDisplayPath(cwd, changedFile)),
1100
+ }
1101
+ : undefined;
1028
1102
  phase.end("dispatch_lint", {
1029
1103
  hasOutput: !!dispatchResult.output,
1030
1104
  diagnosticCount: dispatchResult.diagnostics.length,
@@ -1048,6 +1122,7 @@ export async function runPipeline(ctx, deps) {
1048
1122
  turnSeq: ctx.telemetry?.turnIndex,
1049
1123
  writeSeq: ctx.telemetry?.writeIndex,
1050
1124
  seqState: ctx.seqState,
1125
+ turnEndCascadeSettleStart: ctx.turnEndCascadeSettleStart,
1051
1126
  fileContent,
1052
1127
  wordIndex: ctx.wordIndex,
1053
1128
  onWordIndexUpdated: ctx.onWordIndexUpdated,
@@ -1072,7 +1147,10 @@ export async function runPipeline(ctx, deps) {
1072
1147
  });
1073
1148
  // --- Final timing + all-clear ---
1074
1149
  const elapsed = Date.now() - pipelineStart;
1075
- if (!output) {
1150
+ // #1590: `postAutofixNotice` is output this run produces, just rendered a
1151
+ // layer up. Treat it as output here, or a format-only change would newly
1152
+ // gain an "all clear" line it never had while the sentence lived inline.
1153
+ if (!output && !postAutofixNotice) {
1076
1154
  output = buildAllClearOutput(dispatchResult, elapsed, filePath);
1077
1155
  }
1078
1156
  phase.end("total", { hasOutput: !!output });
@@ -1106,12 +1184,55 @@ export async function runPipeline(ctx, deps) {
1106
1184
  inlineBlockerSummary: dispatchResult.hasBlockers
1107
1185
  ? dispatchResult.blockerOutput.trim() || undefined
1108
1186
  : undefined,
1187
+ // #1561 F1: taken from the very diagnostics `blockerOutput` was rendered
1188
+ // from, so the provenance can never disagree with the text it guards. An
1189
+ // untagged diagnostic contributes the literal "unknown", which no verdict
1190
+ // claims coverage for — it pins the entry rather than silently widening
1191
+ // what an LSP check is allowed to clear.
1192
+ inlineBlockerSources: dispatchResult.hasBlockers
1193
+ ? [
1194
+ ...new Set(dispatchResult.blockers.map((d) => d.tool?.trim() || "unknown")),
1195
+ ]
1196
+ : undefined,
1197
+ inlineBlockerLines: dispatchResult.hasBlockers
1198
+ ? dispatchResult.blockers
1199
+ // #1641 review F2: `dispatchResult.blockers` is NOT guaranteed to be
1200
+ // scoped to THIS file — a chart-wide runner (helm-lint, helm-render)
1201
+ // reports blocking diagnostics against other files in the chart
1202
+ // (e.g. `values.yaml`) alongside `ctx.filePath`. The precedent every
1203
+ // per-file runner already follows (dotnet-build.ts, javac.ts) is to
1204
+ // drop cross-file rows before they reach a per-file record; this is
1205
+ // that same filter applied at the aggregation point instead, since
1206
+ // `blockers` is pooled across every runner dispatched for this file.
1207
+ // Without it, a cross-file line count gets attributed to THIS
1208
+ // file's past-EOF check and can demote an in-bounds, fully valid
1209
+ // blocker for content the diagnostic never described.
1210
+ //
1211
+ // #1641 review round 2 (LOW): `path.resolve` equality doesn't fold
1212
+ // case, and an LSP-sourced diagnostic's `filePath` is stamped with
1213
+ // realpath canonical casing (dispatch/runners/lsp.ts ->
1214
+ // normalizeMapKey) while `ctx.filePath` can arrive lowercase-drive
1215
+ // on Windows — the drive-letter class from #1139/#1150. A bare
1216
+ // `path.resolve` equality then drops EVERY LSP blocker line and
1217
+ // this record silently skips the past-EOF gate (fail-open, but
1218
+ // exactly the pre-fix behavior on the surface #1641 targets).
1219
+ // `normalizeEphemeralMapKey` slash-folds and (on win32)
1220
+ // lowercase-folds both sides with no filesystem I/O — cheap enough
1221
+ // for this per-blocker hot-path filter. `pathsEqual` was
1222
+ // deliberately NOT used here: it calls `realpathSync` per
1223
+ // comparison, which this filter cannot afford per blocker.
1224
+ .filter((d) => normalizeEphemeralMapKey(d.filePath) ===
1225
+ normalizeEphemeralMapKey(filePath))
1226
+ .map((d) => d.line)
1227
+ .filter((line) => typeof line === "number")
1228
+ : undefined,
1109
1229
  actionableWarnings,
1110
1230
  codeQualityWarnings,
1111
1231
  diagnostics: dispatchResult.diagnostics,
1112
1232
  formattersUsed,
1113
1233
  fixedCount,
1114
1234
  autofixTools,
1235
+ postAutofixNotice,
1115
1236
  postMutation: ctx.autofixMode !== "deferred" && autofixChangedFiles.some((f) => path.resolve(f) === path.resolve(filePath)) && fileContent !== undefined
1116
1237
  ? { filePath: path.resolve(filePath), content: fileContent, source: "autofix" }
1117
1238
  : undefined,
@@ -0,0 +1,37 @@
1
+ /**
2
+ * The single post-autofix instruction about a written file (#1590).
3
+ *
4
+ * Two layers used to phrase this. `clients/pipeline.ts` claimed "the attached
5
+ * full content is authoritative" from changed-file membership alone, and
6
+ * `clients/runtime-tool-result.ts` — the only layer that sees the per-file
7
+ * attachment cap and the per-command aggregate budget — appended "too large to
8
+ * attach" for the same file. On a size-capped write the agent got both.
9
+ *
10
+ * The wording now lives here, and `handleToolResult` is the only caller: the
11
+ * pipeline supplies the data (display paths it already resolved) and the layer
12
+ * that made the attachment decision picks the sentence. Keeping the renderer
13
+ * out of `pipeline.ts` also keeps it real in tests that mock the pipeline away.
14
+ */
15
+ /** Render the ONE post-autofix instruction for `decision`. */
16
+ export function renderPostAutofixNotice(notice, decision) {
17
+ const topFiles = notice.changedFiles
18
+ .slice(0, 8)
19
+ .map((f) => " - " + f)
20
+ .join("\n");
21
+ const overflow = notice.changedFiles.length > 8
22
+ ? "\n - ... and " + (notice.changedFiles.length - 8) + " more"
23
+ : "";
24
+ const fileList = notice.changedFiles.length
25
+ ? "\nModified files:\n" + topFiles + overflow
26
+ : "";
27
+ switch (decision) {
28
+ case "attached":
29
+ return `⚠️ **The attached full content for ${notice.targetPath} is authoritative after autofix. You MUST re-read any other modified side-effect files before editing them.**${fileList}`;
30
+ case "size-capped":
31
+ return `⚠️ **File was modified by auto-format/fix. You MUST re-read ${notice.targetPath} before making any further edits — the authoritative content is too large to attach.**${fileList}`;
32
+ case "aggregate-budget-degraded":
33
+ return `⚠️ **File was modified by auto-format/fix. You MUST re-read ${notice.targetPath} before making any further edits — the aggregate authoritative content for this command is too large to attach.**${fileList}`;
34
+ default:
35
+ return `⚠️ **File was modified by auto-format/fix. You MUST re-read modified file(s) before making any further edits — the content on disk has changed (whitespace, indentation, quotes, or code). Editing from memory will produce mismatches.**${fileList}`;
36
+ }
37
+ }
@@ -3,6 +3,7 @@ import * as path from "node:path";
3
3
  import { getProjectDataDir } from "../file-utils.js";
4
4
  import { writeFileAtomic } from "../atomic-write.js";
5
5
  import { readJsonCache } from "../json-cache-read.js";
6
+ import { MTIME_DRIFT_TOLERANCE_MS } from "../blocker-freshness.js";
6
7
  // v2: cheap-tier scan now also runs ast-grep-napi (#308); invalidate older
7
8
  // snapshots so a pre-ast-grep cache isn't served as complete via refreshRunners=cached.
8
9
  export const PROJECT_DIAGNOSTICS_CACHE_VERSION = 2;
@@ -47,7 +48,8 @@ export function writeProjectDiagnosticsDeltaReport(cwd, report) {
47
48
  }
48
49
  /**
49
50
  * Drop diagnostics whose underlying file changed on disk after the snapshot was
50
- * taken (`mtimeMs > scannedAt`) or no longer exists. The persisted snapshot is a
51
+ * taken (`mtimeMs > scannedAt + MTIME_DRIFT_TOLERANCE_MS`) or no longer
52
+ * exists. The persisted snapshot is a
51
53
  * cross-session cache served by `lens_diagnostics mode=full refreshRunners=cached`;
52
54
  * without this it replays diagnostics the agent has since fixed or for files that
53
55
  * were deleted (#298 — "the cache needs to be cleaned before running diagnostics
@@ -56,6 +58,15 @@ export function writeProjectDiagnosticsDeltaReport(cwd, report) {
56
58
  * stays a pure reader. Synchronous (a `statSync` per *distinct* file, memoised),
57
59
  * since the cached full-mode path is already off the typing hot loop.
58
60
  *
61
+ * The boundary is `mtime > scannedAt + MTIME_DRIFT_TOLERANCE_MS`
62
+ * (`blocker-freshness.ts`), not a bare `mtime > scannedAt`: #1711 found this
63
+ * consumer's old +1ms slack did not cover the measured Windows host skew
64
+ * between a file's mtime and the `Date.now()` read that produces `scannedAt`
65
+ * (up to ~11.4ms, #1491/#1498) — a same-tick write-then-scan silently
66
+ * dropped a live finding here, worse than `findingPathFreshness`'s sibling
67
+ * gate (#1708) since this arm DROPS rather than demotes. Reusing the shared
68
+ * constant keeps one source of truth for the measured skew.
69
+ *
59
70
  * Fail-safe on an unparseable `scannedAt`: return the snapshot untouched rather
60
71
  * than risk dropping live findings on a clock/format anomaly.
61
72
  */
@@ -70,8 +81,11 @@ export function reconcileProjectDiagnosticsSnapshot(snapshot) {
70
81
  return cached;
71
82
  let stale;
72
83
  try {
73
- // +1ms tolerance: a file scanned at scannedAt has mtime <= scannedAt.
74
- stale = fs.statSync(filePath).mtimeMs > scannedAtMs + 1;
84
+ // MTIME_DRIFT_TOLERANCE_MS: a file scanned at scannedAt, or written
85
+ // within the tolerance window of the scan timestamp being captured,
86
+ // has mtime <= scannedAt + MTIME_DRIFT_TOLERANCE_MS.
87
+ stale =
88
+ fs.statSync(filePath).mtimeMs > scannedAtMs + MTIME_DRIFT_TOLERANCE_MS;
75
89
  }
76
90
  catch {
77
91
  stale = true; // deleted / unreadable → drop
@@ -1,25 +1,3 @@
1
- /**
2
- * Provenance metadata for the heavyweight project analyzers surfaced in
3
- * `lens_diagnostics mode=full`.
4
- *
5
- * NOTE (#585 regression cleanup): this module USED to also own
6
- * `extractCachedProjectDiagnostics` — a CACHE-ONLY reader that adapted each
7
- * analyzer's cached result to `ProjectDiagnostic[]` via a parallel `EXTRACTORS`
8
- * registry. #585 replaced that reader in production with
9
- * `fetchFreshProjectDiagnostics` (./fresh-fetch.ts), which triggers-or-joins a
10
- * fresh run instead of settling for a possibly-hours-stale session_start
11
- * snapshot. The old reader lingered here wired only to a test — a SECOND,
12
- * dead surfacing path whose registry could (and did) silently diverge from
13
- * fresh-fetch's `ANALYZER_IDS`: opengrep was registered here but missing there,
14
- * so opengrep scanned+cached yet never reached the agent (the exact #585-class
15
- * regression this cleanup removes). The parallel registry is gone; fresh-fetch
16
- * is the single source of truth (#883).
17
- *
18
- * What survives is the honesty metadata (#533): given an analyzer id that
19
- * fresh-fetch reported `cold` (not applicable / unavailable this run),
20
- * `warmTriggerFor` names what WOULD warm it, so the rendered note is actionable
21
- * rather than a bare "not run".
22
- */
23
1
  /**
24
2
  * #533: which trigger warms each analyzer, surfaced in the "cold" honesty note
25
3
  * so the note is actionable (names what to do), matching the #511/#514 house
@@ -40,3 +18,92 @@ const WARM_TRIGGER = {
40
18
  export function warmTriggerFor(analyzerId) {
41
19
  return WARM_TRIGGER[analyzerId] ?? "runs at session-start";
42
20
  }
21
+ /**
22
+ * #1623: single formatter for a "not run" lane entry — reused by every
23
+ * caller that renders `fetchFreshProjectDiagnostics`'s `cold` list (today,
24
+ * `tools/lens-diagnostics.ts`'s mode=full) so the wording can't drift
25
+ * per-caller. Prefers the SPECIFIC reason captured at the decision point
26
+ * (`coldReasons`, ./fresh-fetch.ts) over the generic `warmTriggerFor` guess —
27
+ * the latter only remains a fallback for a `cold` id this map doesn't cover.
28
+ */
29
+ export function formatNotRunEntry(analyzerId, coldReasons) {
30
+ const reason = coldReasons?.[analyzerId];
31
+ return reason
32
+ ? `${analyzerId} — not run (${reason})`
33
+ : `${analyzerId} — not run (${warmTriggerFor(analyzerId)})`;
34
+ }
35
+ /**
36
+ * #1623: human-readable age, for a lane whose result was served from cache
37
+ * rather than executed fresh this call (see `cachedAgeMs`, ./fresh-fetch.ts).
38
+ * Mirrors the granularity an agent actually needs to judge staleness — exact
39
+ * seconds don't matter, "12m" vs "3h" does.
40
+ */
41
+ export function formatCacheAge(ms) {
42
+ // #1623 fix-round F4: `CacheManager.readCache` accepts a missing/corrupt
43
+ // `meta.timestamp` as a HIT (the timestamp only gates staleness, not
44
+ // validity), so `Date.now() - new Date(badTimestamp).getTime()` reaches
45
+ // here as NaN. Rendering "NaNh old" is a worse honesty gap than the one
46
+ // this whole module exists to close — say the age is unknown instead of
47
+ // fabricating one. Mirrors the sibling `Number.isFinite` guard in
48
+ // `./cache.ts`'s `reconcileProjectDiagnosticsSnapshot` (fail-safe on an
49
+ // unparseable timestamp rather than propagate NaN).
50
+ if (!Number.isFinite(ms))
51
+ return "age unknown";
52
+ if (ms < 0)
53
+ return "0m";
54
+ const totalMinutes = Math.round(ms / 60_000);
55
+ if (totalMinutes < 1)
56
+ return "under 1m";
57
+ if (totalMinutes < 60)
58
+ return `${totalMinutes}m`;
59
+ const hours = Math.floor(totalMinutes / 60);
60
+ const minutes = totalMinutes % 60;
61
+ return minutes > 0 ? `${hours}h${minutes}m` : `${hours}h`;
62
+ }
63
+ /**
64
+ * #1623 fix-round F5: the full "<age> old" phrase for a cache-read lane.
65
+ * Every render call site used to append the literal word " old" after
66
+ * `formatCacheAge` itself, so a corrupt/missing timestamp's "age unknown"
67
+ * came out as the ungrammatical "age unknown old" — the exact residual the
68
+ * issue's tracking comment named. "Old" only makes sense once an age is
69
+ * actually known, so this is the single place that decides whether to say
70
+ * it, instead of every caller repeating (and occasionally forgetting) the
71
+ * same guard.
72
+ */
73
+ export function formatCacheAgeOld(ms) {
74
+ const age = formatCacheAge(ms);
75
+ return Number.isFinite(ms) ? `${age} old` : age;
76
+ }
77
+ /**
78
+ * #1623 fix-round F1: a "cold" reason for an analyzer whose `ensureAvailable()`
79
+ * returned false, built from the SAME `AvailabilityOutcome`/`AvailabilityCause`
80
+ * taxonomy every dispatch-side unavailability message already uses
81
+ * (`describeUnavailability`, availability-policy.ts) — not a re-guessed
82
+ * "binary unavailable" for every failure shape.
83
+ *
84
+ * `ensureAvailable() === false` collapses at least three distinct causes: a
85
+ * durable absence (`missing`), a transient probe under an active retry
86
+ * cooldown (`transient`), and — for govulncheck specifically — a project-trust
87
+ * install denial the latch never even records (`assertInstallAllowed` returns
88
+ * before touching it, project-trust.ts). fresh-fetch.ts's govulncheck task
89
+ * checks trust denial itself, via `projectTrustDenialReason()`, before
90
+ * falling back to this function. Wording a cooldown as "unavailable" would
91
+ * repeat, one layer up, exactly the dispatch-layer defect #1467 fixed.
92
+ */
93
+ export function reasonFromAvailabilityVerdict(tool, verdict) {
94
+ if (!verdict || verdict.outcome === null)
95
+ return `${tool} binary unavailable`;
96
+ const { outcome, cause } = verdict;
97
+ if (outcome === "transient") {
98
+ if (cause === "install-retry-exhausted") {
99
+ return `${tool} install kept timing out and hit its retry ceiling this session (not reported missing)`;
100
+ }
101
+ const remainingMs = verdict.retryAtMs - Date.now();
102
+ const remainingS = remainingMs > 0 ? Math.round(remainingMs / 1000) : 0;
103
+ return `${tool} availability probe — retry cooldown (${remainingS}s), not a missing install`;
104
+ }
105
+ if (outcome === "non-installable") {
106
+ return `${tool} unavailable on this host (non-installable)`;
107
+ }
108
+ return `${tool} binary unavailable`;
109
+ }