@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
@@ -34,6 +34,112 @@ pi-lens gives AI coding agents fast, language-aware feedback while they write/ed
34
34
  - MCP server (experimental) so Claude Code or any MCP client can drive the
35
35
  same diagnostics/read-substitute tools pi-lens exposes to pi
36
36
 
37
+ ## Architecture
38
+
39
+ Most lifecycle events enter through one wrapper, which drops and counts events
40
+ that arrive on a replaced session. `tool_call` registers raw: it delegates
41
+ straight to a handler that owns its own total guard. Events fan out into the
42
+ edit-time lane and the LSP lane. Both lanes write into the findings stores.
43
+ Nothing reaches the agent from those stores until a freshness gate or an
44
+ explicit age label clears it.
45
+
46
+ ```mermaid
47
+ flowchart TD
48
+ subgraph host["pi host"]
49
+ HOST["Host events<br/>tool_call, tool_result, turn_start/end,<br/>session_start/shutdown, agent_end, context"]
50
+ WRAP["Stale-ctx wrapper<br/>skips and counts events on a replaced session<br/>tool_result, turn_start, turn_end, agent_end,<br/>agent_settled, session_start, context"]
51
+ end
52
+
53
+ subgraph guards["Guards"]
54
+ RG["Read-guard<br/>blocks edits that lack prior reading"]
55
+ GG["Git-guard<br/>holds commit/push while findings stay unresolved"]
56
+ end
57
+
58
+ subgraph edit["Edit-time lane"]
59
+ PIPE["Post-write pipeline<br/>secrets, format, autofix, sync, lint, tests"]
60
+ PLAN["Dispatch plan<br/>per file kind, per capability group"]
61
+ RUN["Runners<br/>format, lint, types, security, smells, docs"]
62
+ STRUCT["Structural rules<br/>tree-sitter queries and ast-grep"]
63
+ BUS["files-touched bus<br/>tells extensions which paths moved"]
64
+ end
65
+
66
+ subgraph lsp["LSP lane"]
67
+ POOL["Client pool<br/>warm reuse, idle eviction"]
68
+ DIAGS["File and workspace diagnostics"]
69
+ CASC["Impact cascade<br/>tiered wait policy"]
70
+ end
71
+
72
+ STORES["Findings stores<br/>widget state, warning caches, project snapshot"]
73
+
74
+ subgraph gate["Freshness gating"]
75
+ FRESH["Path freshness<br/>mtime vs scan time, past-EOF, dependency drift"]
76
+ DISPO["Dispositions<br/>false-positive, suppress, defer, flagged"]
77
+ LABEL["Explicit age label<br/>for findings no path gate can check"]
78
+ end
79
+
80
+ subgraph deliver["Delivery surfaces"]
81
+ TURN["Turn-end findings injection"]
82
+ WIDGET["Widget and footer tally"]
83
+ TOOLS["lens_diagnostics tool"]
84
+ NUDGE["Agent nudges"]
85
+ end
86
+
87
+ SESSION["Session lifecycle<br/>primary, sequential replacement, concurrent secondary"]
88
+ SINKS["Observability sinks<br/>latency.log, degradation ledger, bounded telemetry,<br/>cache observability, cascade and tree-sitter logs"]
89
+
90
+ HOST --> WRAP
91
+ HOST -->|tool_call, raw| RG
92
+ HOST -->|tool_call, raw| GG
93
+ WRAP -->|session_start| SESSION
94
+ WRAP -->|tool_result| PIPE
95
+ WRAP -->|tool_result, records reads and writes| RG
96
+ SESSION --> POOL
97
+ SESSION --> STORES
98
+ PIPE --> PLAN
99
+ PLAN --> RUN
100
+ PLAN --> STRUCT
101
+ PIPE --> POOL
102
+ PIPE --> BUS
103
+ POOL --> DIAGS
104
+ DIAGS --> CASC
105
+ RUN --> STORES
106
+ STRUCT --> STORES
107
+ DIAGS --> STORES
108
+ CASC --> STORES
109
+ BUS --> NUDGE
110
+ RG -->|read and edit history filter| NUDGE
111
+ STORES --> FRESH
112
+ STORES --> LABEL
113
+ FRESH --> DISPO
114
+ DISPO --> TURN
115
+ DISPO --> WIDGET
116
+ DISPO --> TOOLS
117
+ LABEL --> TURN
118
+ TURN --> GG
119
+ WRAP --> SINKS
120
+ PIPE --> SINKS
121
+ RUN --> SINKS
122
+ STRUCT --> SINKS
123
+ POOL --> SINKS
124
+ CASC --> SINKS
125
+ RG --> SINKS
126
+ GG --> SINKS
127
+ FRESH --> SINKS
128
+ ```
129
+
130
+ Architecture-level view, updated when a lane changes. Per-tool inventories live
131
+ in [features](docs/features.md) and
132
+ [language coverage](docs/language-coverage.md). Today the edit-time lane carries
133
+ 45+ runner modules over 35+ file kinds, and the LSP lane speaks to a dozen-plus
134
+ language servers.
135
+
136
+ The gating box is an abstraction, not a call order. Freshness covers several
137
+ independent mechanisms: path freshness against scan time, past-EOF line checks,
138
+ and forward-import dependency drift. Dispositions are one more filter alongside
139
+ them, not a second stage every finding walks through. Read the box as "a finding
140
+ passes the gates that apply to it", and see `clients/finding-delivery-gate.ts`
141
+ for the per-surface contract.
142
+
37
143
  ## Install
38
144
 
39
145
  ```bash
@@ -213,11 +319,19 @@ Thanks goes to these wonderful people:
213
319
  </tr>
214
320
  <tr>
215
321
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/pppobear"><img src="https://avatars.githubusercontent.com/u/21952175?v=4" width="100px;" alt=""/><br /><sub><b>pppobear</b></sub></a><br /><a href="#bug-pppobear" title="Bug reports">🐛</a></td>
322
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/bcachet"><img src="https://avatars.githubusercontent.com/u/45542?v=4" width="100px;" alt=""/><br /><sub><b>Bertrand Cachet</b></sub></a><br /><a href="#code-bcachet" title="Code">💻</a></td>
323
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/EarthChen"><img src="https://avatars.githubusercontent.com/u/20179425?v=4" width="100px;" alt=""/><br /><sub><b>earthchen</b></sub></a><br /><a href="#code-EarthChen" title="Code">💻</a></td>
324
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/Don-Yin"><img src="https://avatars.githubusercontent.com/u/65135356?v=4" width="100px;" alt=""/><br /><sub><b>Don Yin</b></sub></a><br /><a href="#code-Don-Yin" title="Code">💻</a></td>
325
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/ELA718"><img src="https://avatars.githubusercontent.com/u/193304463?v=4" width="100px;" alt=""/><br /><sub><b>ELA718</b></sub></a><br /><a href="#doc-ELA718" title="Documentation">📖</a></td>
326
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/sujeito-operator/pilot"><img src="https://avatars.githubusercontent.com/u/313599463?v=4" width="100px;" alt=""/><br /><sub><b>Sujeito Operator</b></sub></a><br /><a href="#code-sujeito-operator" title="Code">💻</a></td>
327
+ <td align="center" valign="top" width="14.28%"><a href="http://www.blahs.life/"><img src="https://avatars.githubusercontent.com/u/620336?v=4" width="100px;" alt=""/><br /><sub><b>Dan Blah</b></sub></a><br /><a href="#bug-danblah" title="Bug reports">🐛</a></td>
328
+ </tr>
329
+ <tr>
216
330
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/3choBoomer"><img src="https://avatars.githubusercontent.com/u/521828?v=4" width="100px;" alt=""/><br /><sub><b>Nathan Cooke</b></sub></a><br /><a href="#code-3choBoomer" title="Code">💻</a></td>
217
331
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/white-hat"><img src="https://avatars.githubusercontent.com/u/922988?v=4" width="100px;" alt=""/><br /><sub><b>Eli Stark</b></sub></a><br /><a href="#code-white-hat" title="Code">💻</a></td>
218
- <td align="center" valign="top" width="14.28%"><a href="https://github.com/marvtub"><img src="https://avatars.githubusercontent.com/u/33159023?v=4" width="100px;" alt=""/><br /><sub><b>Marvin Aziz</b></sub></a><br /><a href="#code-marvtub" title="Code">💻</a></td>
219
- <td align="center" valign="top" width="14.28%"><a href="https://github.com/mjfaga"><img src="https://avatars.githubusercontent.com/u/7584015?v=4" width="100px;" alt=""/><br /><sub><b>Mark Faga</b></sub></a><br /><a href="#code-mjfaga" title="Code">💻</a></td>
220
- <td align="center" valign="top" width="14.28%"><a href="https://github.com/aeturnal"><img src="https://avatars.githubusercontent.com/u/219271200?v=4" width="100px;" alt=""/><br /><sub><b>aeturnal</b></sub></a><br /><a href="#code-aeturnal" title="Code">💻</a></td>
332
+ <td align="center" valign="top" width="14.28%"><a href="https://marvinaziz.de/"><img src="https://avatars.githubusercontent.com/u/33159023?v=4" width="100px;" alt=""/><br /><sub><b>Marvin Aziz</b></sub></a><br /><a href="#code-marvtub" title="Code">💻</a></td>
333
+ <td align="center" valign="top" width="14.28%"><a href="https://github.com/mjfaga"><img src="https://avatars.githubusercontent.com/u/7584015?v=4" width="100px;" alt=""/><br /><sub><b>Mark</b></sub></a><br /><a href="#code-mjfaga" title="Code">💻</a></td>
334
+ <td align="center" valign="top" width="14.28%"><a href="https://aeturnal.io/"><img src="https://avatars.githubusercontent.com/u/219271200?v=4" width="100px;" alt=""/><br /><sub><b>aeturnal</b></sub></a><br /><a href="#code-aeturnal" title="Code">💻</a></td>
221
335
  <td align="center" valign="top" width="14.28%"><a href="https://github.com/floatGray"><img src="https://avatars.githubusercontent.com/u/44295302?v=4" width="100px;" alt=""/><br /><sub><b>floatGray</b></sub></a><br /><a href="#code-floatGray" title="Code">💻</a></td>
222
336
  </tr>
223
337
  </tbody>
@@ -16,10 +16,52 @@ select = [
16
16
  "SIM", # flake8-simplify (simplifiable constructs)
17
17
  "C4", # flake8-comprehensions (unnecessary comprehension patterns)
18
18
  "PIE", # flake8-pie (misc lints)
19
+ "S", # flake8-bandit (Bandit-equivalent security checks; refs #1757)
19
20
  ]
20
21
 
22
+ # C90 (mccabe cyclomatic complexity) — considered and NOT enabled (refs #1757).
23
+ # Measured against `requests` (mature, well-styled: 2 hits over the default
24
+ # threshold of 10, both genuinely complex) and `pandas` (379 hits) — the
25
+ # signal is real complexity, not false positives, but the volume on a large
26
+ # pre-existing codebase would drown the security signal `S` adds in the same
27
+ # pass. C90 is a maintainability metric, not a Bandit-equivalent security
28
+ # check, so it stays out of scope for this issue. Revisit as its own opt-in
29
+ # if pi-lens grows a "code health" ruleset.
30
+
31
+ # S sub-rules excluded below were triaged by running `ruff check --select S`
32
+ # against tests/fixtures/real-bugs/python/silent-and-security.py (this repo's
33
+ # own security fixture — 3/3 true positives: S110, S105, S307) and against the
34
+ # `requests` and `pip` packages installed under a local Python 3.11 (394
35
+ # combined S findings across two mature, widely-audited real-world
36
+ # codebases) — chosen as the "2-3 real fixtures" because pi-lens's own repo
37
+ # only has ~15 Python files, too small to expose over-firing sub-rules.
21
38
  ignore = [
22
39
  "E501", # line too long — formatter handles this
23
40
  "B008", # function call in default argument — common FastAPI/typer pattern
24
41
  "SIM108", # ternary operator — readability is subjective
42
+
43
+ # S101 assert: 354 of 394 S hits (90%) across requests+pip were bare
44
+ # `assert` statements — the risk `S101` warns about (asserts stripped under
45
+ # `python -O`) is real only for security-enforcement code, not general
46
+ # application or test code, where `assert` is idiomatic (pytest). Pure
47
+ # noise at this volume.
48
+ "S101",
49
+ # S311 suspicious-non-cryptographic-random-usage: every hit observed
50
+ # (e.g. pip/_internal/utils/filesystem.py building a temp-file suffix) was
51
+ # a non-security use of `random` — file names, jitter, sampling. Ruff
52
+ # cannot distinguish security-sensitive randomness from ordinary use.
53
+ "S311",
54
+ # S603 subprocess-without-shell-equals-true: fires on every list-argument
55
+ # `subprocess.run(...)`/`Popen(...)` call regardless of whether the
56
+ # arguments are attacker-controlled — this is the RECOMMENDED safe form
57
+ # (no shell=True), yet it was the rule's only trigger condition in every
58
+ # one of the 10 hits observed in pip. Bandit's own docs note this rule's
59
+ # high false-positive rate; excluded for the same reason upstream projects
60
+ # commonly disable it.
61
+ "S603",
62
+ # S607 start-process-with-partial-path: fires whenever a subprocess call
63
+ # names its executable by PATH lookup (`["rustc", "--version"]`) instead of
64
+ # an absolute path — standard practice for any CLI-wrapping code, and both
65
+ # observed hits in pip were exactly that pattern, not a real vulnerability.
66
+ "S607",
25
67
  ]
@@ -1,6 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import * as fs from "node:fs";
3
3
  import * as path from "node:path";
4
+ import { hashText, normalizeMessage, stableFindingId, } from "./finding-identity.js";
4
5
  import { applyWorkspaceEdit } from "./lsp/edits.js";
5
6
  import { getLSPService } from "./lsp/index.js";
6
7
  import { normalizeMapKey } from "./path-utils.js";
@@ -14,19 +15,47 @@ let beforeWarningStateLockForTests = null;
14
15
  export function _setBeforeWarningStateLockForTests(hook) {
15
16
  beforeWarningStateLockForTests = hook;
16
17
  }
17
- function normalizeMessage(message) {
18
- return message.replace(/\s+/g, " ").trim().toLowerCase();
19
- }
20
- function hashText(value, length = 10) {
21
- return createHash("sha256").update(value).digest("hex").slice(0, length);
22
- }
23
- function relativeFile(filePath, cwd) {
24
- const rel = path.relative(cwd, filePath).replace(/\\/g, "/");
25
- return rel && !rel.startsWith("..") ? rel : normalizeMapKey(filePath);
26
- }
18
+ /** #1816: was a local `relativeFile|tool|source|code|rule|normalizedMessage|
19
+ * line` hash, hand-rolled independently of `diagnostic-dispositions.ts`'s
20
+ * canonicalizing version — this is now the shared `finding-identity.js`
21
+ * builder (which DOES canonicalize both `cwd` and `filePath` through
22
+ * `normalizeMapKey` before relativizing, and hashes to 12 chars, matching
23
+ * dispositions). See `legacyActionableWarningId` below for the pre-#1816
24
+ * formula, kept only for on-disk suppression-store migration. */
27
25
  export function createActionableWarningId(args) {
26
+ return stableFindingId("aw:", {
27
+ cwd: args.cwd,
28
+ filePath: args.filePath,
29
+ parts: [
30
+ args.tool,
31
+ args.source,
32
+ args.code,
33
+ args.rule,
34
+ normalizeMessage(args.message),
35
+ args.line,
36
+ ],
37
+ });
38
+ }
39
+ /** PRE-#1816 id formula (raw, non-canonicalized `relativeFile`; 10-char
40
+ * hash). `actionable-warning-state.json` is a keyed, persisted store — a
41
+ * warning suppressed under the old formula must not silently reappear as
42
+ * unsuppressed just because this module unified onto the canonical,
43
+ * 12-char id. `suppressionFor`/`updateWarningState` use this ONLY to look up
44
+ * and migrate a still-pending old entry forward; nothing ever WRITES under
45
+ * this id. Do not canonicalize this function — that would make it identical
46
+ * to `createActionableWarningId` and silently defeat the migration lookup
47
+ * for every path that actually needed canonicalizing (the #533 class this
48
+ * whole item exists to fix). Review-round F3 (#1816): this guard is only
49
+ * provable under a MIS-CASED path fixture — a fixture whose raw and
50
+ * canonical forms coincide (a bare mkdtempSync path) makes canonicalizing
51
+ * this function a no-op, so the regression test must seed under a mis-cased
52
+ * segment (see `actionable-warnings.test.ts`'s migration describe block) or
53
+ * the guard passes vacuously either way. */
54
+ function legacyActionableWarningId(args) {
55
+ const rel = path.relative(args.cwd, args.filePath).replace(/\\/g, "/");
56
+ const legacyRelativeFile = rel && !rel.startsWith("..") ? rel : normalizeMapKey(args.filePath);
28
57
  const parts = [
29
- relativeFile(args.filePath, args.cwd),
58
+ legacyRelativeFile,
30
59
  args.tool ?? "",
31
60
  args.source ?? "",
32
61
  String(args.code ?? ""),
@@ -34,7 +63,7 @@ export function createActionableWarningId(args) {
34
63
  normalizeMessage(args.message),
35
64
  String(args.line ?? ""),
36
65
  ];
37
- return `aw:${hashText(parts.join("|"))}`;
66
+ return `aw:${hashText(parts.join("|"), 10)}`;
38
67
  }
39
68
  function actionSafety(action) {
40
69
  const kind = action.kind ?? "";
@@ -93,7 +122,28 @@ function updateWarningState(cwd, warnings) {
93
122
  const now = new Date().toISOString();
94
123
  state.warnings ??= {};
95
124
  for (const warning of warnings) {
96
- const existing = state.warnings[warning.id] ?? {};
125
+ // #1816 migration: this warning may still be recorded under the
126
+ // pre-#1816 id (raw relativeFile, 10-char hash) from before this
127
+ // store unified onto the canonical id. Fold that entry forward
128
+ // onto the current id and drop the stale key, so a warning
129
+ // suppressed before the migration stays suppressed, and repeated
130
+ // re-encounters converge the store onto one id per warning
131
+ // instead of accumulating both forever.
132
+ //
133
+ // Review-round F1: this MUST read `warning.legacyId` — the value
134
+ // `suppressionFor` already computed from the exact identity args
135
+ // used at lookup time — and must NEVER re-derive a legacy id from
136
+ // `warning.rule`/`tool`/`source`/`code`. Those fields hold
137
+ // DISPLAY values that diverge from the id-construction args for
138
+ // LSP-origin records (see `ActionableWarningRecord.legacyId`'s
139
+ // doc comment), so a re-derivation here would compute a
140
+ // different legacy id than the one `suppressionFor` checked,
141
+ // permanently bifurcating the store.
142
+ const legacyId = warning.legacyId;
143
+ const legacyEntry = legacyId && legacyId !== warning.id
144
+ ? state.warnings[legacyId]
145
+ : undefined;
146
+ const existing = state.warnings[warning.id] ?? legacyEntry ?? {};
97
147
  state.warnings[warning.id] = {
98
148
  ...existing,
99
149
  status: existing.status ?? "active",
@@ -101,6 +151,8 @@ function updateWarningState(cwd, warnings) {
101
151
  lastSeenAt: now,
102
152
  seenCount: (existing.seenCount ?? 0) + 1,
103
153
  };
154
+ if (legacyEntry && legacyId)
155
+ delete state.warnings[legacyId];
104
156
  }
105
157
  return state;
106
158
  },
@@ -115,36 +167,64 @@ function updateWarningState(cwd, warnings) {
115
167
  }),
116
168
  });
117
169
  }
118
- function suppressionFor(cwd, id) {
119
- const entry = readSuppressionState(cwd).warnings?.[id];
170
+ /** Looks up suppression under the current id, falling back to the pre-#1816
171
+ * id (see `legacyActionableWarningId`) so a warning suppressed before this
172
+ * migration doesn't silently reappear as unsuppressed. `args` is the exact
173
+ * identity shape both id builders take.
174
+ *
175
+ * Also RETURNS the `legacyId` it computed (review-round F1, #1816): the
176
+ * caller carries it onto the record's `legacyId` field so
177
+ * `updateWarningState` can migrate the SAME legacy id this lookup used,
178
+ * instead of re-deriving one from the record's own `rule`/`tool`/`source`/
179
+ * `code` fields later. Re-deriving is unsound for LSP-origin records —
180
+ * `recordFromLspDiagnostic` passes no `rule` into this function (LSP
181
+ * diagnostics don't have one), then sets `record.rule` afterward to
182
+ * `${source}:${code}` purely for display. Recomputing from that display
183
+ * value would silently compute a DIFFERENT legacy id than the one actually
184
+ * checked here, permanently bifurcating the store: a suppression written
185
+ * this turn under the current id would never be found again next turn. */
186
+ function suppressionFor(cwd, id, args) {
187
+ const state = readSuppressionState(cwd);
188
+ const legacyId = legacyActionableWarningId({ cwd, ...args });
189
+ const entry = state.warnings?.[id] ??
190
+ (legacyId !== id ? state.warnings?.[legacyId] : undefined);
120
191
  return {
121
192
  suppressed: entry?.status === "suppressed",
122
193
  reason: entry?.reason,
194
+ legacyId,
123
195
  };
124
196
  }
125
197
  export function recordFromDispatchDiagnostic(diagnostic, cwd) {
126
- if (diagnostic.semantic !== "warning" || diagnostic.severity !== "warning")
198
+ if (diagnostic.semantic !== "warning")
199
+ return undefined;
200
+ // #1777: the old gate demanded `severity === "warning"` exactly, which was
201
+ // invisible while the ast-grep runner collapsed every non-error tier to
202
+ // "warning". Now that hint and info survive the dispatch path, admit them:
203
+ // a fix is a fix, and the tier governs how loudly a finding renders, not
204
+ // whether its fix is worth offering. `error` still routes to the blocking
205
+ // path, so it stays out even when a runner leaves `semantic` at "warning".
206
+ if (diagnostic.severity === "error")
127
207
  return undefined;
128
208
  if (!diagnostic.fixable && !diagnostic.fixSuggestion)
129
209
  return undefined;
130
210
  const filePath = path.resolve(cwd, diagnostic.filePath);
131
- const id = createActionableWarningId({
132
- cwd,
211
+ const identityArgs = {
133
212
  filePath,
134
213
  tool: diagnostic.tool,
135
214
  code: diagnostic.code,
136
215
  rule: diagnostic.rule,
137
216
  message: diagnostic.message,
138
217
  line: diagnostic.line,
139
- });
140
- const suppression = suppressionFor(cwd, id);
218
+ };
219
+ const id = createActionableWarningId({ cwd, ...identityArgs });
220
+ const suppression = suppressionFor(cwd, id, identityArgs);
141
221
  return {
142
222
  id,
143
223
  filePath,
144
224
  displayPath: toRunnerDisplayPath(cwd, filePath),
145
225
  line: diagnostic.line,
146
226
  column: diagnostic.column,
147
- severity: "warning",
227
+ severity: diagnostic.severity,
148
228
  tool: diagnostic.tool,
149
229
  code: diagnostic.code,
150
230
  rule: diagnostic.rule,
@@ -155,6 +235,7 @@ export function recordFromDispatchDiagnostic(diagnostic, cwd) {
155
235
  actions: [],
156
236
  suppressed: suppression.suppressed,
157
237
  suppressionReason: suppression.reason,
238
+ legacyId: suppression.legacyId,
158
239
  origin: "dispatch",
159
240
  };
160
241
  }
@@ -170,16 +251,16 @@ function recordFromLspDiagnostic(diag, filePath, cwd) {
170
251
  const column = diag.range.start.character + 1;
171
252
  const source = diag.source ?? "lsp";
172
253
  const code = diag.code === undefined ? undefined : String(diag.code);
173
- const id = createActionableWarningId({
174
- cwd,
254
+ const identityArgs = {
175
255
  filePath,
176
256
  tool: "lsp",
177
257
  source,
178
258
  code,
179
259
  message: diag.message,
180
260
  line,
181
- });
182
- const suppression = suppressionFor(cwd, id);
261
+ };
262
+ const id = createActionableWarningId({ cwd, ...identityArgs });
263
+ const suppression = suppressionFor(cwd, id, identityArgs);
183
264
  return {
184
265
  id,
185
266
  filePath,
@@ -195,6 +276,7 @@ function recordFromLspDiagnostic(diag, filePath, cwd) {
195
276
  actions: [],
196
277
  suppressed: suppression.suppressed,
197
278
  suppressionReason: suppression.reason,
279
+ legacyId: suppression.legacyId,
198
280
  origin: "lsp",
199
281
  };
200
282
  }
@@ -329,8 +411,13 @@ export async function buildActionableWarningsReport(args) {
329
411
  }
330
412
  const merged = mergeWarnings(records);
331
413
  updateWarningState(cwd, merged);
414
+ // legacyId is #1816 migration bookkeeping for updateWarningState above —
415
+ // strip it before the report leaves this function, so it never lands in
416
+ // the `.pi-lens/cache/actionable-warnings.json` cache file or any
417
+ // agent-facing rendering of a warning record.
418
+ const reportWarnings = merged.map(({ legacyId: _legacyId, ...rest }) => rest);
332
419
  const byFile = new Map();
333
- for (const warning of merged) {
420
+ for (const warning of reportWarnings) {
334
421
  const arr = byFile.get(warning.filePath) ?? [];
335
422
  arr.push(warning);
336
423
  byFile.set(warning.filePath, arr);
@@ -342,9 +429,16 @@ export async function buildActionableWarningsReport(args) {
342
429
  warnings,
343
430
  }));
344
431
  const allActions = merged.flatMap((warning) => warning.actions);
432
+ const unsuppressed = merged.filter((warning) => !warning.suppressed);
433
+ const countTier = (tier) => unsuppressed.filter((warning) => warning.severity === tier).length;
345
434
  const summary = {
346
435
  warnings: merged.length,
347
- unsuppressed: merged.filter((warning) => !warning.suppressed).length,
436
+ unsuppressed: unsuppressed.length,
437
+ byTier: {
438
+ warning: countTier("warning"),
439
+ info: countTier("info"),
440
+ hint: countTier("hint"),
441
+ },
348
442
  suppressed: merged.filter((warning) => warning.suppressed).length,
349
443
  files: files.length,
350
444
  actions: allActions.length,
@@ -586,8 +680,17 @@ export function formatActionableWarningsAdvisory(report) {
586
680
  const safe = report.summary.autoFixEligible > 0
587
681
  ? ` ${report.summary.autoFixEligible} appear to have conservative preferred quickfixes.`
588
682
  : "";
683
+ // #1777: hint and info are style opinions, so say how much of the count is
684
+ // opinion. The line appears only when a quiet tier is actually present —
685
+ // an all-warning turn already says everything in the count above.
686
+ const byTier = report.summary.byTier;
687
+ const quiet = byTier ? byTier.hint + byTier.info : 0;
688
+ const tierLine = quiet > 0
689
+ ? `${quiet} of those are hint/info tier — style opinions, worth fixing only while you are already in that code.`
690
+ : undefined;
589
691
  return [
590
692
  `🟡 Fixable warnings introduced this turn: ${report.summary.unsuppressed}.${safe}`,
693
+ tierLine,
591
694
  `Details written to .pi-lens/cache/actionable-warnings.json`,
592
695
  fileList ? `Files:\n${fileList}${more}` : undefined,
593
696
  "If continuing in these files, read that JSON and resolve warnings that are safe and relevant. Do not apply broad refactors unless requested.",