@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
@@ -0,0 +1,316 @@
1
+ /**
2
+ * Single documentation home for the finding-delivery gate stack (#1634).
3
+ *
4
+ * Every store that renders findings to the AGENT — the turn-end blocker/
5
+ * advisory tiers, `lens_diagnostics` mode=full/all/delta, the widget/footer
6
+ * tally, agent nudges, and the persisted project-diagnostics snapshot —
7
+ * invented its own freshness and retirement rules across
8
+ * #1461/#1561/#1622/#1631, so the stores drifted from each other and each new
9
+ * store re-created the class. #1622/#1625/#1627/#1633 converged on two gates;
10
+ * this module names them ONE time so every other file points here instead of
11
+ * re-explaining the contract. `mode=delta` — the tool's DEFAULT mode — was
12
+ * the review round's live catch: it re-served the actionable/quality-warnings
13
+ * caches verbatim, unfixed by the earlier per-store passes because it sits
14
+ * one layer up from any single scanner.
15
+ *
16
+ * ── Freshness (mtime vs scannedAt, onMissing policy) ──────────────────────
17
+ * `gateFindingsByPathFreshness` (advisory-provenance.ts) partitions a cached
18
+ * store's findings by what the cited path looks like NOW versus the scan
19
+ * timestamp (`scannedAt`) the store was captured at:
20
+ * - missing → `onMissing: "drop"` (default) removes the finding outright —
21
+ * right when the finding IS the file's content (a secret in a deleted
22
+ * file cannot be rotated). `onMissing: "demote"` keeps it — right when the
23
+ * cited path is only EVIDENCE for a finding pinned elsewhere (a
24
+ * govulncheck CVE is pinned by go.mod, not by the traced call site).
25
+ * - stale (mtime > scannedAt + MTIME_DRIFT_TOLERANCE_MS,
26
+ * `blocker-freshness.ts`) → DEMOTE, never drop. The finding survives,
27
+ * the now-untrustworthy line number does not.
28
+ * - live → deliver unchanged, full authority.
29
+ * - unknown (unparseable/absent `scannedAt`, unreadable path) → fail OPEN,
30
+ * deliver unchanged. A missed demotion is noise; a wrong drop can hide a
31
+ * live credential or CVE.
32
+ * The turn-end secrets (gitleaks/trivy-secrets) and govulncheck advisory both
33
+ * route through this gate in `clients/runtime-turn.ts`.
34
+ *
35
+ * The SAME freshness family, one level up, covers cross-file drift: a cached
36
+ * inline blocker is a verdict about its file *and everything that file
37
+ * imports* — `clients/blocker-freshness.ts` (`sweepInlineBlockerFreshness`,
38
+ * the widget-store counterpart `reconcileStaleWidgetDependencyBlockers`
39
+ * paired with `reconcileStaleWidgetFiles`) stats the file and its forward
40
+ * imports against the verdict's `recordedAtMs` baseline (#1631/#1633). A
41
+ * drifted entry is demoted with the SAME `[stale — re-run to confirm]`
42
+ * marker (`STALE_LINE_MARKER`, `clients/stale-marker.ts` — its own leaf
43
+ * module so `widget-state.ts` can use it without a circular import back
44
+ * through the turn orchestrator, #1631 review V2) and `isBlocking`
45
+ * answers false for it — the one predicate both the footer tally and
46
+ * `mode=all`'s blocking count consult, which is what keeps `mode=all` from
47
+ * contradicting a same-minute `mode=full` sweep on the same paths (#1631
48
+ * criterion 3 / #1634 criterion 4).
49
+ *
50
+ * Two INDEPENDENT gates share this `stale` field, distinguished by
51
+ * `WidgetDiagnostic.staleReason`: `"dependency-drift"` (#1631, above) and
52
+ * `"past-eof"` (#1641 — a cited line beyond the file's current on-disk length,
53
+ * a stale in-memory LSP document diverged from disk). Each gate only HEALS
54
+ * demotions it made itself (`staleReason` defaults to `"past-eof"` for
55
+ * backward compatibility with pre-#1641 records) — composed, not merged into
56
+ * one undifferentiated flag, so a fix for one hazard can never silently clear
57
+ * the other's verdict.
58
+ *
59
+ * ── Dispositions (strict-only for blocking) ───────────────────────────────
60
+ * `applyDispositions` (diagnostic-dispositions.ts) filters false-positive/
61
+ * suppress/defer/flagged judgments the agent or user already recorded for a
62
+ * finding. Anchoring is STRICT (line-content-hashed) only for false-positive
63
+ * — a judgment about one exact piece of code that must NOT survive a rewrite
64
+ * of that line — and WEAK (no line hash) for defer/flagged/suppress, which
65
+ * are intent-level judgments that must survive incidental nearby edits.
66
+ * `formatFullMode` (tools/lens-diagnostics.ts) applies this on every
67
+ * mode=full pass; the per-edit dispatch path applies the identical filter
68
+ * before writing into widget-state, so mode=all and the footer inherit
69
+ * disposition state for any file that has gone through a live edit this
70
+ * session WITHOUT re-computing it (kept cache-only and instant, #1634
71
+ * criterion 5's documented exception — see "Explicit lag labels" below).
72
+ *
73
+ * ── Demotion rendering (#1419) ─────────────────────────────────────────────
74
+ * A demoted finding is never silently dropped and never re-asserted at full
75
+ * authority: it renders with `STALE_LINE_MARKER` (or the widget's `[stale]`
76
+ * tag) in place of the coordinate the drift invalidated. This is the one
77
+ * rendering convention every gated surface reuses — a store must not invent
78
+ * its own "stale" wording.
79
+ *
80
+ * #1944 completes the rule: demotion must change the BODY, not only the
81
+ * channel and the coordinate. A demoted body carries no STOP banner and no
82
+ * "must be fixed" imperative, and a cited line the file no longer has renders
83
+ * as `L<n> (line no longer exists)`. `clients/demoted-finding-render.ts`
84
+ * (`degradeDemotedFindingBody`) is the one implementation for surfaces that
85
+ * deliver a RENDERED BODY — the turn-end advisory tier. Per-row surfaces
86
+ * (`clients/widget-state.ts`, `tools/lens-diagnostics.ts`) have no body to
87
+ * degrade; they satisfy the same rule by dropping the authority marker
88
+ * alongside the coordinate.
89
+ *
90
+ * ── Retirement (#1944) ────────────────────────────────────────────────────
91
+ * Demote-not-drop assumes the agent CAN re-run to confirm. A past-EOF
92
+ * demotion breaks that assumption: the file shrank past the cited lines, so
93
+ * no re-run can ever speak to them, and the record re-served on every turn
94
+ * end for the life of the session. Such a record is delivered ONCE, degraded,
95
+ * then retired (`RuntimeCoordinator.retireDemotedPastEofBlocker`). The
96
+ * suppression is recorded in the degradation ledger under
97
+ * `demoted-finding-retired`, whose subject keeps the store and file, and the
98
+ * delivered payload says so in its own words — so an empty advisory section
99
+ * can only mean "nothing to say". Dependency-drift demotions keep in-bounds
100
+ * coordinates the agent can act on and are NOT retired.
101
+ *
102
+ * ── Explicit lag labels (the non-gated escape hatch) ──────────────────────
103
+ * A store that cannot afford the freshness/disposition stack — because it
104
+ * has no cited per-file path to stat (a package-pinned finding like a trivy
105
+ * CRITICAL CVE or a license-risk row), or because re-computing dispositions
106
+ * would cost the "instant" cache-only render mode=all/the footer promise —
107
+ * MUST say so explicitly, with the finding's age, rather than presenting as
108
+ * if it were current. `formatCacheAgeLabel` below is the one implementation;
109
+ * every labeled surface in `DELIVERY_SURFACES` calls it instead of hand-
110
+ * rolling an age string. This is the "(b)" arm of #1634's contract: every
111
+ * agent-facing surface is EITHER gated OR explicitly labeled — never neither.
112
+ */
113
+ const MS_PER_MINUTE = 60_000;
114
+ /**
115
+ * Render a short, honest age suffix for a store that cannot be freshness-
116
+ * gated per-path (see module doc). `undefined`/unparseable `scannedAt`
117
+ * degrades to a neutral "scan age unknown" label — fail open on WORDING the
118
+ * same way the freshness gate fails open on VERDICT: an unlabeled finding is
119
+ * worse than a vague one, but never fabricate a number from a bad timestamp.
120
+ */
121
+ export function formatCacheAgeLabel(scannedAt, nowMs = Date.now()) {
122
+ if (scannedAt === undefined || scannedAt === null || scannedAt === "") {
123
+ return "scan age unknown";
124
+ }
125
+ const scannedAtMs = typeof scannedAt === "number" ? scannedAt : Date.parse(scannedAt);
126
+ if (!Number.isFinite(scannedAtMs))
127
+ return "scan age unknown";
128
+ const ageMs = Math.max(0, nowMs - scannedAtMs);
129
+ const ageMinutes = Math.round(ageMs / MS_PER_MINUTE);
130
+ if (ageMinutes < 1)
131
+ return "scanned <1m ago";
132
+ if (ageMinutes < 60)
133
+ return `scanned ${ageMinutes}m ago`;
134
+ // Floor the hour, keep the remainder minutes explicit — a naive
135
+ // `Math.round(ageMinutes / 60)` reported "1h" at 89 minutes (F5), rounding
136
+ // a finding's age UP is the wrong direction to err for a staleness label.
137
+ const ageHours = Math.floor(ageMinutes / 60);
138
+ const remMinutes = ageMinutes % 60;
139
+ return remMinutes === 0
140
+ ? `scanned ${ageHours}h ago`
141
+ : `scanned ${ageHours}h ${remMinutes}m ago`;
142
+ }
143
+ /**
144
+ * The enumeration (#1634 criterion 1): every surface that renders findings to
145
+ * the agent. Two DIFFERENT seam shapes, each derived structurally rather than
146
+ * hand-listed (#1634 review round F2):
147
+ *
148
+ * - `clients/runtime-turn.ts`: every `blockerParts.push`/`advisoryParts.push`/
149
+ * `staleSecretParts.push` call site carries an `@delivery-surface: <id>`
150
+ * comment naming its entry here. `tests/clients/finding-delivery-gate.test.ts`
151
+ * scans the file for every such push call (comments/strings stripped, so a
152
+ * commented-out or string-embedded false match can't hide a REAL untagged
153
+ * seam) and fails if one has no tag, or a tag names an id not in this
154
+ * registry — a brand-new ungated `advisoryParts.push` cannot pass silently.
155
+ * - `tools/lens-diagnostics.ts`: each `mode=` report is its own function
156
+ * (`formatFullMode`/`formatAllMode`/`formatDeltaMode`), tagged the same way
157
+ * immediately above its `function` line.
158
+ * - `clients/widget-state.ts` (the footer) and `clients/agent-nudge.ts` are
159
+ * hand-registered below — one surface each, not a push-site pattern the
160
+ * scan can derive structurally, so a coverage test asserts these two
161
+ * files are not silently untouched by other tests in the same run.
162
+ *
163
+ * Single source of truth: adding a new render seam without adding/tagging an
164
+ * entry here fails the coverage test, not a human re-reading a hand list.
165
+ */
166
+ /**
167
+ * Factory for a `gated` entry. #1634 review round (SonarCloud): 20+ entries
168
+ * written as multi-line object literals put the SAME `mode`/`file` key
169
+ * sequence on the same relative lines over and over — the TS/JS duplication
170
+ * detector normalizes string literals to a placeholder token, so those
171
+ * literally-different-content blocks still read as duplicate TOKEN STREAMS.
172
+ * Collapsing each entry to one factory call removes the repeating shape
173
+ * instead of the (irreducible) per-entry data.
174
+ */
175
+ function gated(file, description, gates, evidence, extra = {}) {
176
+ return { mode: "gated", file, description, gates, evidence, ...extra };
177
+ }
178
+ /** Factory for a `labeled` entry — see {@link gated}'s doc for why this exists. */
179
+ function labeled(file, description, reason, ageSource, evidence = [], extra = {}) {
180
+ return { mode: "labeled", file, description, reason, ageSource, evidence, ...extra };
181
+ }
182
+ const RUNTIME_TURN_FILE = "clients/runtime-turn.ts";
183
+ const LENS_DIAGNOSTICS_FILE = "tools/lens-diagnostics.ts";
184
+ export const DELIVERY_SURFACES = {
185
+ "runtime-turn:secrets-gitleaks": gated(RUNTIME_TURN_FILE, "Turn-end 🔴 secrets blocker, gitleaks cache.", ["gateFindingsByPathFreshness"], ['store: "gitleaks"']),
186
+ "runtime-turn:secrets-trivy": gated(RUNTIME_TURN_FILE, "Turn-end 🔴 secrets blocker, trivy secrets cache.", ["gateFindingsByPathFreshness"], ['store: "trivy-secrets"']),
187
+ "runtime-turn:govulncheck-advisory": gated(RUNTIME_TURN_FILE, "Turn-end 🛡️ Go CVE advisory (call-site line only).", ["gateFindingsByPathFreshness"], ['store: "govulncheck"']),
188
+ // Two tagged seams (the stale and live render branches below the same
189
+ // `sweepInlineBlockerFreshness` call) legitimately share one evidence
190
+ // occurrence — evidenceMin: 2 tells the exclusive-assignment check both
191
+ // are expected claimants, not a rogue seam contesting the real one.
192
+ "runtime-turn:unresolved-inline-blocker": gated(RUNTIME_TURN_FILE, "Turn-end re-surfaced unresolved inline blockers.", ["sweepInlineBlockerFreshness"],
193
+ // #1790: the call now passes `additionalEntries` (widget-store rows) as a
194
+ // third argument, so the literal is the call's opening rather than the
195
+ // whole single-line invocation.
196
+ ["sweepInlineBlockerFreshness(runtime, cwd, {"], { evidenceMin: 2 }),
197
+ // Same two gate calls as the live secrets tier — this tier renders their
198
+ // `.stale` arm, so it has no OWN gate call to point at.
199
+ "runtime-turn:stale-secrets-tier": gated(RUNTIME_TURN_FILE, "Turn-end 🔑 demoted-secrets tier (drifted since scan).", ["gateFindingsByPathFreshness"], ['store: "gitleaks"', 'store: "trivy-secrets"']),
200
+ // The evidence below is the literal header FRAGMENT including the
201
+ // interpolation — proves the label is actually rendered, not merely
202
+ // computed and discarded (review round F1's "deleted the age
203
+ // interpolations" attack).
204
+ "runtime-turn:trivy-critical-blocker": labeled(RUNTIME_TURN_FILE, "Turn-end 🔴 CRITICAL dependency CVE blocker (trivy).", "Package-pinned finding with no cited file:line to stat — freshness has " +
205
+ "nothing to check drift against. The session_start cache can be " +
206
+ "arbitrarily old, so its age is stated instead. Also routes through " +
207
+ "`filterFindingsByDisposition` (#1625) first — a suppressed/false-" +
208
+ "positive finding never reaches this render, so the age label and the " +
209
+ "disposition filter compose rather than substitute for each other.", "TrivyResult.scannedAt", ["CRITICAL dependency CVEs (trivy, ${trivyAgeLabel}"]),
210
+ "runtime-turn:trivy-cve-advisory": labeled(RUNTIME_TURN_FILE, "Turn-end 🛡️ non-critical dependency CVE advisory (trivy).", "Same package-pinned shape and #1625 disposition composition as the " +
211
+ "CRITICAL blocker above.", "TrivyResult.scannedAt", ["Dependency CVEs (trivy, ${trivyAgeLabel}"]),
212
+ "runtime-turn:trivy-license-advisory": labeled(RUNTIME_TURN_FILE, "Turn-end 📜 dependency license-risk advisory (trivy).", "Same package-pinned shape as the CRITICAL blocker above.", "TrivyResult.scannedAt", ["Dependency license risk (trivy, ${trivyAgeLabel}"]),
213
+ "runtime-turn:dead-code-advisory": labeled(RUNTIME_TURN_FILE, "Turn-end dead-code delta advisory (knip/vulture/etc).", "The delta shown is computed from THIS turn's own analyze() call, " +
214
+ "diffed against the previous cache — never a replay of a stale cache.", "live"),
215
+ "runtime-turn:knip-blocker": labeled(RUNTIME_TURN_FILE, "Turn-end 🔴 Knip unresolved-imports/deps blocker.", "Same shape as the dead-code advisory: `await knipClient.analyze(cwd, " +
216
+ "...)` runs fresh THIS turn, diffed against the previous cache and " +
217
+ "filtered to files edited this turn — never a replay of a stale cache.", "live"),
218
+ "runtime-turn:knip-advisory": labeled(RUNTIME_TURN_FILE, "Turn-end ⚠️ Knip newly-unused-exports advisory.", "Same live-this-turn shape as the Knip blocker above.", "live"),
219
+ "runtime-turn:actionable-warnings-advisory": labeled(RUNTIME_TURN_FILE, "Turn-end actionable-warnings advisory (ast-grep etc).", "`peekActionableWarnings` reads `_actionableWarningsThisTurn` — recorded " +
220
+ "fresh from this turn's own dispatch, never a cross-turn cache.", "live"),
221
+ "runtime-turn:code-quality-warnings-advisory": labeled(RUNTIME_TURN_FILE, "Turn-end code-quality-warnings advisory.", "`peekCodeQualityWarnings` reads `_codeQualityWarningsThisTurn` — the " +
222
+ "same per-turn accumulator shape as actionable-warnings above.", "live"),
223
+ "runtime-turn:disposition-suppressed-notice": labeled(RUNTIME_TURN_FILE, "Turn-end running disposition-suppressed-count notice (#1616).", "A live running total accumulated from this turn's own gate/disposition " +
224
+ "calls above (`dispositionSuppressedTotal`) — telemetry ABOUT the other " +
225
+ "gated surfaces, not a cache of its own.", "live"),
226
+ "runtime-turn:cascade-blocker": labeled(RUNTIME_TURN_FILE, "Turn-end 🧪 cascade neighbor blocker.", "Cascade results settle synchronously this turn where possible " +
227
+ "(`settleCascadeRuns`), but an unsettled compute can carry over to a " +
228
+ "later turn (bounded by a carry cap) — this round does not freshness-" +
229
+ "gate that carry-over window.", "live", [], {
230
+ status: "partial",
231
+ partialReason: "A carried-over cascade result (run.carriedTurns > 0) is rendered " +
232
+ "without an age label. Follow-up: surface carriedTurns as an explicit " +
233
+ "label when > 0, or route through formatCacheAgeLabel using the run's " +
234
+ "own timestamp.",
235
+ }),
236
+ "runtime-turn:cascade-coverage-advisory": labeled(RUNTIME_TURN_FILE, "Turn-end cascade-coverage-gap advisories (graph/binding/budget).", "Explains what the cascade check could NOT confirm this turn — not a " +
237
+ "finding with a cited path, an absence-of-coverage disclosure computed " +
238
+ "from this turn's own indeterminate-run list.", "live", [], {
239
+ status: "partial",
240
+ partialReason: "Same cascade carry-over caveat as runtime-turn:cascade-blocker.",
241
+ }),
242
+ "runtime-turn:call-graph-advisory": labeled(RUNTIME_TURN_FILE, "Turn-end 📊 call-graph impact advisory.", "`runtime.callGraph` is a session-lifetime in-memory structure; this " +
243
+ "round does not verify or gate ITS OWN freshness policy (how/when it " +
244
+ "incorporates edits made earlier in the session).", "live", [], {
245
+ status: "partial",
246
+ partialReason: "call-graph freshness/invalidation policy is out of this PR's scope — " +
247
+ "tracked as a follow-up, not silently assumed fresh.",
248
+ }),
249
+ "lens-diagnostics:mode-full": gated(LENS_DIAGNOSTICS_FILE, "`lens_diagnostics mode=full` report.", ["applyDispositions", "applyRulePolicy", "reconcileProjectDiagnosticsSnapshot"], ["applyDispositions(", "applyRulePolicy(", "reconcileProjectDiagnosticsSnapshot("]),
250
+ "lens-diagnostics:mode-all": gated(LENS_DIAGNOSTICS_FILE, "`lens_diagnostics mode=all` report (widget-state read).", ["reconcileStaleWidgetFiles", "reconcileStaleWidgetDependencyBlockers"], ["reconcileStaleWidgetFiles(", "reconcileStaleWidgetDependencyBlockers("]),
251
+ // #1634 review round F3: this was the most important gap — the tool's
252
+ // DEFAULT mode rendered cached `file:line` findings with zero freshness
253
+ // check. `applyDeltaFreshnessGate` (this file's sibling in
254
+ // tools/lens-diagnostics.ts) now routes the actionable/quality-warnings
255
+ // caches through the shared gate using each report's own `generatedAt`.
256
+ // Round R3: mode=delta has a THIRD arm — the persisted project-diagnostics
257
+ // delta report, rendered by `appendProjectDiagnosticsDeltaLines` — which
258
+ // carried the identical unfixed shape. It now gates the same way, against
259
+ // its own `generatedAt`.
260
+ "lens-diagnostics:mode-delta": gated(LENS_DIAGNOSTICS_FILE, "`lens_diagnostics mode=delta` report (the tool's DEFAULT mode) — " +
261
+ "re-serves the actionable-warnings/code-quality-warnings caches AND " +
262
+ "the persisted project-diagnostics delta report.", ["gateFindingsByPathFreshness"], [
263
+ 'store: "lens-diagnostics-delta"',
264
+ "applyDeltaFreshnessGate(",
265
+ 'store: "lens-diagnostics-delta-project"',
266
+ ]),
267
+ "widget-state:footer": gated("clients/widget-state.ts", "TUI footer blocking/error/warning tally.", ["reconcileStaleWidgetFiles", "isBlocking"], ["isBlocking(diagnostic)", "reconcileStaleWidgetFiles()"]),
268
+ "agent-nudge:context-message": labeled("clients/agent-nudge.ts", "Post-edit file-touch nudge injected via `context`.", "Not a scanner finding store: no severity, no cited line, no cache — the " +
269
+ "accumulator is drained and cleared at the moment of injection, so the " +
270
+ "content IS the current state by construction.", "live"),
271
+ "project-diagnostics:persisted-snapshot": gated(LENS_DIAGNOSTICS_FILE, "Cross-session persisted project-diagnostics snapshot read.", ["reconcileProjectDiagnosticsSnapshot"], ["reconcileProjectDiagnosticsSnapshot("]),
272
+ };
273
+ function assertPartialStatusHasReason(id, entry) {
274
+ if (entry.status === "partial" && !entry.partialReason) {
275
+ throw new Error(`finding-delivery-gate: surface "${id}" is status=partial but names no partialReason`);
276
+ }
277
+ }
278
+ function assertGatedShapeIsWellFormed(id, entry) {
279
+ if (!Array.isArray(entry.gates) || entry.gates.length === 0) {
280
+ throw new Error(`finding-delivery-gate: surface "${id}" is mode=gated but names no gate`);
281
+ }
282
+ if (!Array.isArray(entry.evidence) || entry.evidence.length === 0) {
283
+ throw new Error(`finding-delivery-gate: surface "${id}" is mode=gated but names no evidence`);
284
+ }
285
+ }
286
+ function assertLabeledShapeIsWellFormed(id, entry) {
287
+ if (!entry.reason || !entry.ageSource) {
288
+ throw new Error(`finding-delivery-gate: surface "${id}" is mode=labeled but is missing reason/ageSource`);
289
+ }
290
+ // "live" surfaces call no age-formatting helper — nothing to grep for.
291
+ // Every other ageSource claims a real cache, so it must be provable.
292
+ if (entry.ageSource !== "live" && entry.evidence.length === 0) {
293
+ throw new Error(`finding-delivery-gate: surface "${id}" claims ageSource "${entry.ageSource}" but names no evidence`);
294
+ }
295
+ }
296
+ /**
297
+ * Enforce #1634's "no third state" rule: every registered surface is either
298
+ * `gated` (names at least one gate) or `labeled` (names a reason and an age
299
+ * source) — never a malformed/undeclared third shape. Throws naming the
300
+ * offending surface id, so a bad registration fails loudly instead of
301
+ * silently rendering ungated.
302
+ */
303
+ export function assertNoDeliveryBypass(registry = DELIVERY_SURFACES) {
304
+ for (const [id, entry] of Object.entries(registry)) {
305
+ assertPartialStatusHasReason(id, entry);
306
+ if (entry.mode === "gated") {
307
+ assertGatedShapeIsWellFormed(id, entry);
308
+ continue;
309
+ }
310
+ if (entry.mode === "labeled") {
311
+ assertLabeledShapeIsWellFormed(id, entry);
312
+ continue;
313
+ }
314
+ throw new Error(`finding-delivery-gate: surface "${id}" has unrecognized mode ${JSON.stringify(entry.mode)} — must be "gated" or "labeled"`);
315
+ }
316
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Shared "finding identity" primitive (#1816 item 2, unifying the #533
3
+ * canonicalization fix that only reached one of three copies).
4
+ *
5
+ * Three call sites independently hand-rolled the same shape — a hash over
6
+ * `relativeFile|tool|rule|...|normalizedMessage` — to derive a stable id for
7
+ * a diagnostic/finding: `diagnostic-dispositions.ts` (dd:/ddw:),
8
+ * `actionable-warnings.ts` (aw:), and `code-quality-warnings.ts` (cq:). Only
9
+ * `diagnostic-dispositions.ts`'s `relativeFile` routed both `cwd` and
10
+ * `filePath` through `normalizeMapKey` before computing the relative path
11
+ * (see the #1024/#210-class comment this module's `relativeFile` carries
12
+ * forward) — the other two hashed the RAW inputs, so a drive-letter-case or
13
+ * slash-variant `filePath` produced a different id in the warning stores
14
+ * than dispositions would compute for the identical file. This module is the
15
+ * single source for all three: one canonicalizing `relativeFile`, one
16
+ * `normalizeMessage`, one `hashText`, and one hash length.
17
+ *
18
+ * Hash length: dispositions used 12 hex chars, the two warning builders used
19
+ * 10. This module picks 12 (dispositions' length — dispositions is the older,
20
+ * more heavily-audited call site) for every finding id going forward.
21
+ * Callers that persist ids in a keyed on-disk store (only
22
+ * `actionable-warnings.ts` does; see its own module doc) are responsible for
23
+ * back-compat lookups against ids computed under their PRE-#1816 formula —
24
+ * this module does not attempt migration itself, since it has no way to know
25
+ * which callers persist and which are ephemeral-per-turn.
26
+ */
27
+ import { createHash } from "node:crypto";
28
+ import * as path from "node:path";
29
+ import { normalizeMapKey } from "./path-utils.js";
30
+ /** Every finding id in this codebase truncates its sha256 hex digest to this
31
+ * many characters. Single source so the three call sites this module
32
+ * unifies (and any future one) can't drift back apart the way the pre-#1816
33
+ * 10-vs-12 split did. */
34
+ export const FINDING_ID_HASH_LENGTH = 12;
35
+ /** Exported so a cross-check against a live diagnostic's message (e.g.
36
+ * lens-diagnostic-mark's widget match) folds whitespace/case the same way id
37
+ * derivation does — a second, slightly different normalizer would make a
38
+ * real match invisible. */
39
+ export function normalizeMessage(message) {
40
+ return message.replace(/\s+/g, " ").trim().toLowerCase();
41
+ }
42
+ export function hashText(value, length = FINDING_ID_HASH_LENGTH) {
43
+ return createHash("sha256").update(value).digest("hex").slice(0, length);
44
+ }
45
+ /**
46
+ * Canonicalize BOTH `filePath` and `cwd` through `normalizeMapKey` (realpath
47
+ * + case-fold on Windows) BEFORE computing the relative path, so two callers
48
+ * holding different path FORMS of the same file (raw vs. already-normalized,
49
+ * a Windows drive/segment case difference, a slash variant) converge on the
50
+ * identical relative-path component instead of silently diverging into two
51
+ * different finding ids for the same file (the #533 orphaned-record class).
52
+ * `normalizeMapKey` is idempotent, so an already-canonical caller pays no
53
+ * behavior change, only the realpath I/O — acceptable here because finding
54
+ * ids are computed far less often than a per-write hot-path map key.
55
+ */
56
+ export function relativeFile(filePath, cwd) {
57
+ const canonicalCwd = normalizeMapKey(cwd);
58
+ const canonicalFile = normalizeMapKey(filePath);
59
+ const rel = path.relative(canonicalCwd, canonicalFile).replace(/\\/g, "/");
60
+ return rel && !rel.startsWith("..") ? rel : canonicalFile;
61
+ }
62
+ /**
63
+ * Shared finding-id builder. `prefix` carries the caller's own namespace
64
+ * (`"dd:"`, `"ddw:"`, `"aw:"`, `"cq:"`, ...) so distinct finding families
65
+ * never collide in a shared store. `parts` is the caller's own ordered,
66
+ * domain-specific identity fields (tool/rule/code/normalizedMessage/line/
67
+ * lineContentHash/...) — this function only supplies the canonical
68
+ * `relativeFile` component and the hash/prefix wiring.
69
+ *
70
+ * Both `undefined` AND `null` entries fold to `""` (review-round F4,
71
+ * #1816), matching the `String(x ?? "")` idiom every pre-#1816 id builder
72
+ * used. `null` is in the parts type despite every caller's field being
73
+ * declared `T | undefined` in TypeScript: those fields (`Diagnostic.code`,
74
+ * `.rule`, etc.) are frequently assigned straight from `JSON.parse`'d tool
75
+ * output, which defeats the static type at runtime — a runner that emits
76
+ * `"code": null` produces a real `null`, not `undefined`. Folding only
77
+ * `undefined` would silently hash that as the string `"null"` instead of
78
+ * `""`, diverging from every other id-construction path for the exact same
79
+ * finding — a fresh, narrower instance of the #533 divergence class this
80
+ * module exists to eliminate.
81
+ */
82
+ export function stableFindingId(prefix, args) {
83
+ const joined = [
84
+ relativeFile(args.filePath, args.cwd),
85
+ ...args.parts.map((part) => part === undefined || part === null ? "" : String(part)),
86
+ ].join("|");
87
+ return `${prefix}${hashText(joined)}`;
88
+ }
@@ -1,7 +1,8 @@
1
1
  /** Shared lazy formatter catalog seam (#1394). */
2
- let formatterPromise;
2
+ import { createLazyImport } from "./lazy-import.js";
3
+ const lazyFormatters = createLazyImport(() => import("./formatters.js"));
3
4
  export function warmFormatters() {
4
- return (formatterPromise ??= import("./formatters.js"));
5
+ return lazyFormatters.get();
5
6
  }
6
7
  export function loadFormatters() {
7
8
  return warmFormatters();