@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
@@ -82,11 +82,14 @@
82
82
  */
83
83
  import * as fs from "node:fs";
84
84
  import * as path from "node:path";
85
+ import { applyDispositionsMultiFile } from "../diagnostic-dispositions.js";
85
86
  import { getKnipIgnorePatterns } from "../file-utils.js";
86
87
  import { isAtOrAboveHomeDir } from "../path-utils.js";
87
88
  import { GitleaksClient } from "../gitleaks-client.js";
88
89
  import { GovulncheckClient } from "../govulncheck-client.js";
90
+ import { isToolInstallAllowedByTrust, projectTrustDenialReason, } from "../project-trust.js";
89
91
  import { TrivyClient } from "../trivy-client.js";
92
+ import { reasonFromAvailabilityVerdict } from "./extractors.js";
90
93
  import { deadCodeResultToProjectDiagnostics } from "./runner-adapters/dead-code.js";
91
94
  import { gitleaksResultToProjectDiagnostics } from "./runner-adapters/gitleaks.js";
92
95
  import { govulncheckResultToProjectDiagnostics } from "./runner-adapters/govulncheck.js";
@@ -141,11 +144,13 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
141
144
  // / review-graph's buildOrUpdateGraph; like the latter, there is no safe
142
145
  // substitute root to fall back to — the caller's `paths` scope only filters
143
146
  // REPORTED results, it never narrows what these analyzers walk.
147
+ const unsafeRootReason = "the working directory resolves at or above the home directory; heavyweight analyzers refuse to walk from there (#747)";
144
148
  if (isAtOrAboveHomeDir(analysisRoot, options.homeDir)) {
145
149
  return {
146
150
  diagnostics: [],
147
151
  runners: [],
148
152
  cold: [...ANALYZER_IDS],
153
+ coldReasons: Object.fromEntries(ANALYZER_IDS.map((id) => [id, unsafeRootReason])),
149
154
  failed: [],
150
155
  timings: {},
151
156
  unsafeRoot: true,
@@ -154,13 +159,46 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
154
159
  const diagnostics = [];
155
160
  const runners = [];
156
161
  const cold = [];
162
+ // #1623: the specific reason each `cold` id was skipped, captured at the
163
+ // gate that decided it — see FreshProjectDiagnosticsResult.coldReasons.
164
+ const coldReasons = {};
157
165
  const failed = [];
158
166
  const timings = {};
167
+ // #1623: ms-old each id's data was when this call read it, for lanes that
168
+ // are cache-reads by design (currently only test-runner — see its task
169
+ // below) rather than a fresh execution this call. Absent for every other
170
+ // key: this module's other lanes always trigger-or-join a genuine run
171
+ // when attempted (see the module header), so there is nothing to date.
172
+ const cachedAgeMs = {};
159
173
  const settledIds = new Set();
174
+ let dispositionSuppressed = 0;
175
+ const dispositionSuppressedByLane = {};
176
+ // #1617: this is the ONE choke point every analyzer's findings pass
177
+ // through on the way into `diagnostics`, so applying the agent/user
178
+ // disposition filter HERE covers the whole mode=full class (knip/jscpd/
179
+ // madge/gitleaks/govulncheck/opengrep/trivy/dead-code) in one place — the
180
+ // same anchor derivation `dispatcher.ts:924` uses, via
181
+ // `applyDispositionsMultiFile` (`diagnostic-dispositions.ts`), not a
182
+ // second cloned filter. Unlike the dispatch path's one-file-at-a-time
183
+ // shape, a project-wide scan's findings span many files, so this groups by
184
+ // each diagnostic's own `filePath` and reads each file's current content
185
+ // once — see that function's doc for the fail-open contract when a file
186
+ // can't be read.
187
+ function markCold(id, reason) {
188
+ pushUnique(cold, id);
189
+ coldReasons[id] = reason;
190
+ }
160
191
  function record(id, adapted, elapsedMs) {
161
192
  timings[id] = (timings[id] ?? 0) + elapsedMs;
162
- if (adapted.length > 0) {
163
- diagnostics.push(...adapted);
193
+ const kept = applyDispositionsMultiFile(adapted, analysisRoot, (d) => d.filePath);
194
+ const suppressedHere = adapted.length - kept.length;
195
+ dispositionSuppressed += suppressedHere;
196
+ if (suppressedHere > 0) {
197
+ dispositionSuppressedByLane[id] =
198
+ (dispositionSuppressedByLane[id] ?? 0) + suppressedHere;
199
+ }
200
+ if (kept.length > 0) {
201
+ diagnostics.push(...kept);
164
202
  pushUnique(runners, id);
165
203
  }
166
204
  }
@@ -194,7 +232,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
194
232
  // detection, exactly mirroring session_start's own logic.
195
233
  task("jscpd", async () => {
196
234
  if (!(await clients.jscpdClient.ensureAvailable())) {
197
- cold.push("jscpd");
235
+ markCold("jscpd", reasonFromAvailabilityVerdict("jscpd", clients.jscpdClient.getAvailabilityVerdict?.()));
198
236
  return;
199
237
  }
200
238
  const isTsProject = fs.existsSync(path.join(analysisRoot, "tsconfig.json"));
@@ -213,7 +251,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
213
251
  // madge — circular-dependency detection.
214
252
  task("madge", async () => {
215
253
  if (!(await clients.depChecker.ensureAvailable())) {
216
- cold.push("madge");
254
+ markCold("madge", reasonFromAvailabilityVerdict("madge", clients.depChecker.getAvailabilityVerdict?.()));
217
255
  return;
218
256
  }
219
257
  const startMs = Date.now();
@@ -234,11 +272,11 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
234
272
  // "cold" on a project with no explicit gitleaks config.
235
273
  task("gitleaks", async () => {
236
274
  if (!GitleaksClient.hasGitRepo(analysisRoot)) {
237
- cold.push("gitleaks");
275
+ markCold("gitleaks", "not a git repository (no .git found)");
238
276
  return;
239
277
  }
240
278
  if (!(await clients.gitleaksClient.ensureAvailable())) {
241
- cold.push("gitleaks");
279
+ markCold("gitleaks", reasonFromAvailabilityVerdict("gitleaks", clients.gitleaksClient.getAvailabilityVerdict?.()));
242
280
  return;
243
281
  }
244
282
  const startMs = Date.now();
@@ -257,11 +295,22 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
257
295
  // govulncheck — Go module CVE detection. Go-module-gated per #132.
258
296
  task("govulncheck", async () => {
259
297
  if (!GovulncheckClient.hasGoModule(analysisRoot)) {
260
- cold.push("govulncheck");
298
+ markCold("govulncheck", "no go.mod found (not a Go module)");
261
299
  return;
262
300
  }
263
301
  if (!(await clients.govulncheckClient.ensureAvailable())) {
264
- cold.push("govulncheck");
302
+ // #1623 fix-round F1: `GovulncheckClient.doEnsureAvailable` has a
303
+ // branch (`assertInstallAllowed`, govulncheck-client.ts) that returns
304
+ // false WITHOUT ever touching its availability latch — a
305
+ // project-trust install denial, deliberately not latched so a later
306
+ // trust grant can retry (see that file's own comment). The latch's
307
+ // verdict is genuinely absent in that case, not merely unread, so
308
+ // check trust denial FIRST via the same taxonomy project-trust.ts
309
+ // already exposes, and only fall back to the probe-based verdict
310
+ // (a real timeout/absence) when trust isn't the reason.
311
+ markCold("govulncheck", isToolInstallAllowedByTrust()
312
+ ? reasonFromAvailabilityVerdict("govulncheck", clients.govulncheckClient.getAvailabilityVerdict?.())
313
+ : (projectTrustDenialReason() ?? "govulncheck binary unavailable"));
265
314
  return;
266
315
  }
267
316
  const startMs = Date.now();
@@ -291,7 +340,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
291
340
  // `lens_diagnostics mode=full` — the honesty gap (#533) this task closes.
292
341
  task("opengrep", async () => {
293
342
  if (!(await clients.opengrepClient.ensureAvailable())) {
294
- cold.push("opengrep");
343
+ markCold("opengrep", reasonFromAvailabilityVerdict("opengrep", clients.opengrepClient.getAvailabilityVerdict?.()));
295
344
  return;
296
345
  }
297
346
  const startMs = Date.now();
@@ -308,11 +357,11 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
308
357
  // trivy — dependency CVE detection. Explicit opt-in per #131.
309
358
  task("trivy", async () => {
310
359
  if (!TrivyClient.shouldScan(analysisRoot)) {
311
- cold.push("trivy");
360
+ markCold("trivy", "not opted in (.pi-lens.json trivy.enabled) or no dependency manifest found");
312
361
  return;
313
362
  }
314
363
  if (!(await clients.trivyClient.ensureAvailable())) {
315
- cold.push("trivy");
364
+ markCold("trivy", reasonFromAvailabilityVerdict("trivy", clients.trivyClient.getAvailabilityVerdict?.()));
316
365
  return;
317
366
  }
318
367
  const startMs = Date.now();
@@ -332,7 +381,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
332
381
  task("dead-code", async () => {
333
382
  const applicable = clients.deadCodeClients.filter((c) => c.detect(analysisRoot));
334
383
  if (applicable.length === 0) {
335
- cold.push("dead-code");
384
+ markCold("dead-code", "no dead-code client detected an applicable language for this project");
336
385
  return;
337
386
  }
338
387
  await Promise.all(applicable.map(async (client) => {
@@ -380,9 +429,16 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
380
429
  const startMs = Date.now();
381
430
  const cached = cacheManager.readCache("test-runner-findings", analysisRoot);
382
431
  if (!cached?.data) {
383
- cold.push("test-runner");
432
+ markCold("test-runner", "no turn_end test-runner cache entry yet this session");
384
433
  return;
385
434
  }
435
+ // #1623: unlike every other lane in this module, test-runner is a
436
+ // cache-read BY DESIGN (see the task's own header comment above) — it
437
+ // never performs a fresh run this call, so its age must be surfaced
438
+ // the same way a genuinely-stale cache read would be, rather than
439
+ // looking indistinguishable from a lane that just executed.
440
+ cachedAgeMs["test-runner"] =
441
+ Date.now() - new Date(cached.meta.timestamp).getTime();
386
442
  record("test-runner", testRunnerFindingsToProjectDiagnostics(cached.data, analysisRoot, options.runtime), Date.now() - startMs);
387
443
  }),
388
444
  ];
@@ -414,11 +470,25 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
414
470
  diagnostics,
415
471
  runners,
416
472
  cold,
473
+ coldReasons,
417
474
  failed,
418
475
  timings,
476
+ cachedAgeMs,
419
477
  aborted: true,
420
478
  abortedIds,
479
+ dispositionSuppressed,
480
+ dispositionSuppressedByLane,
421
481
  };
422
482
  }
423
- return { diagnostics, runners, cold, failed, timings };
483
+ return {
484
+ diagnostics,
485
+ runners,
486
+ cold,
487
+ coldReasons,
488
+ failed,
489
+ timings,
490
+ cachedAgeMs,
491
+ dispositionSuppressed,
492
+ dispositionSuppressedByLane,
493
+ };
424
494
  }
@@ -2,19 +2,31 @@ import * as path from "node:path";
2
2
  /**
3
3
  * A gitleaks finding is a leaked secret at a concrete `file:startLine`. Secrets
4
4
  * are treated as **blocking** — a committed credential is not a style nit.
5
+ *
6
+ * Exception: `pathStatus: "scratch"` (#1562 review-round F2) — a finding
7
+ * `classifyAndFilterFindings` demoted rather than dropped, so the observability
8
+ * criterion ("record carries tracked/ignored/scratch status") stays honest
9
+ * about a fourth REACHABLE value instead of silently deleting it. Demoted to
10
+ * `severity: "info"`/`semantic: "none"` so it can never read as a blocking
11
+ * "leaked secret" alarm, while remaining visible for an audit read.
5
12
  */
6
13
  export function gitleaksFindingToProjectDiagnostic(cwd, finding) {
14
+ // #1562 observability criterion: surface the git status right in the
15
+ // finding's message so a triage is a read, not a re-derivation. Omitted
16
+ // when git itself degraded (`pathStatus` undefined) rather than guessed.
17
+ const statusSuffix = finding.pathStatus ? ` [git: ${finding.pathStatus}]` : "";
18
+ const isScratch = finding.pathStatus === "scratch";
7
19
  return {
8
20
  filePath: path.isAbsolute(finding.file)
9
21
  ? finding.file
10
22
  : path.resolve(cwd, finding.file),
11
23
  line: finding.startLine,
12
- severity: "error",
13
- semantic: "blocking",
24
+ severity: isScratch ? "info" : "error",
25
+ semantic: isScratch ? "none" : "blocking",
14
26
  tool: "gitleaks",
15
27
  runner: "gitleaks",
16
28
  rule: `gitleaks:${finding.ruleId}`,
17
- message: `Potential secret: ${finding.description || finding.ruleId}`,
29
+ message: `Potential secret: ${finding.description || finding.ruleId}${statusSuffix}`,
18
30
  source: "project-scan",
19
31
  };
20
32
  }
@@ -24,8 +24,56 @@ export function trivyFindingToProjectDiagnostic(cwd, finding) {
24
24
  source: "project-scan",
25
25
  };
26
26
  }
27
+ /**
28
+ * A trivy *secret* finding (`TrivyResult.secrets`) is a leaked credential at a
29
+ * concrete `file:line` — the trivy-scanned sibling of
30
+ * `gitleaksFindingToProjectDiagnostic`, and treated the same way: **blocking**,
31
+ * since a committed credential is not a style nit.
32
+ *
33
+ * Rule id is namespaced `trivy-secret:<ruleId>`, deliberately distinct from the
34
+ * CVE lane's `trivy:<vulnerabilityId>` (#1628) — trivy's own rule-id spaces for
35
+ * secrets and CVEs are independent, so without this prefix a secret rule id
36
+ * could collide with a vulnerability id and silently share (or steal) that
37
+ * finding's disposition anchor.
38
+ */
39
+ export function trivySecretFindingToProjectDiagnostic(cwd, finding) {
40
+ return {
41
+ filePath: path.isAbsolute(finding.file)
42
+ ? finding.file
43
+ : path.resolve(cwd, finding.file),
44
+ line: finding.line,
45
+ severity: "error",
46
+ semantic: "blocking",
47
+ tool: "trivy",
48
+ runner: "trivy",
49
+ rule: `trivy-secret:${finding.ruleId}`,
50
+ message: `Potential secret: ${finding.title || finding.ruleId}`,
51
+ source: "project-scan",
52
+ };
53
+ }
54
+ function trivySecretsToProjectDiagnostics(cwd, secrets) {
55
+ return secrets.map((finding) => trivySecretFindingToProjectDiagnostic(cwd, finding));
56
+ }
57
+ /**
58
+ * Adapts BOTH of trivy's finding kinds from one scan pass — CVEs (`findings`)
59
+ * and secrets (`secrets`, #1628) — into the single `ProjectDiagnostic[]`
60
+ * `lens_diagnostics mode=full` surfaces. Before #1628, `secrets` was silently
61
+ * unread here: a trivy-only secret (no gitleaks/ast-grep corroboration) had no
62
+ * `lens_diagnostics`-visible identity at all for an agent to anchor a mark
63
+ * against, even though `runtime-turn.ts`'s turn_end gate already blocked on it.
64
+ */
27
65
  export function trivyResultToProjectDiagnostics(cwd, result) {
28
- if (!result.success || result.findings.length === 0)
66
+ if (!result.success)
29
67
  return [];
30
- return result.findings.map((finding) => trivyFindingToProjectDiagnostic(cwd, finding));
68
+ return [
69
+ ...(result.findings ?? []).map((finding) => trivyFindingToProjectDiagnostic(cwd, finding)),
70
+ // `secrets` defaults to `[]` here rather than assuming the field is
71
+ // always present: `fetchFreshProjectDiagnostics` swallows a task
72
+ // rejection into a silent "completed" outcome (its
73
+ // `.catch(() => "completed")`), so an unguarded `.map` on a missing
74
+ // field here would drop this lane's CVE diagnostics too, not just the
75
+ // secrets — a caller-visible regression for a field this adapter
76
+ // doesn't itself require.
77
+ ...trivySecretsToProjectDiagnostics(cwd, result.secrets ?? []),
78
+ ];
31
79
  }
@@ -89,6 +89,11 @@ function fromDispatchDiagnostic(diagnostic, runner) {
89
89
  */
90
90
  async function scanFileMajorRules(cwd, files, signal) {
91
91
  const client = getSharedTreeSitterClient();
92
+ // #1715: grow the tree cache to span this scan's working set BEFORE
93
+ // parsing starts, so a project bigger than the interactive default (50
94
+ // entries) still gets cross-scan reuse instead of every file re-parsing
95
+ // on every scan.
96
+ client?.ensureTreeCacheCapacity(files.length);
92
97
  const treeSitterReady = !!client && client.isAvailable() && (await client.init());
93
98
  // Same singleton the dispatch runner uses (tree-sitter.ts:444) — memoized
94
99
  // per root, so repeated scans stop re-reading the ~180 query YAMLs.
@@ -283,17 +288,26 @@ async function scanFileMajorRules(cwd, files, signal) {
283
288
  // phase-major scans.
284
289
  durationMs: Date.now() - startedAt - astGrepDurationMs,
285
290
  stats,
291
+ // #1935 review: ast-grep's own cost is often a scan's most expensive
292
+ // phase (production evidence: 13168ms over 86 files, the single
293
+ // biggest contributor). Its duration is subtracted above so it stays
294
+ // comparable to the historical phase-major scans; carry it here too
295
+ // so it stays visible SOMEWHERE instead of disappearing when the
296
+ // vacuous `project_diagnostics_ast_grep_scan` cache_stats record
297
+ // (below) was removed.
298
+ astGrep: { durationMs: astGrepDurationMs, fileCount: astGrepFilesScanned },
286
299
  });
287
300
  });
288
- await client.withParseCacheMeasurement(async () => { }, (stats) => {
289
- logTreeSitterCacheStats({
290
- scope: "project_diagnostics_ast_grep_scan",
291
- filePath: cwd,
292
- fileCount: astGrepFilesScanned,
293
- durationMs: astGrepDurationMs,
294
- stats,
295
- });
296
- });
301
+ // #1935: no `project_diagnostics_ast_grep_scan` cache_stats record here.
302
+ // `scanAstGrepFile` parses through ast-grep-napi's own `lang.parse()` — a
303
+ // separate native engine, not `TreeSitterClient`'s WASM `TreeCache` — so a
304
+ // cache_stats record for this scope would always read all-zero (0
305
+ // lookups, 0 hits, every counter 0) no matter how the scan behaves. That
306
+ // was a vacuous observability record, not a real one: it looked like a
307
+ // signal but could never carry information. `astGrepDurationMs` and
308
+ // `astGrepFilesScanned` still feed the `project_diagnostics_scan` record
309
+ // above (`astGrep` sub-field), so this cost stays observable without a
310
+ // second, always-zero record to carry it.
297
311
  return { treeSitter, factRules, astGrep, filesScanned, wasmAborted };
298
312
  }
299
313
  export async function scanProjectDiagnostics(options) {
@@ -84,6 +84,9 @@ const PROJECT_OWN_CONFIG_KEYS = [
84
84
  "maxProjectFiles",
85
85
  "reviewGraph",
86
86
  "trivy",
87
+ // `helm.renderValidation.enabled` — the opt-in for rendered-manifest
88
+ // validation, read via `.raw` in the helm-render runner (#1283).
89
+ "helm",
87
90
  ];
88
91
  /** Clamp bounds for `reviewGraph.maxFiles` — see the field's doc comment above. */
89
92
  const REVIEW_GRAPH_MAX_FILES_MIN = 100;
@@ -36,6 +36,7 @@
36
36
  import * as path from "node:path";
37
37
  import { normalizeMapKey, toProjectRelativePath } from "./path-utils.js";
38
38
  import { loadProjectSnapshotWithoutWordIndex } from "./project-snapshot.js";
39
+ import { formatReviewGraphRevisionDriftNote, } from "./review-graph/revision-drift.js";
39
40
  const DEFAULT_LIMIT = 10;
40
41
  const STALE_THRESHOLD_MS = 15 * 60_000; // 15 minutes
41
42
  const LOW_COVERAGE_THRESHOLD = 0.8;
@@ -113,7 +114,11 @@ function buildFileDegrees(graph) {
113
114
  return { fanIn, fanOut };
114
115
  }
115
116
  // --- section 1: trust header --------------------------------------------------
116
- function computeTrust(graph, cwd) {
117
+ function computeTrust(graph, cwd,
118
+ // Passed in rather than looked up here: the builder is imported dynamically
119
+ // by `projectReport` to keep the module graph acyclic, and the value must be
120
+ // computed per render, never cached (#1961 review F3).
121
+ drift) {
117
122
  const filesCovered = graph.fileNodes.size;
118
123
  const snapshot = loadProjectSnapshotWithoutWordIndex(cwd);
119
124
  const snapshotFileCount = snapshot ? Object.keys(snapshot.files).length : 0;
@@ -151,6 +156,11 @@ function computeTrust(graph, cwd) {
151
156
  const lowCoverage = coverage < LOW_COVERAGE_THRESHOLD ||
152
157
  graph.persistCoverage?.partial === true;
153
158
  const notes = [];
159
+ // #1961: the blind read now SERVES a snapshot stamped at a different HEAD
160
+ // rather than dropping it. Age alone would not catch a branch switch made
161
+ // minutes ago, so the revision difference gets its own note.
162
+ if (drift)
163
+ notes.push(formatReviewGraphRevisionDriftNote(drift));
154
164
  if (stale) {
155
165
  const ageMin = Math.round(ageMs / 60_000);
156
166
  notes.push(`Graph is stale: built ${ageMin}m ago. Sections below may miss recent edits — run pilens_rebuild or re-analyze to refresh.`);
@@ -184,6 +194,7 @@ function computeTrust(graph, cwd) {
184
194
  sampleSize,
185
195
  },
186
196
  stale,
197
+ ...(drift ? { revisionDrift: drift } : {}),
187
198
  lowCoverage,
188
199
  persistCoverage: graph.persistCoverage?.partial
189
200
  ? graph.persistCoverage
@@ -493,25 +504,23 @@ const inFlightGraphBuilds = new Set();
493
504
  export function _resetProjectReportBuildGuardForTests() {
494
505
  inFlightGraphBuilds.clear();
495
506
  }
496
- function triggerBackgroundGraphBuild(cwd) {
507
+ function triggerBackgroundGraphBuild(cwd, deps) {
497
508
  const key = normalizeMapKey(path.resolve(cwd));
498
509
  if (inFlightGraphBuilds.has(key))
499
- return false;
510
+ return "already_running";
511
+ // Ask the builder, not just this module's own guard: a build kicked off by
512
+ // the edit pipeline or another reader never touches `inFlightGraphBuilds`.
513
+ // The probe and the call are in ONE synchronous block on purpose — awaiting
514
+ // between them (the pre-#1962 dynamic imports did) reopens the race.
515
+ const deduped = deps.isGraphBuildInFlight(key, []);
500
516
  inFlightGraphBuilds.add(key);
501
- void (async () => {
502
- try {
503
- const { buildOrUpdateGraph } = await import("./review-graph/builder.js");
504
- const { FactStore } = await import("./dispatch/fact-store.js");
505
- await buildOrUpdateGraph(key, [], new FactStore());
506
- }
507
- catch {
508
- // buildOrUpdateGraph records the durable failure and surfaced status.
509
- }
510
- finally {
511
- inFlightGraphBuilds.delete(key);
512
- }
513
- })();
514
- return true;
517
+ const build = deps
518
+ .buildOrUpdateGraph(key, [], new deps.FactStore())
519
+ .catch(() => {
520
+ // buildOrUpdateGraph records the durable failure and surfaced status.
521
+ });
522
+ void build.finally(() => inFlightGraphBuilds.delete(key));
523
+ return deduped ? "already_running" : "started";
515
524
  }
516
525
  // --- entry point ---------------------------------------------------------------
517
526
  /**
@@ -523,7 +532,7 @@ export async function projectReport(cwd, options) {
523
532
  const limit = clampLimit(options?.limit);
524
533
  const focusTerms = normalizeFocus(options?.focus);
525
534
  const view = options?.view;
526
- const { getCachedReviewGraph, getReviewGraphSizeSkipVerdict, getLastReviewGraphBuildAttempt, } = await import("./review-graph/builder.js");
535
+ const { getCachedReviewGraph, getReviewGraphSizeSkipVerdict, getLastReviewGraphBuildAttempt, buildOrUpdateGraph, isGraphBuildInFlight, getReviewGraphRevisionDrift, } = await import("./review-graph/builder.js");
527
536
  let graph;
528
537
  try {
529
538
  graph = getCachedReviewGraph(cwd);
@@ -556,22 +565,48 @@ export async function projectReport(cwd, options) {
556
565
  };
557
566
  }
558
567
  const previousAttempt = getLastReviewGraphBuildAttempt(cwd);
559
- const kickedOff = triggerBackgroundGraphBuild(cwd);
560
- const lastBuildAttempt = previousAttempt ?? getLastReviewGraphBuildAttempt(cwd);
568
+ const { FactStore } = await import("./dispatch/fact-store.js");
569
+ const trigger = triggerBackgroundGraphBuild(cwd, {
570
+ buildOrUpdateGraph,
571
+ isGraphBuildInFlight,
572
+ FactStore,
573
+ });
574
+ const started = trigger === "started";
575
+ // #1962: report the attempt that is CURRENT. When this call started a
576
+ // build, `buildOrUpdateGraph` has already recorded a fresh `running`
577
+ // attempt synchronously, and the previous outcome belongs in the hint
578
+ // text, not in a field labelled "last attempt". When no build started,
579
+ // the earlier attempt genuinely IS the current one.
580
+ const lastBuildAttempt = started
581
+ ? (getLastReviewGraphBuildAttempt(cwd) ?? previousAttempt)
582
+ : previousAttempt;
583
+ // A terminal previous outcome is the useful half of the message: it says
584
+ // WHY the graph is missing. It is prefixed to whichever verdict follows,
585
+ // rather than selecting between two parallel sentence pairs — the first
586
+ // version of this branch did that, and its terminal-plus-deduped arm was
587
+ // unreachable (#1962 review F1). A pending build always records a
588
+ // `running` attempt synchronously, so "terminal" and "not started" cannot
589
+ // both hold for the same key.
590
+ const terminal = previousAttempt?.outcome === "failed" ||
591
+ previousAttempt?.outcome === "skipped";
592
+ const cause = terminal
593
+ ? `Review graph unavailable: ${previousAttempt?.reason ?? previousAttempt?.outcome}. `
594
+ : "";
561
595
  return {
562
596
  available: false,
563
- hint: lastBuildAttempt?.outcome === "failed" ||
564
- lastBuildAttempt?.outcome === "skipped"
565
- ? `Review graph unavailable: ${lastBuildAttempt.reason ?? lastBuildAttempt.outcome}. A retry was ${kickedOff ? "started" : "not started"}.`
566
- : kickedOff
567
- ? "No review graph cached for this workspace yet — a build was kicked off in the background; retry this call shortly."
568
- : "No review graph cached for this workspace yet — the background build is still running; retry this call shortly.",
597
+ hint: started
598
+ ? terminal
599
+ ? `${cause}A retry was started.`
600
+ : "No review graph cached for this workspace yet — a build was kicked off in the background; retry this call shortly."
601
+ : `${cause}A build is already running for this workspace; retry this call shortly.`,
569
602
  ...(lastBuildAttempt ? { lastBuildAttempt } : {}),
570
603
  ...(view ? { view } : {}),
571
604
  };
572
605
  }
573
606
  const degrees = buildFileDegrees(graph);
574
- const trust = computeTrust(graph, cwd);
607
+ // Computed on THIS render, from the workspace entry's stamped commit and the
608
+ // worktree's HEAD right now — never from a value cached beside the graph.
609
+ const trust = computeTrust(graph, cwd, getReviewGraphRevisionDrift(cwd));
575
610
  const hubs = await computeHubs(graph, degrees, cwd, limit, focusTerms);
576
611
  const { entryPoints, entryPointFiles } = computeEntryPoints(graph, degrees, cwd, limit, focusTerms);
577
612
  const subsystems = computeSubsystems(graph, cwd, limit);