@herbertgao/pi-extensions 2026.8.6 → 2026.8.7

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 (343) hide show
  1. package/README.md +5 -5
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +1 -1
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +1 -1
  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 +272 -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 +1 -1
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +14 -0
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +55 -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 +1 -0
  35. package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +26 -10
  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 +2 -1
  39. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +3 -1
  40. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +2 -2
  41. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/zh.json +2 -2
  42. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +3 -2
  43. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +10 -0
  44. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +3 -1
  45. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +30 -7
  46. package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
  47. package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +30 -4
  48. package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +26 -5
  49. package/node_modules/@narumitw/pi-btw/README.md +120 -111
  50. package/node_modules/@narumitw/pi-btw/dist/index.ts +2898 -0
  51. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +7 -0
  52. package/node_modules/@narumitw/pi-btw/package.json +10 -6
  53. package/node_modules/@narumitw/pi-btw/src/btw.ts +36 -40
  54. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +55 -10
  55. package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +390 -0
  56. package/node_modules/@narumitw/pi-btw/src/menu.ts +45 -2
  57. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
  58. package/node_modules/pi-lens/CHANGELOG.md +909 -0
  59. package/node_modules/pi-lens/README.md +11 -3
  60. package/node_modules/pi-lens/config/ruff/core.toml +42 -0
  61. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +130 -27
  62. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +126 -13
  63. package/node_modules/pi-lens/dist/clients/agent-nudge.js +67 -11
  64. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +9 -3
  65. package/node_modules/pi-lens/dist/clients/atomic-write.js +9 -3
  66. package/node_modules/pi-lens/dist/clients/bash-file-access.js +285 -8
  67. package/node_modules/pi-lens/dist/clients/biome-client.js +61 -30
  68. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
  69. package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +119 -0
  70. package/node_modules/pi-lens/dist/clients/bootstrap.js +12 -1
  71. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +12 -3
  72. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +192 -0
  73. package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
  74. package/node_modules/pi-lens/dist/clients/cascade-format.js +20 -1
  75. package/node_modules/pi-lens/dist/clients/cascade-types.js +9 -1
  76. package/node_modules/pi-lens/dist/clients/child-unref.js +54 -6
  77. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +76 -24
  78. package/node_modules/pi-lens/dist/clients/dead-code-client.js +123 -31
  79. package/node_modules/pi-lens/dist/clients/deadline-utils.js +8 -1
  80. package/node_modules/pi-lens/dist/clients/debug-handles.js +5 -0
  81. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +62 -13
  82. package/node_modules/pi-lens/dist/clients/dependency-checker.js +25 -3
  83. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +147 -33
  84. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
  85. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +52 -2
  86. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +256 -88
  87. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +7 -4
  88. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +5 -0
  89. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +234 -18
  90. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +187 -19
  91. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +6 -3
  92. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +11 -9
  93. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +398 -0
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +11 -3
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +12 -7
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +18 -0
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +4 -0
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +16 -3
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +60 -53
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -0
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +23 -0
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +331 -55
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +38 -5
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +97 -19
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +14 -0
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +20 -0
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +22 -0
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +10 -0
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +18 -6
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +73 -12
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +275 -13
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +21 -6
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +260 -27
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +734 -64
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +86 -11
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +72 -0
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +9 -0
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +9 -0
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -1
  121. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
  122. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
  123. package/node_modules/pi-lens/dist/clients/extension-log.js +22 -1
  124. package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
  125. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +294 -0
  126. package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
  127. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +3 -2
  128. package/node_modules/pi-lens/dist/clients/formatters.js +500 -115
  129. package/node_modules/pi-lens/dist/clients/generation-guard.js +216 -0
  130. package/node_modules/pi-lens/dist/clients/git-guard.js +31 -0
  131. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
  132. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +109 -9
  133. package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
  134. package/node_modules/pi-lens/dist/clients/host-ports.js +8 -0
  135. package/node_modules/pi-lens/dist/clients/installer/index.js +1114 -100
  136. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +58 -0
  137. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +715 -0
  138. package/node_modules/pi-lens/dist/clients/instance-reaper.js +643 -97
  139. package/node_modules/pi-lens/dist/clients/instance-registry.js +87 -17
  140. package/node_modules/pi-lens/dist/clients/jscpd-client.js +82 -6
  141. package/node_modules/pi-lens/dist/clients/knip-client.js +310 -10
  142. package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
  143. package/node_modules/pi-lens/dist/clients/language-profile.js +2 -0
  144. package/node_modules/pi-lens/dist/clients/latency-logger.js +440 -11
  145. package/node_modules/pi-lens/dist/clients/lazy-import.js +21 -0
  146. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -0
  147. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
  148. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +102 -7
  149. package/node_modules/pi-lens/dist/clients/lsp/client.js +1516 -159
  150. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +83 -1
  151. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
  152. package/node_modules/pi-lens/dist/clients/lsp/index.js +2274 -147
  153. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +215 -0
  154. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +146 -14
  155. package/node_modules/pi-lens/dist/clients/lsp/language.js +48 -4
  156. package/node_modules/pi-lens/dist/clients/lsp/server.js +277 -16
  157. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +22 -0
  158. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +43 -0
  159. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +79 -3
  160. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +43 -0
  161. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +422 -28
  162. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +30 -0
  163. package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +175 -0
  164. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +3 -2
  165. package/node_modules/pi-lens/dist/clients/mcp/session.js +10 -2
  166. package/node_modules/pi-lens/dist/clients/module-report.js +8 -0
  167. package/node_modules/pi-lens/dist/clients/opengrep-client.js +15 -1
  168. package/node_modules/pi-lens/dist/clients/package-manager.js +170 -14
  169. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +27 -0
  170. package/node_modules/pi-lens/dist/clients/path-utils.js +160 -0
  171. package/node_modules/pi-lens/dist/clients/pipeline.js +154 -33
  172. package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +37 -0
  173. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +17 -3
  174. package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +89 -22
  175. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +84 -14
  176. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +15 -3
  177. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +50 -2
  178. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +5 -0
  179. package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
  180. package/node_modules/pi-lens/dist/clients/project-snapshot.js +299 -0
  181. package/node_modules/pi-lens/dist/clients/quiet-window-config.js +47 -0
  182. package/node_modules/pi-lens/dist/clients/quiet-window.js +11 -25
  183. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +1 -1
  184. package/node_modules/pi-lens/dist/clients/read-guard.js +184 -10
  185. package/node_modules/pi-lens/dist/clients/resource-sampler.js +49 -17
  186. package/node_modules/pi-lens/dist/clients/reverse-deps.js +50 -11
  187. package/node_modules/pi-lens/dist/clients/review-graph/query.js +52 -4
  188. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +96 -7
  189. package/node_modules/pi-lens/dist/clients/runtime-context.js +8 -1
  190. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +308 -45
  191. package/node_modules/pi-lens/dist/clients/runtime-session.js +332 -9
  192. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
  193. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +212 -79
  194. package/node_modules/pi-lens/dist/clients/runtime-turn.js +575 -67
  195. package/node_modules/pi-lens/dist/clients/safe-spawn.js +220 -7
  196. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +161 -0
  197. package/node_modules/pi-lens/dist/clients/search-read-registration.js +34 -6
  198. package/node_modules/pi-lens/dist/clients/security-scan-client.js +157 -24
  199. package/node_modules/pi-lens/dist/clients/sg-runner.js +116 -22
  200. package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
  201. package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
  202. package/node_modules/pi-lens/dist/clients/startup-timing.js +19 -1
  203. package/node_modules/pi-lens/dist/clients/test-runner-client.js +151 -16
  204. package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
  205. package/node_modules/pi-lens/dist/clients/tool-policy.js +125 -20
  206. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +75 -1
  207. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +769 -64
  208. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +11 -0
  209. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +90 -0
  210. package/node_modules/pi-lens/dist/clients/trivy-client.js +19 -1
  211. package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
  212. package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
  213. package/node_modules/pi-lens/dist/index.js +67738 -55739
  214. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +466 -54
  215. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +132 -43
  216. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
  217. package/node_modules/pi-lens/docs/agent-guide.md +6 -1
  218. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +515 -506
  219. package/node_modules/pi-lens/docs/dispositions.md +21 -0
  220. package/node_modules/pi-lens/docs/features.md +19 -5
  221. package/node_modules/pi-lens/docs/globalconfig.md +3 -0
  222. package/node_modules/pi-lens/docs/language-coverage.md +71 -5
  223. package/node_modules/pi-lens/docs/mcp.md +2 -2
  224. package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
  225. package/node_modules/pi-lens/docs/settings.md +19 -1
  226. package/node_modules/pi-lens/docs/usage.md +1 -0
  227. package/node_modules/pi-lens/package.json +10 -6
  228. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-js-snapshot.yml +23 -0
  229. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-snapshot.yml +23 -0
  230. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/ts-void-zero-snapshot.yml +23 -0
  231. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-object-param-test.yml +16 -0
  232. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +15 -1
  233. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-compile-call-test.yml +29 -1
  234. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-dupe-class-members-test.yml +33 -0
  235. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-js-test.yml +7 -1
  236. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-test.yml +7 -1
  237. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-known-value-widening-test.yml +9 -0
  238. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml +216 -0
  239. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +2 -0
  240. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +2 -0
  241. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +2 -1
  242. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +2 -1
  243. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-return-value-in-generator-test.yml +12 -0
  244. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-runtime-typeof-test.yml +33 -0
  245. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-server-bind-wildcard-test.yml +9 -0
  246. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-shape-in-symbol-names-test.yml +13 -0
  247. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-js-test.yml +5 -1
  248. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-test.yml +5 -1
  249. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-parameters-test.yml +12 -0
  250. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-returns-test.yml +16 -0
  251. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-any-test.yml +10 -0
  252. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-unknown-test.yml +8 -0
  253. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/redundant-unsafe-function-test.yml +35 -0
  254. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/require-safety-comment-for-as-unknown-as-test.yml +177 -0
  255. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ts-void-zero-test.yml +1 -0
  256. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member-js.yml +13 -2
  257. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member.yml +13 -2
  258. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +2 -0
  259. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-object-param.yml +60 -0
  260. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +57 -12
  261. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-compile-call.yml +63 -5
  262. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-dupe-class-members.yml +52 -8
  263. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html-js.yml +27 -2
  264. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html.yml +27 -2
  265. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-known-value-widening.yml +71 -0
  266. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-non-null-assertion.yml +316 -0
  267. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +7 -0
  268. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +22 -2
  269. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +23 -2
  270. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +33 -5
  271. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +34 -8
  272. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-return-value-in-generator.yml +22 -5
  273. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-runtime-typeof.yml +121 -0
  274. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-server-bind-wildcard.yml +23 -7
  275. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-shape-in-symbol-names.yml +68 -0
  276. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +41 -2
  277. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code.yml +41 -2
  278. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +6 -1
  279. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-parameters.yml +67 -0
  280. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-returns.yml +106 -0
  281. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-any.yml +50 -0
  282. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-unknown.yml +56 -0
  283. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +2 -0
  284. package/node_modules/pi-lens/rules/ast-grep-rules/rules/redundant-unsafe-function.yml +32 -0
  285. package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml +184 -0
  286. package/node_modules/pi-lens/rules/ast-grep-rules/rules/ts-void-zero.yml +5 -0
  287. package/node_modules/pi-lens/rules/ast-grep-rules/self-scan-baseline.json +5 -0
  288. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +53 -1
  289. package/node_modules/pi-lens/scripts/download-grammars.js +25 -0
  290. package/node_modules/pi-lens/scripts/grammars.lock.json +9 -0
  291. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +2 -0
  292. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +80 -3
  293. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +41 -0
  294. package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
  295. package/node_modules/pi-mcp-adapter/CHANGELOG.md +36 -0
  296. package/node_modules/pi-mcp-adapter/README.md +47 -5
  297. package/node_modules/pi-mcp-adapter/cli.js +163 -1
  298. package/node_modules/pi-mcp-adapter/commands.ts +128 -22
  299. package/node_modules/pi-mcp-adapter/config.ts +25 -7
  300. package/node_modules/pi-mcp-adapter/direct-tools.ts +5 -4
  301. package/node_modules/pi-mcp-adapter/index.ts +219 -32
  302. package/node_modules/pi-mcp-adapter/init.ts +36 -4
  303. package/node_modules/pi-mcp-adapter/lifecycle.ts +315 -24
  304. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +39 -6
  305. package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +387 -0
  306. package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +27 -3
  307. package/node_modules/pi-mcp-adapter/mcp-code.ts +4 -0
  308. package/node_modules/pi-mcp-adapter/mcp-panel.ts +42 -13
  309. package/node_modules/pi-mcp-adapter/metadata-cache.ts +32 -21
  310. package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
  311. package/node_modules/pi-mcp-adapter/package.json +3 -1
  312. package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
  313. package/node_modules/pi-mcp-adapter/request-headers-command.ts +31 -37
  314. package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
  315. package/node_modules/pi-mcp-adapter/server-manager.ts +140 -2
  316. package/node_modules/pi-mcp-adapter/session-recovery.ts +7 -0
  317. package/node_modules/pi-mcp-adapter/tool-approval.ts +15 -2
  318. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
  319. package/node_modules/pi-mcp-adapter/types.ts +2 -0
  320. package/node_modules/pi-mcp-adapter/ui-server.ts +18 -16
  321. package/node_modules/pi-mcp-adapter/utils.ts +70 -0
  322. package/node_modules/pi-web-access/CHANGELOG.md +23 -0
  323. package/node_modules/pi-web-access/README.md +27 -9
  324. package/node_modules/pi-web-access/anysearch.ts +4 -2
  325. package/node_modules/pi-web-access/brave.ts +16 -4
  326. package/node_modules/pi-web-access/curator-page.ts +6 -3
  327. package/node_modules/pi-web-access/curator-server.ts +4 -1
  328. package/node_modules/pi-web-access/exa.ts +18 -7
  329. package/node_modules/pi-web-access/extract.ts +28 -3
  330. package/node_modules/pi-web-access/gemini-search.ts +16 -4
  331. package/node_modules/pi-web-access/index.ts +41 -57
  332. package/node_modules/pi-web-access/package.json +1 -1
  333. package/node_modules/pi-web-access/page-query.ts +4 -2
  334. package/node_modules/pi-web-access/parallel-mcp.ts +249 -0
  335. package/node_modules/pi-web-access/parallel.ts +2 -2
  336. package/node_modules/pi-web-access/query-rewrite.ts +51 -0
  337. package/node_modules/pi-web-access/serper.ts +211 -0
  338. package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
  339. package/node_modules/pi-web-access/summary-review.ts +44 -22
  340. package/node_modules/pi-web-access/tavily.ts +16 -4
  341. package/node_modules/pi-web-access/utils.ts +87 -0
  342. package/node_modules/pi-web-access/valyu.ts +199 -0
  343. package/package.json +13 -13
@@ -1,9 +1,20 @@
1
1
  id: no-await-expression-member-js
2
2
  language: JavaScript
3
3
  severity: hint
4
- message: "Unnecessary parentheses around await — write await expr.prop directly"
4
+ message: "(await expr).prop — do not rewrite to await expr.prop (that reads .prop off the unresolved promise). Keep the parens, or destructure first: const x = await expr; x.prop"
5
5
  note: |
6
- (await expr).prop can be written as await expr.prop — the parens are redundant.
6
+ `(await expr).prop` awaits `expr` first, THEN reads `.prop` off the
7
+ resolved value. `await expr.prop` is NOT equivalent: `.` binds
8
+ tighter than `await`, so it reads `.prop` off the still-pending
9
+ Promise first (almost always `undefined`, since Promise objects
10
+ don't have arbitrary properties) and only then awaits that.
11
+ The rule previously told the caller to make this exact swap — bad
12
+ advice that fabricates a bug at every fix site (#1806 audit). The
13
+ correct move is either to keep the parenthesized form as-is (it's
14
+ already correct, just not "unnecessary") or to destructure into a
15
+ named variable first: `const resolved = await expr; resolved.prop`.
16
+ There's no autofix here on purpose — which form reads better is a
17
+ judgment call, not a mechanical rewrite.
7
18
  Exception: (await import(...)).prop is the standard dynamic import pattern.
8
19
  rule:
9
20
  pattern: "(await $EXPR).$PROP"
@@ -1,9 +1,20 @@
1
1
  id: no-await-expression-member
2
2
  language: TypeScript
3
3
  severity: hint
4
- message: "Unnecessary parentheses around await — write await expr.prop directly"
4
+ message: "(await expr).prop — do not rewrite to await expr.prop (that reads .prop off the unresolved promise). Keep the parens, or destructure first: const x = await expr; x.prop"
5
5
  note: |
6
- (await expr).prop can be written as await expr.prop — the parens are redundant.
6
+ `(await expr).prop` awaits `expr` first, THEN reads `.prop` off the
7
+ resolved value. `await expr.prop` is NOT equivalent: `.` binds
8
+ tighter than `await`, so it reads `.prop` off the still-pending
9
+ Promise first (almost always `undefined`, since Promise objects
10
+ don't have arbitrary properties) and only then awaits that.
11
+ The rule previously told the caller to make this exact swap — bad
12
+ advice that fabricates a bug at every fix site (#1806 audit). The
13
+ correct move is either to keep the parenthesized form as-is (it's
14
+ already correct, just not "unnecessary") or to destructure into a
15
+ named variable first: `const resolved = await expr; resolved.prop`.
16
+ There's no autofix here on purpose — which form reads better is a
17
+ judgment call, not a mechanical rewrite.
7
18
  Exception: (await import(...)).prop is the standard dynamic import pattern.
8
19
  rule:
9
20
  pattern: "(await $EXPR).$PROP"
@@ -1,6 +1,8 @@
1
1
  id: no-bare-host-path-in-win32-branch
2
2
  language: TypeScript
3
3
  severity: warning
4
+ metadata:
5
+ category: pi-lens-self-scan
4
6
  message: "Use win32 path operations inside a branch committed to Windows path semantics"
5
7
  note: |
6
8
  A branch guarded by isWindowsPath/isFullyQualifiedWin32 has committed to
@@ -0,0 +1,60 @@
1
+ id: no-bare-object-param
2
+ language: TypeScript
3
+ severity: error
4
+ metadata:
5
+ category: pi-lens-self-scan
6
+ message: "Parameter typed bare 'object' — guarantees nothing about shape, use Record<string, unknown> or a real interface"
7
+ note: |
8
+ `object` only tells the compiler "not a primitive" — it doesn't
9
+ guarantee any property exists, so every consumer still has to cast
10
+ or reach for `as` before doing anything useful. Use
11
+ `Record<string, unknown>` for an open bag of properties, or a real
12
+ interface/type when the shape is known.
13
+
14
+ Scope: direct annotations only — a parameter (required or optional)
15
+ whose type annotation is exactly the bare `object` keyword, matched
16
+ structurally at the `predefined_type` leaf so it fires the same way
17
+ whether the parameter sits in a function declaration, an arrow
18
+ function, a class method, an interface method signature, or a
19
+ function-type alias (all four share the same
20
+ `required_parameter`/`optional_parameter` -> `type_annotation` ->
21
+ `predefined_type` shape in tree-sitter-typescript). Anti-slop's
22
+ transitive-alias-resolution half (flag a parameter typed with an
23
+ alias that itself resolves to bare `object`) is intentionally
24
+ dropped — that needs same-file symbol lookup ast-grep doesn't do.
25
+ A union member (`object | null`) or an array element (`object[]`)
26
+ is NOT flagged: the type_annotation's only content must be the bare
27
+ keyword, so wrapping it in anything else takes it out of scope
28
+ rather than risk a wider, noisier match than the direct case calls
29
+ for. Capitalized `Object` is a different node kind (`type_identifier`,
30
+ not `predefined_type`) and was never in scope.
31
+
32
+ No JS variant: JavaScript has no type annotations, so this pattern
33
+ has nothing to match there (same call as no-unknown-laundering.yml).
34
+
35
+ FP-scan (napi engine, every .ts/.tsx file under clients/ and tests/,
36
+ 998 files): exactly one hit, `clients/host-ports.ts:8` —
37
+ `export type HostLogSink = (entry: object) => void;`. That's a
38
+ function-type alias, confirming the rule does cover function-type
39
+ parameters, not just declarations/methods. Fixed in the same PR by
40
+ narrowing to `Record<string, unknown>`: `HostLogSink` feeds
41
+ `NdjsonLogger.log(obj: unknown)` through the host's log sink, and
42
+ every real log record is a structured key/value bag, not an opaque
43
+ non-primitive — `Record<string, unknown>` says that honestly without
44
+ over-committing to a fixed shape. Zero hits remained after the fix,
45
+ so severity stays at `warning` rather than `hint`.
46
+
47
+ 2026-08-19 (refs #1718): promoted `warning` -> `error` as part of the
48
+ anti-slop pattern adoption. Re-ran the FP scan on the current tree
49
+ (clients/ + tests/, same napi engine): still 0 hits. A zero-violation
50
+ rule costs nothing to run at `error`, and it stays free only if
51
+ promoted before someone writes the first one.
52
+ rule:
53
+ kind: predefined_type
54
+ regex: "^object$"
55
+ inside:
56
+ kind: type_annotation
57
+ inside:
58
+ any:
59
+ - kind: required_parameter
60
+ - kind: optional_parameter
@@ -1,21 +1,66 @@
1
1
  id: no-chained-type-assertions
2
2
  language: TypeScript
3
- severity: warning
3
+ severity: error
4
+ metadata:
5
+ category: pi-lens-self-scan
4
6
  message: "Chained type assertion (x as A as B) — stacking assertions with no runtime check between them"
5
7
  note: |
6
8
  `x as A as B` stacks two assertions with no runtime check between
7
9
  them, so the compiler can't verify either hop. Narrow with a type
8
10
  guard, or assert once to the type you actually need. `as const`
9
11
  chains are allowed — they don't launder the value's type, they just
10
- freeze a literal. `as unknown as B` chains are also allowed: routing
11
- a cast through `unknown` (rather than through an unrelated concrete
12
- type) is the standard, TypeScript-endorsed way to perform a cast that
13
- the compiler can't otherwise verify as safe — see no-as-any.yml's own
14
- note, which recommends this exact form as the safe replacement for
15
- `as any`. An FP-scan of the pi-lens codebase found 22 chained-assertion
16
- hits and all 22 were `as unknown as`; none were a genuine two
17
- concrete-type stack.
12
+ freeze a literal.
13
+
14
+ 2026-08-19 (refs #1718): promoted `warning` -> `error` and DROPPED the
15
+ `as unknown as $B` exemption as part of adopting anti-slop's
16
+ `no-chained-type-assertions` at its upstream strictness for the
17
+ shipped catalog. anti-slop's own rule (dmmulroy/anti-slop,
18
+ src/rules/no-chained-type-assertions.ts) treats `as unknown as` as a
19
+ forbidden chain too — routing a cast through `unknown` still discards
20
+ the original type's evidence, it just discards it in two hops instead
21
+ of one. The earlier note here argued `as unknown as` was the
22
+ TypeScript-endorsed safe-cast idiom (no-as-any.yml's own
23
+ recommendation) and cited a 22-hit FP scan where every chained-assertion
24
+ hit in pi-lens's own tree was that form — that FP-load argument is
25
+ still true, but it is an argument for pi-lens's OWN code, and this
26
+ catalog ships to other repositories. Users get the stricter upstream
27
+ form; pi-lens's own ~22 `as unknown as` chains stay non-conforming
28
+ until #1718 designs a self-scan baseline (or a follow-up narrows this
29
+ rule back down) — the same trade the audit made for every hint-tier
30
+ row in this PR: adopt the useful pattern for the product without
31
+ forcing pi-lens's own history to retroactively conform in the same PR.
32
+
33
+ 2026-08-20 (review round, refs #1718): `error` severity is semantic-
34
+ blocking (ast-grep-napi.ts:699) with no independent escape valve — a
35
+ caller who follows the sibling `require-safety-comment-for-as-unknown-as.yml`
36
+ hint and adds a `SAFETY:` comment still hit a hard block, because the
37
+ two rules were wired independently. Fixed by giving THIS rule its own
38
+ `SAFETY:` exemption for the `as unknown as` arm specifically (the same
39
+ relational check — `follows`/`inside` a preceding comment matching
40
+ `SAFETY\s*:` — as the sibling hint rule, so a commented site satisfies
41
+ both at once). A genuine two-concrete-type chain (`x as A as B`, no
42
+ `unknown` hop) gets NO escape valve: that shape has no legitimate
43
+ reading upstream or here, so it stays hard-blocked. The two rules are
44
+ now a coherent pair: an uncommented `as unknown as` chain is a hard
45
+ error; a `SAFETY:`-commented one is clean; the hint rule keeps
46
+ teaching the convention on every OTHER assertion form.
47
+
48
+ 2026-08-20 (refs #1727, #1777): the `as unknown as` arm is REMOVED from
49
+ this rule and delegated wholly to
50
+ `require-safety-comment-for-as-unknown-as.yml`, which was promoted to
51
+ `error` in the same change. The two rules previously matched the exact
52
+ same site list — verified identical on four corpora (16/16 pi-lens
53
+ `clients/`, 182/182 pi core, 194/194 opencode, and 1803 of this rule's
54
+ 1849 oh-my-pi hits) — so every uncommented `x as unknown as T` raised
55
+ TWO diagnostics for one defect, one of them semantic-blocking. They now
56
+ partition the space: that rule owns the `unknown` hop and carries the
57
+ `SAFETY:` escape valve; this rule owns the concrete `x as A as B`
58
+ chain, which keeps NO escape valve because it has no legitimate
59
+ reading. Residual census for the concrete arm alone (2026-08-20):
60
+ pi-lens 0, pi core 0, opencode 0, oh-my-pi 46. Tagged
61
+ `metadata.category: pi-lens-self-scan` so CI holds pi-lens's own tree
62
+ at that zero.
18
63
  rule:
19
- pattern: $X as $A as $B
20
- not:
21
- pattern: "$X as unknown as $B"
64
+ all:
65
+ - pattern: $X as $A as $B
66
+ - not: { pattern: $X as unknown as $B }
@@ -9,12 +9,70 @@ note: |
9
9
  `compile(source, ...)` with non-literal source compiles arbitrary code
10
10
  that may be executed later. If `source` is user-controlled, this is
11
11
  a code injection vulnerability.
12
- Pattern: matches any compile(...) call. The fixture validates whether
13
- the source is a static string vs dynamic — for the lint, we warn on
14
- every compile() (safe static compiles are rare and easy to refactor
15
- to a module-level constant).
12
+
13
+ Static/trusted source is suppressed (the rule's original ship still
14
+ described this design in prose but the shipped pattern matched every
15
+ compile() call unconditionally — #1806 audit: 3 FP hits, all in an
16
+ eval runner's `ast.parse` → `compile` pipeline). A source is trusted
17
+ when it is:
18
+ - a string literal (`compile('print(1)', ...)`);
19
+ - the direct result of an `ast.<method>(...)` call
20
+ (`compile(ast.parse(source), ...)`); or
21
+ - a variable of the SAME name assigned from `ast.<method>(...)`
22
+ SOMEWHERE in the nearest enclosing function
23
+ (`module = ast.parse(source); compile(module, ...)`).
24
+ The third case covers the common "parse once, compile the tree"
25
+ idiom (including intermediate `ast.Module`/`ast.Expression`
26
+ reconstructions built from an already-parsed tree) without full
27
+ dataflow analysis. It is honestly a same-scope, same-name,
28
+ ANY-ORDER heuristic, not real reaching-definitions: it does not
29
+ check that the `ast.<method>(...)` assignment happens BEFORE the
30
+ `compile()` call, so a later reassignment to untrusted input
31
+ (`module = ast.parse(source); module = user_input;
32
+ compile(module, ...)`) is a known, accepted miss (fixture pins it
33
+ under `valid:` with an explanatory comment — ast-grep's relational
34
+ rules can't express statement ordering, only ancestor/descendant/
35
+ sibling-existence). Anything else (a bare identifier with no such
36
+ assignment anywhere in scope, string concatenation, a call to
37
+ something other than `ast.*`) is still flagged.
38
+
39
+ 2026-08-20 (review round, refs #1806): two follow-up fixes.
40
+ (1) The "same function" scope was `inside: {stopBy: end, kind:
41
+ function_definition}`, which climbs the WHOLE ancestor chain and
42
+ matches the first function_definition ANYWHERE above — including an
43
+ outer function, past a nested one. A nested function whose own
44
+ parameter happens to share a name with an outer function's
45
+ `ast.parse`-derived variable (shadowing, not the same binding) was
46
+ wrongly trusted. Bounded to the NEAREST enclosing function with
47
+ `stopBy: {kind: function_definition}` on the `inside` ascent itself
48
+ (same boundary-rule shape used to scope `no-return-value-in-generator`
49
+ in this PR's first round) — it stops climbing at the first
50
+ function_definition found instead of continuing past it.
51
+ (2) `pattern: compile($SRC, $$$REST)` has a literal comma in its
52
+ source text, so it never matched the single-argument form
53
+ `compile(user_input)` — a silent arity regression from the original
54
+ `compile($$$ARGS)` (any arity). Restored via an explicit `compile($SRC)`
55
+ alternative, mirroring the `$DB.query($SQL)` / `$DB.query($SQL, $$$REST)`
56
+ two-arity shape already used in `no-sql-in-code`.
16
57
  rule:
17
- pattern: compile($$$ARGS)
58
+ any:
59
+ - pattern: compile($SRC)
60
+ - pattern: compile($SRC, $$$REST)
61
+ constraints:
62
+ SRC:
63
+ not:
64
+ any:
65
+ - kind: string
66
+ - pattern: ast.$METHOD($$$A)
67
+ - all:
68
+ - kind: identifier
69
+ - inside:
70
+ stopBy:
71
+ kind: function_definition
72
+ kind: function_definition
73
+ has:
74
+ stopBy: end
75
+ pattern: $SRC = ast.$METHOD($$$A)
18
76
  has_fix: false
19
77
  tags:
20
78
  - python
@@ -9,12 +9,40 @@ rule:
9
9
  - inside:
10
10
  field: name
11
11
  matches: is-class-members
12
- precedes:
13
- stopBy: end
14
- all:
15
- - matches: is-class-members
16
- - has:
17
- matches: accessor-name
12
+ any:
13
+ # 2026-08-20 (review round, refs #1806): staticness must be
14
+ # compared BETWEEN the pair, not blanket-exempted. A static
15
+ # member and a same-named instance member live in separate
16
+ # namespaces (`ClassName.foo` vs `instance.foo`) — no
17
+ # overwrite, correctly exempt. Two static members (or two
18
+ # instance members) with the same name DO collide — the
19
+ # original review-round fix over-corrected by excluding
20
+ # ANY static-enclosed accessor from pairing at all, which
21
+ # silently dropped the rule's core case
22
+ # (`static foo(){} static foo(){}`, the exact silent
23
+ # overwrite this rule exists to catch). These two arms
24
+ # require the anchor and its paired duplicate to agree on
25
+ # staticness: a static anchor only pairs with a later
26
+ # static member, a non-static anchor only pairs with a
27
+ # later non-static member.
28
+ - all:
29
+ - matches: is-static-member
30
+ - precedes:
31
+ stopBy: end
32
+ all:
33
+ - matches: is-static-member
34
+ - has:
35
+ matches: accessor-name
36
+ - all:
37
+ - not:
38
+ matches: is-static-member
39
+ - precedes:
40
+ stopBy: end
41
+ all:
42
+ - not:
43
+ matches: is-static-member
44
+ - has:
45
+ matches: accessor-name
18
46
  - matches: member-name
19
47
  all:
20
48
  - not:
@@ -33,13 +61,21 @@ rule:
33
61
  utils:
34
62
  duplicate-field:
35
63
  matches: is-class-members
64
+ not:
65
+ # Anchored on the member's own text (which starts at its first
66
+ # modifier keyword), not on the single nearest-preceding-sibling
67
+ # token. `follows: pattern: $$ACCESS` only ever binds the LAST
68
+ # modifier before the name — for `static async foo() {}` that is
69
+ # "async", so a `not: regex: static` check nested under that
70
+ # follows clause never sees "static" and the escape valve never
71
+ # fires (#1806 audit: 3 FP hits, static factory + same-named
72
+ # instance method both flagged as duplicates).
73
+ regex: '^static\b'
36
74
  has:
37
75
  matches: member-name
38
76
  any:
39
77
  - follows:
40
78
  pattern: $$ACCESS
41
- not:
42
- regex: static
43
79
  not:
44
80
  regex: constructor
45
81
  - not:
@@ -51,6 +87,14 @@ utils:
51
87
  matches: member-name
52
88
  follows:
53
89
  pattern: $$ACCESS
90
+ is-static-member:
91
+ # Anchored on the member's own text (which starts at its first
92
+ # modifier keyword), not on the single nearest-preceding-sibling
93
+ # token — see the `duplicate-field` comment below for why
94
+ # `follows: pattern: $$ACCESS` can't be trusted to see "static"
95
+ # once another modifier (e.g. "async") sits closer to the name.
96
+ matches: is-class-members
97
+ regex: '^static\b'
54
98
  is-class-members:
55
99
  any:
56
100
  - kind: method_definition
@@ -6,8 +6,33 @@ note: |
6
6
  innerHTML and outerHTML can introduce XSS vulnerabilities when used with
7
7
  user-supplied data. Use textContent for plain text or a library like DOMPurify
8
8
  for sanitized HTML.
9
+
10
+ The assignment forms (`$EL.innerHTML = $VAL` / `$EL.outerHTML = $VAL`)
11
+ are NOT flagged when `$VAL` is a plain string literal or a template
12
+ literal with no `${...}` substitution — clearing a node
13
+ (`el.innerHTML = ''`) or setting static markup
14
+ (`el.innerHTML = "<hr>"`) can't carry injected content, since the
15
+ right-hand side is fixed at author time. Before this constraint every
16
+ literal assignment matched too, which is why 8/8 sampled hits in the
17
+ audit corpus were this exact "clear/reset" idiom (#1806). A dynamic
18
+ value (an identifier, a call, or a template literal with a
19
+ substitution) is still flagged — that's the actual injection surface.
20
+ `insertAdjacentHTML(...)` keeps its original unconditional match: its
21
+ argument shape (`position, html`) doesn't fit the same RHS-literal
22
+ check cleanly, and the issue that drove this fix was specifically the
23
+ assignment forms.
9
24
  rule:
10
25
  any:
11
- - pattern: $EL.innerHTML = $$$
12
- - pattern: $EL.outerHTML = $$$
26
+ - pattern: $EL.innerHTML = $VAL
27
+ - pattern: $EL.outerHTML = $VAL
13
28
  - pattern: $EL.insertAdjacentHTML($$$)
29
+ constraints:
30
+ VAL:
31
+ not:
32
+ any:
33
+ - kind: string
34
+ - all:
35
+ - kind: template_string
36
+ - not:
37
+ has:
38
+ kind: template_substitution
@@ -6,8 +6,33 @@ note: |
6
6
  innerHTML and outerHTML can introduce XSS vulnerabilities when used with
7
7
  user-supplied data. Use textContent for plain text or a library like DOMPurify
8
8
  for sanitized HTML.
9
+
10
+ The assignment forms (`$EL.innerHTML = $VAL` / `$EL.outerHTML = $VAL`)
11
+ are NOT flagged when `$VAL` is a plain string literal or a template
12
+ literal with no `${...}` substitution — clearing a node
13
+ (`el.innerHTML = ''`) or setting static markup
14
+ (`el.innerHTML = "<hr>"`) can't carry injected content, since the
15
+ right-hand side is fixed at author time. Before this constraint every
16
+ literal assignment matched too, which is why 8/8 sampled hits in the
17
+ audit corpus were this exact "clear/reset" idiom (#1806). A dynamic
18
+ value (an identifier, a call, or a template literal with a
19
+ substitution) is still flagged — that's the actual injection surface.
20
+ `insertAdjacentHTML(...)` keeps its original unconditional match: its
21
+ argument shape (`position, html`) doesn't fit the same RHS-literal
22
+ check cleanly, and the issue that drove this fix was specifically the
23
+ assignment forms.
9
24
  rule:
10
25
  any:
11
- - pattern: $EL.innerHTML = $$$
12
- - pattern: $EL.outerHTML = $$$
26
+ - pattern: $EL.innerHTML = $VAL
27
+ - pattern: $EL.outerHTML = $VAL
13
28
  - pattern: $EL.insertAdjacentHTML($$$)
29
+ constraints:
30
+ VAL:
31
+ not:
32
+ any:
33
+ - kind: string
34
+ - all:
35
+ - kind: template_string
36
+ - not:
37
+ has:
38
+ kind: template_substitution
@@ -0,0 +1,71 @@
1
+ id: no-known-value-widening
2
+ language: TypeScript
3
+ severity: hint
4
+ message: "const initialized from an object literal, widened by a Record<...> annotation — prefer inference or 'satisfies'"
5
+ note: |
6
+ Narrowed port of dmmulroy/anti-slop's `no-known-value-widening`
7
+ (src/rules/no-known-value-widening.ts, MIT). Upstream is a full
8
+ data-flow rule: it resolves `const` variable references transitively,
9
+ walks return statements, assignments, property definitions, and type
10
+ assertions, and flags ANY syntactically-known value (object/array/
11
+ function/literal, or a stable `const` binding that resolves to one)
12
+ flowing into an explicitly broad target type (`unknown`, `object`, an
13
+ open `Record<...>`/mapped-type dictionary, or an anonymous object
14
+ type). None of that data-flow — resolving a variable back to its
15
+ declaration, walking a return path — is something ast-grep's
16
+ structural matcher does; building a fake version of it would be
17
+ exactly the "vacuous guard" failure mode this repo's own review
18
+ process screens for.
19
+
20
+ This port keeps ONE syntactically self-contained sub-case: a `const`
21
+ declared with an object-literal initializer AND a `Record<K, V>`
22
+ annotation, matched in the same statement (`const x: Record<K, V> =
23
+ { ... }`). That is exactly what the 2026-08-19 audit measured (87
24
+ hits repo-wide vs. only 30 `satisfies` uses) and is the shape upstream
25
+ cites as the primary example: the object literal's own key/value
26
+ types are already known at the declaration site, and `Record<K, V>`
27
+ throws that evidence away in favor of a uniform key type — `satisfies
28
+ Record<K, V>` (or no annotation at all, letting inference stand) keeps
29
+ the literal's precise keys and value types AND still gets the
30
+ dictionary-shape check.
31
+
32
+ Everything else upstream covers — return-type widening, assignment
33
+ widening, transitively-resolved `const` references, `as`/type-literal
34
+ targets — is out of scope for this port. Shipped at `hint`: this is a
35
+ readability/precision rule, not a defect-prevention one (this repo's
36
+ audit explicitly ranked it below the top 5 for that reason), and an
37
+ annotated `Record<K, V>` initializer is frequently deliberate (a
38
+ lookup table whose value type is genuinely uniform across keys).
39
+ Self-scan note: do NOT try to make pi-lens's own tree clean against
40
+ this rule; the adopting PR records the 2026-08-19 hit count instead.
41
+
42
+ 2026-08-20 (refs #1727, #1777): CONSIDERED for promotion to `error`,
43
+ KEPT at `hint`. AGENTS.md's severity policy admits a rule to `error`
44
+ only with a documented zero-false-positive audit, and `error` is the
45
+ only tier that maps to semantic `blocking`, so promoting it stops an
46
+ agent mid-turn on any file carrying a hit. Four-corpus census, ast-grep
47
+ CLI 0.45:
48
+
49
+ | corpus | hits |
50
+ |---|---:|
51
+ | pi-lens `clients/` | 90 |
52
+ | pi-lens `tests/` | 55 |
53
+ | pi core `packages/` | 74 (64 outside test paths) |
54
+ | opencode `packages/` | 193 (173) |
55
+ | oh-my-pi `packages/` | 828 (687) |
56
+
57
+ Verdict: no structural narrowing found. Every one of the 90 `clients/`
58
+ hits is a module-level lookup table whose value type genuinely IS
59
+ uniform (`LANGUAGE_TO_GRAMMAR`, `DELIVERY_SURFACES`, `EMOJI`,
60
+ `TREE_SITTER_EXT_TO_LANG`) — the exact deliberate use this note already
61
+ names. `Record<K, V>` on a lookup table and `Record<K, V>` on a value
62
+ whose keys were known and thrown away are the SAME syntax; the
63
+ difference is intent, which no relational constraint can read. Splitting
64
+ by `export const` at module scope versus a local `const` was probed and
65
+ rejected: it would encode "module-level tables are fine" as a rule of
66
+ the language, which it is not. Promotion needs a `satisfies` migration
67
+ of pi-lens's own tables, not a rule change.
68
+ rule:
69
+ pattern:
70
+ context: "const $NAME: Record<$K, $V> = { $$$PROPS };"
71
+ selector: variable_declarator