@herbertgao/pi-extensions 2026.8.6 → 2026.8.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (385) hide show
  1. package/README.md +8 -6
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +2 -2
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -2
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +19 -7
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +30 -9
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +320 -22
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +79 -17
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +27 -0
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +66 -17
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +41 -2
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +75 -6
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +7 -3
  14. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +64 -1
  15. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  16. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
  17. package/node_modules/@herbertgao/pi-subagents/README.md +30 -22
  18. package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +5 -5
  19. package/node_modules/@herbertgao/pi-subagents/package.json +7 -7
  20. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +7 -1
  21. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +48 -19
  22. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +17 -13
  23. package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +26 -2
  24. package/node_modules/@herbertgao/pi-subagents/src/index.ts +219 -40
  25. package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +101 -3
  26. package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +18 -4
  27. package/node_modules/@herbertgao/pi-subagents/src/settings.ts +99 -0
  28. package/node_modules/@herbertgao/pi-subagents/src/types.ts +22 -3
  29. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +51 -3
  30. package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +20 -2
  31. package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +21 -6
  32. package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
  33. package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +20 -0
  34. package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +5 -4
  35. package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +174 -100
  36. package/node_modules/@juicesharp/rpiv-ask-user-question/config.ts +25 -0
  37. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/configuration.md +13 -4
  38. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +5 -1
  39. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +10 -2
  40. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +10 -6
  41. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/tool-schema.md +11 -5
  42. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +5 -2
  43. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/zh.json +2 -2
  44. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +3 -2
  45. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +10 -0
  46. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +140 -97
  47. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +63 -28
  48. package/node_modules/@juicesharp/rpiv-ask-user-question/state/selectors/projections.ts +22 -15
  49. package/node_modules/@juicesharp/rpiv-ask-user-question/state/state-reducer.ts +11 -1
  50. package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
  51. package/node_modules/@juicesharp/rpiv-ask-user-question/tool/response-envelope.ts +11 -0
  52. package/node_modules/@juicesharp/rpiv-ask-user-question/tool/types.ts +11 -0
  53. package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/multi-select-view.ts +31 -17
  54. package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/preview/preview-block-renderer.ts +15 -6
  55. package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/wrapping-select.ts +15 -6
  56. package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +86 -38
  57. package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +76 -9
  58. package/node_modules/@narumitw/pi-btw/README.md +120 -111
  59. package/node_modules/@narumitw/pi-btw/dist/index.ts +2898 -0
  60. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +7 -0
  61. package/node_modules/@narumitw/pi-btw/package.json +10 -6
  62. package/node_modules/@narumitw/pi-btw/src/btw.ts +36 -40
  63. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +55 -10
  64. package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +390 -0
  65. package/node_modules/@narumitw/pi-btw/src/menu.ts +45 -2
  66. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
  67. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +44 -1856
  68. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
  69. package/node_modules/@pi-plugins/fast-mode/package.json +4 -6
  70. package/node_modules/pi-lens/CHANGELOG.md +999 -0
  71. package/node_modules/pi-lens/README.md +117 -3
  72. package/node_modules/pi-lens/config/ruff/core.toml +42 -0
  73. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +130 -27
  74. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +126 -13
  75. package/node_modules/pi-lens/dist/clients/agent-nudge.js +67 -11
  76. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +9 -3
  77. package/node_modules/pi-lens/dist/clients/atomic-write.js +9 -3
  78. package/node_modules/pi-lens/dist/clients/bash-file-access.js +381 -13
  79. package/node_modules/pi-lens/dist/clients/biome-client.js +61 -30
  80. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
  81. package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +129 -0
  82. package/node_modules/pi-lens/dist/clients/bootstrap.js +12 -1
  83. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +12 -3
  84. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +206 -0
  85. package/node_modules/pi-lens/dist/clients/cache-observability.js +353 -76
  86. package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
  87. package/node_modules/pi-lens/dist/clients/cascade-format.js +20 -1
  88. package/node_modules/pi-lens/dist/clients/cascade-types.js +9 -1
  89. package/node_modules/pi-lens/dist/clients/child-unref.js +54 -6
  90. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +76 -24
  91. package/node_modules/pi-lens/dist/clients/dead-code-client.js +123 -31
  92. package/node_modules/pi-lens/dist/clients/deadline-utils.js +8 -1
  93. package/node_modules/pi-lens/dist/clients/debug-handles.js +5 -0
  94. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +84 -14
  95. package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +155 -0
  96. package/node_modules/pi-lens/dist/clients/dependency-checker.js +25 -3
  97. package/node_modules/pi-lens/dist/clients/deps/pi-tui.js +8 -2
  98. package/node_modules/pi-lens/dist/clients/deps/typebox.js +8 -3
  99. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +147 -33
  100. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
  101. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +52 -2
  102. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +256 -88
  103. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +7 -4
  104. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +5 -0
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +234 -18
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +187 -19
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +6 -3
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +11 -9
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +398 -0
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +9 -6
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +11 -3
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +12 -7
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +18 -0
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +9 -7
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +8 -6
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +4 -0
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +16 -3
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +60 -53
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -2
  121. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +25 -2
  122. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +20 -5
  123. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +44 -11
  124. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +331 -55
  125. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +38 -5
  126. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +97 -19
  127. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +17 -8
  128. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +32 -4
  129. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +47 -3
  130. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +14 -4
  131. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +127 -28
  132. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +12 -7
  133. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +73 -12
  134. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +275 -13
  135. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +21 -6
  136. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +260 -27
  137. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +734 -64
  138. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +86 -11
  139. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +188 -0
  140. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +9 -0
  141. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +21 -10
  142. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -2
  143. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
  144. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
  145. package/node_modules/pi-lens/dist/clients/extension-log.js +22 -1
  146. package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
  147. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +316 -0
  148. package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
  149. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +3 -2
  150. package/node_modules/pi-lens/dist/clients/formatters.js +500 -115
  151. package/node_modules/pi-lens/dist/clients/generation-guard.js +216 -0
  152. package/node_modules/pi-lens/dist/clients/git-guard.js +31 -0
  153. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
  154. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +109 -9
  155. package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
  156. package/node_modules/pi-lens/dist/clients/host-ports.js +8 -0
  157. package/node_modules/pi-lens/dist/clients/installer/index.js +1114 -100
  158. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +58 -0
  159. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +715 -0
  160. package/node_modules/pi-lens/dist/clients/instance-reaper.js +643 -97
  161. package/node_modules/pi-lens/dist/clients/instance-registry.js +87 -17
  162. package/node_modules/pi-lens/dist/clients/jscpd-client.js +87 -8
  163. package/node_modules/pi-lens/dist/clients/knip-client.js +310 -10
  164. package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
  165. package/node_modules/pi-lens/dist/clients/language-profile.js +9 -2
  166. package/node_modules/pi-lens/dist/clients/latency-logger.js +440 -11
  167. package/node_modules/pi-lens/dist/clients/lazy-import.js +21 -0
  168. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -0
  169. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
  170. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +128 -8
  171. package/node_modules/pi-lens/dist/clients/lsp/client.js +1660 -164
  172. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +83 -1
  173. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
  174. package/node_modules/pi-lens/dist/clients/lsp/index.js +2423 -151
  175. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +215 -0
  176. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +146 -14
  177. package/node_modules/pi-lens/dist/clients/lsp/language.js +48 -4
  178. package/node_modules/pi-lens/dist/clients/lsp/server.js +277 -16
  179. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +22 -0
  180. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +43 -0
  181. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +79 -3
  182. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +43 -0
  183. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +422 -28
  184. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +30 -0
  185. package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +175 -0
  186. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +3 -2
  187. package/node_modules/pi-lens/dist/clients/mcp/session.js +10 -2
  188. package/node_modules/pi-lens/dist/clients/module-report.js +22 -1
  189. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +114 -23
  190. package/node_modules/pi-lens/dist/clients/opengrep-client.js +15 -1
  191. package/node_modules/pi-lens/dist/clients/package-manager.js +170 -14
  192. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +27 -0
  193. package/node_modules/pi-lens/dist/clients/path-utils.js +160 -0
  194. package/node_modules/pi-lens/dist/clients/pipeline.js +154 -33
  195. package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +37 -0
  196. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +17 -3
  197. package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +89 -22
  198. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +84 -14
  199. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +15 -3
  200. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +50 -2
  201. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +23 -9
  202. package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
  203. package/node_modules/pi-lens/dist/clients/project-report.js +62 -27
  204. package/node_modules/pi-lens/dist/clients/project-snapshot.js +299 -0
  205. package/node_modules/pi-lens/dist/clients/quiet-window-config.js +47 -0
  206. package/node_modules/pi-lens/dist/clients/quiet-window.js +11 -25
  207. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +8 -3
  208. package/node_modules/pi-lens/dist/clients/read-guard.js +253 -10
  209. package/node_modules/pi-lens/dist/clients/resource-sampler.js +49 -17
  210. package/node_modules/pi-lens/dist/clients/reverse-deps.js +50 -11
  211. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +194 -31
  212. package/node_modules/pi-lens/dist/clients/review-graph/query.js +52 -4
  213. package/node_modules/pi-lens/dist/clients/review-graph/revision-drift.js +21 -0
  214. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +6 -3
  215. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +96 -7
  216. package/node_modules/pi-lens/dist/clients/runtime-context.js +8 -1
  217. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +352 -45
  218. package/node_modules/pi-lens/dist/clients/runtime-session.js +373 -9
  219. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
  220. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +212 -79
  221. package/node_modules/pi-lens/dist/clients/runtime-turn.js +620 -67
  222. package/node_modules/pi-lens/dist/clients/safe-spawn.js +220 -7
  223. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +161 -0
  224. package/node_modules/pi-lens/dist/clients/search-read-registration.js +34 -6
  225. package/node_modules/pi-lens/dist/clients/security-scan-client.js +157 -24
  226. package/node_modules/pi-lens/dist/clients/session-event-guard.js +184 -0
  227. package/node_modules/pi-lens/dist/clients/sg-runner.js +116 -22
  228. package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
  229. package/node_modules/pi-lens/dist/clients/source-filter.js +6 -2
  230. package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
  231. package/node_modules/pi-lens/dist/clients/startup-scan.js +5 -2
  232. package/node_modules/pi-lens/dist/clients/startup-timing.js +19 -1
  233. package/node_modules/pi-lens/dist/clients/test-runner-client.js +151 -16
  234. package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
  235. package/node_modules/pi-lens/dist/clients/tool-policy.js +125 -20
  236. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +75 -1
  237. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +769 -64
  238. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +1 -0
  239. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +11 -0
  240. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +90 -0
  241. package/node_modules/pi-lens/dist/clients/trivy-client.js +19 -1
  242. package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
  243. package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
  244. package/node_modules/pi-lens/dist/index.js +61407 -48577
  245. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +476 -57
  246. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +132 -43
  247. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
  248. package/node_modules/pi-lens/docs/agent-guide.md +6 -1
  249. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +515 -506
  250. package/node_modules/pi-lens/docs/dispositions.md +21 -0
  251. package/node_modules/pi-lens/docs/features.md +19 -5
  252. package/node_modules/pi-lens/docs/globalconfig.md +3 -0
  253. package/node_modules/pi-lens/docs/language-coverage.md +71 -5
  254. package/node_modules/pi-lens/docs/mcp.md +2 -2
  255. package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
  256. package/node_modules/pi-lens/docs/settings.md +19 -1
  257. package/node_modules/pi-lens/docs/usage.md +1 -0
  258. package/node_modules/pi-lens/package.json +27 -10
  259. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-js-snapshot.yml +23 -0
  260. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-snapshot.yml +23 -0
  261. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/ts-void-zero-snapshot.yml +23 -0
  262. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-object-param-test.yml +16 -0
  263. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +15 -1
  264. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-compile-call-test.yml +29 -1
  265. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-dupe-class-members-test.yml +33 -0
  266. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-js-test.yml +7 -1
  267. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-test.yml +7 -1
  268. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-known-value-widening-test.yml +9 -0
  269. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml +216 -0
  270. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +2 -0
  271. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +2 -0
  272. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +2 -1
  273. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +2 -1
  274. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-return-value-in-generator-test.yml +12 -0
  275. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-runtime-typeof-test.yml +33 -0
  276. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-server-bind-wildcard-test.yml +9 -0
  277. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-shape-in-symbol-names-test.yml +13 -0
  278. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-js-test.yml +5 -1
  279. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-test.yml +5 -1
  280. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-parameters-test.yml +12 -0
  281. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-returns-test.yml +16 -0
  282. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-any-test.yml +10 -0
  283. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-unknown-test.yml +8 -0
  284. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/redundant-unsafe-function-test.yml +35 -0
  285. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/require-safety-comment-for-as-unknown-as-test.yml +177 -0
  286. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ts-void-zero-test.yml +1 -0
  287. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member-js.yml +13 -2
  288. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member.yml +13 -2
  289. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +2 -0
  290. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-object-param.yml +60 -0
  291. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +57 -12
  292. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-compile-call.yml +63 -5
  293. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-dupe-class-members.yml +52 -8
  294. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html-js.yml +27 -2
  295. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html.yml +27 -2
  296. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-known-value-widening.yml +71 -0
  297. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-non-null-assertion.yml +316 -0
  298. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +7 -0
  299. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +22 -2
  300. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +23 -2
  301. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +33 -5
  302. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +34 -8
  303. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-return-value-in-generator.yml +22 -5
  304. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-runtime-typeof.yml +121 -0
  305. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-server-bind-wildcard.yml +23 -7
  306. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-shape-in-symbol-names.yml +68 -0
  307. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +41 -2
  308. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code.yml +41 -2
  309. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +6 -1
  310. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-parameters.yml +67 -0
  311. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-returns.yml +106 -0
  312. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-any.yml +50 -0
  313. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-unknown.yml +56 -0
  314. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +2 -0
  315. package/node_modules/pi-lens/rules/ast-grep-rules/rules/redundant-unsafe-function.yml +32 -0
  316. package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml +184 -0
  317. package/node_modules/pi-lens/rules/ast-grep-rules/rules/ts-void-zero.yml +5 -0
  318. package/node_modules/pi-lens/rules/ast-grep-rules/self-scan-baseline.json +5 -0
  319. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +53 -1
  320. package/node_modules/pi-lens/scripts/download-grammars.js +25 -0
  321. package/node_modules/pi-lens/scripts/grammars.lock.json +9 -0
  322. package/node_modules/pi-lens/scripts/install-selftest.mjs +99 -11
  323. package/node_modules/pi-lens/scripts/lib/host-provided-deps.mjs +75 -0
  324. package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +285 -0
  325. package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +233 -0
  326. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +2 -0
  327. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +80 -3
  328. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +41 -0
  329. package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
  330. package/node_modules/pi-mcp-adapter/CHANGELOG.md +36 -0
  331. package/node_modules/pi-mcp-adapter/README.md +47 -5
  332. package/node_modules/pi-mcp-adapter/cli.js +163 -1
  333. package/node_modules/pi-mcp-adapter/commands.ts +128 -22
  334. package/node_modules/pi-mcp-adapter/config.ts +25 -7
  335. package/node_modules/pi-mcp-adapter/direct-tools.ts +5 -4
  336. package/node_modules/pi-mcp-adapter/index.ts +219 -32
  337. package/node_modules/pi-mcp-adapter/init.ts +36 -4
  338. package/node_modules/pi-mcp-adapter/lifecycle.ts +315 -24
  339. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +39 -6
  340. package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +387 -0
  341. package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +27 -3
  342. package/node_modules/pi-mcp-adapter/mcp-code.ts +4 -0
  343. package/node_modules/pi-mcp-adapter/mcp-panel.ts +42 -13
  344. package/node_modules/pi-mcp-adapter/metadata-cache.ts +32 -21
  345. package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
  346. package/node_modules/pi-mcp-adapter/package.json +3 -1
  347. package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
  348. package/node_modules/pi-mcp-adapter/request-headers-command.ts +31 -37
  349. package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
  350. package/node_modules/pi-mcp-adapter/server-manager.ts +140 -2
  351. package/node_modules/pi-mcp-adapter/session-recovery.ts +7 -0
  352. package/node_modules/pi-mcp-adapter/tool-approval.ts +15 -2
  353. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
  354. package/node_modules/pi-mcp-adapter/types.ts +2 -0
  355. package/node_modules/pi-mcp-adapter/ui-server.ts +18 -16
  356. package/node_modules/pi-mcp-adapter/utils.ts +70 -0
  357. package/node_modules/pi-web-access/CHANGELOG.md +37 -0
  358. package/node_modules/pi-web-access/README.md +32 -13
  359. package/node_modules/pi-web-access/anysearch.ts +4 -2
  360. package/node_modules/pi-web-access/brave.ts +16 -4
  361. package/node_modules/pi-web-access/chrome-cookies.ts +86 -15
  362. package/node_modules/pi-web-access/curator-page.ts +6 -3
  363. package/node_modules/pi-web-access/curator-server.ts +4 -1
  364. package/node_modules/pi-web-access/data-uri-sanitize.ts +406 -0
  365. package/node_modules/pi-web-access/exa.ts +18 -7
  366. package/node_modules/pi-web-access/extract.ts +40 -5
  367. package/node_modules/pi-web-access/firecrawl.ts +18 -2
  368. package/node_modules/pi-web-access/gemini-search.ts +16 -4
  369. package/node_modules/pi-web-access/github-extract.ts +65 -36
  370. package/node_modules/pi-web-access/index.ts +60 -61
  371. package/node_modules/pi-web-access/openai-search.ts +17 -6
  372. package/node_modules/pi-web-access/package.json +1 -1
  373. package/node_modules/pi-web-access/page-query.ts +4 -2
  374. package/node_modules/pi-web-access/parallel-mcp.ts +249 -0
  375. package/node_modules/pi-web-access/parallel.ts +2 -2
  376. package/node_modules/pi-web-access/pdf-extract.ts +18 -5
  377. package/node_modules/pi-web-access/query-rewrite.ts +51 -0
  378. package/node_modules/pi-web-access/serper.ts +211 -0
  379. package/node_modules/pi-web-access/ssrf-protection.ts +12 -2
  380. package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
  381. package/node_modules/pi-web-access/summary-review.ts +44 -22
  382. package/node_modules/pi-web-access/tavily.ts +16 -4
  383. package/node_modules/pi-web-access/utils.ts +87 -0
  384. package/node_modules/pi-web-access/valyu.ts +199 -0
  385. package/package.json +14 -14
@@ -0,0 +1,177 @@
1
+ id: require-safety-comment-for-as-unknown-as
2
+ valid:
3
+ - |
4
+ // SAFETY: checked above
5
+ const a = x as unknown as Foo;
6
+ - |
7
+ const b = /* SAFETY: inline */ x as unknown as Foo;
8
+ - |
9
+ // SAFETY: arg is validated upstream
10
+ foo(x as unknown as Foo);
11
+ # 2026-08-20 (#1727/#1777): this rule now owns the `as unknown as` shape
12
+ # alone, so a single concrete `as` and a concrete CHAIN are both out of scope
13
+ # here (the chain belongs to no-chained-type-assertions.yml). Widening the
14
+ # pattern back to any assertion reds both.
15
+ - 'const c = x as Foo;'
16
+ - 'const d = x as A as B;'
17
+ # #1847: the `inside:` kind list omitted `export_statement`, so a
18
+ # SAFETY: comment above an EXPORTED cast could not satisfy the valve.
19
+ # Dropping `export_statement` from the rule's kind list reds this case.
20
+ - |
21
+ // SAFETY: node exposes this at runtime, absent from @types/node
22
+ export const b = (globalThis as unknown as { z: number }).z;
23
+ # #1847: same gap for a class-field cast — the kind list omitted
24
+ # `public_field_definition`. Dropping it from the rule's kind list
25
+ # reds this case.
26
+ - |
27
+ class Foo {
28
+ // SAFETY: server always sends this field at runtime
29
+ bar: unknown = (globalThis as unknown as { z: number }).z;
30
+ }
31
+ # #1852 review (F1): same gap for an enum member's initializer cast —
32
+ # the kind list omitted `enum_assignment`. Dropping it from the
33
+ # rule's kind list reds this case. Covers plain, `const`, and
34
+ # `export` enum alike — `enum_assignment` is the member node itself,
35
+ # unaffected by keywords on the enclosing `enum_declaration`.
36
+ # (`declare enum` members have no initializer expression to cast, so
37
+ # there is nothing to probe for that flavor.)
38
+ - |
39
+ enum Direction {
40
+ // SAFETY: node exposes this at runtime, absent from @types/node
41
+ Up = (globalThis as unknown as { z: number }).z,
42
+ }
43
+ - |
44
+ const enum Direction {
45
+ // SAFETY: node exposes this at runtime, absent from @types/node
46
+ Up = (globalThis as unknown as { z: number }).z,
47
+ }
48
+ - |
49
+ export enum Direction {
50
+ // SAFETY: node exposes this at runtime, absent from @types/number
51
+ Up = (globalThis as unknown as { z: number }).z,
52
+ }
53
+ # #1852 review over-suppression probe: two casts inside ONE exported
54
+ # declaration under a single SAFETY: comment. This is pre-existing
55
+ # behavior, not new — the same one-comment-covers-the-whole-statement
56
+ # trade already applied to `lexical_declaration`/`variable_declaration`
57
+ # before #1847 (verified: an unexported `const pair = {a: x as unknown
58
+ # as Foo, b: y as unknown as Foo}` under one SAFETY: comment was
59
+ # already 0 findings on master). The "Scope and known gap" note above
60
+ # states the valve is statement-scoped, not cast-scoped, by design:
61
+ # "a comment is accepted if it directly precedes... the assertion's
62
+ # containing... statement." `export_statement` inherits that same
63
+ # trade; it does not introduce a new one. Locked in here so a future
64
+ # narrowing of the scope is a deliberate choice, not an accident.
65
+ - |
66
+ // SAFETY: both fields document the same upstream payload shape
67
+ export const pair = { a: x as unknown as Foo, b: y as unknown as Foo };
68
+ # #1870: tree-sitter-typescript calls an object-literal member a `pair`.
69
+ # A comment directly above that pair is the natural local anchor.
70
+ - |
71
+ const config = {
72
+ // SAFETY: input is validated by the config loader
73
+ value: input as unknown as string,
74
+ };
75
+ - |
76
+ configure({
77
+ // SAFETY: input is validated by the config loader
78
+ value: input as unknown as string,
79
+ });
80
+ # Direct comments immediately above casts in array elements and call
81
+ # arguments are supported by the direct-cast arm.
82
+ - |
83
+ const values = [
84
+ // SAFETY: input is validated by the config loader
85
+ input as unknown as string,
86
+ ];
87
+ - |
88
+ configure(
89
+ // SAFETY: input is validated by the config loader
90
+ input as unknown as string,
91
+ );
92
+ invalid:
93
+ - "const a = x as unknown as Foo;"
94
+ - |
95
+ const b = x as unknown as Foo; // no safety note
96
+ - |
97
+ // some other comment
98
+ const c = x as unknown as Foo;
99
+ # The comment must actually claim safety. A comment mentioning the word in
100
+ # prose without the `SAFETY:` marker does not clear it — deleting the
101
+ # `SAFETY\s*:` regex from the rule reds this case.
102
+ - |
103
+ // this cast is safe, trust me
104
+ const d = x as unknown as Foo;
105
+ # #1834: the `follows: {stopBy: end}` scan is unbounded — it must not walk
106
+ # past the contiguous comment block into an EARLIER statement's SAFETY:
107
+ # comment. A stray SAFETY: comment anywhere earlier in the same block must
108
+ # not exempt a later, undocumented cast.
109
+ - |
110
+ function f(x: unknown, y: unknown) {
111
+ // SAFETY: this comment documents a DIFFERENT assertion below.
112
+ const a = (y as unknown as string).length;
113
+
114
+ const b = (x as unknown as string).length;
115
+ return a + b;
116
+ }
117
+ # SAFETY: on cast A must not bleed to cast B directly below it, even with
118
+ # no other statement in between.
119
+ - |
120
+ // SAFETY: documents castA only
121
+ const castA = a as unknown as Foo;
122
+ const castB = b as unknown as Foo;
123
+ # #1847: an exported cast with no SAFETY: comment must still flag —
124
+ # adding `export_statement` to the valve must not turn it into a
125
+ # blanket exemption for every exported cast.
126
+ - "export const b = (globalThis as unknown as { z: number }).z;"
127
+ # #1847: an undocumented class-field cast must still flag — adding
128
+ # `public_field_definition` to the valve must not exempt every field
129
+ # cast regardless of a SAFETY: comment.
130
+ - |
131
+ class Foo {
132
+ bar: unknown = (globalThis as unknown as { z: number }).z;
133
+ }
134
+ # #1852 review (F1): an undocumented enum-member cast must still flag
135
+ # — adding `enum_assignment` to the valve must not exempt every enum
136
+ # member cast regardless of a SAFETY: comment.
137
+ - |
138
+ enum Direction {
139
+ Up = (globalThis as unknown as { z: number }).z,
140
+ }
141
+ # #1852 review over-suppression probe: a SAFETY: comment separated
142
+ # from the cast by an unrelated statement must NOT suppress. This is
143
+ # already enforced by #1834's `stopBy: {not: {kind: comment}}` bound
144
+ # (the comment is no longer the statement's immediate preceding
145
+ # sibling once another statement sits between them), but it had no
146
+ # dedicated minimal fixture — the existing #1834 cases both pair the
147
+ # comment with a DIFFERENT documented cast, not a bare intervening
148
+ # statement.
149
+ - |
150
+ // SAFETY: documents nothing below — an unrelated call sits between
151
+ doSomethingUnrelated();
152
+ const b = x as unknown as Foo;
153
+ # A comment on an unrelated sibling pair must not reach a later pair.
154
+ - |
155
+ const config = {
156
+ unrelated: 1,
157
+ // SAFETY: this documents a different property
158
+ other: 2,
159
+ target: input as unknown as string,
160
+ };
161
+ # An outer pair comment must not cross into a nested pair.
162
+ - |
163
+ const config = {
164
+ // SAFETY: only the parent property is validated
165
+ parent: {
166
+ nestedTarget: value as unknown as string,
167
+ },
168
+ };
169
+ # A nested pair comment must not travel outward to a parent cast.
170
+ - |
171
+ const config = {
172
+ parent: value as unknown as string,
173
+ // SAFETY: only the nested property is validated
174
+ nested: {
175
+ child: value as unknown as string,
176
+ },
177
+ };
@@ -3,6 +3,7 @@ valid:
3
3
  - 'undefined'
4
4
  - 'void x'
5
5
  - 'void 1'
6
+ - 'function probe(undefined) { return undefined; }'
6
7
  invalid:
7
8
  - 'void 0'
8
9
  - 'const x = void 0'
@@ -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