@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
@@ -6,9 +6,325 @@ note: |
6
6
  The ! operator bypasses TypeScript's null checking which can lead to
7
7
  runtime errors. Use optional chaining (?.), nullish coalescing (??),
8
8
  or explicit null checks instead.
9
+
10
+ #1777 census and decision: the original false-positive census (49
11
+ hits across pi-lens, nestjs/nest, and colinhacks/zod) found 88% of
12
+ hits were the narrow-after-check idiom TypeScript can't itself
13
+ verify. Two of those idiom shapes are common enough, and structural
14
+ enough, to exclude with an ast-grep relational constraint instead of
15
+ demoting the whole rule — so the rule stays at `warning` and gets
16
+ narrower instead:
17
+
18
+ 1. `$M.get($K)!` when the enclosing function ALSO contains a call to
19
+ `$M.has($K)` — same receiver, same key (ast-grep enforces the
20
+ metavariable binding, so a `.has()` check on a DIFFERENT key or a
21
+ DIFFERENT map does not suppress the finding).
22
+ 2. `$A.pop()!` / `$A.shift()!` inside a `while`/`for`/`if` whose
23
+ condition references `$A.length` — again same-array-binding, so a
24
+ length check on a different array does not suppress it.
25
+
26
+ Both exclusions are scoped to the nearest enclosing function via a
27
+ `stopBy` BOUNDARY rule, not the whole file.
28
+
29
+ Review round 1 found two proven defects in the first version of this
30
+ narrowing, both fixed here:
31
+
32
+ - **F1 (high):** the original `stopBy: end` on the `inside` relation
33
+ is a search-DEPTH flag, not a stop condition — it walked ancestors
34
+ all the way to the file root. The `any:` kind list only chose which
35
+ ancestor could SATISFY the match; it did not stop the walk. Result:
36
+ a `.has()`/`.length` guard in an OUTER function suppressed a
37
+ closure's `!` inside an INNER function, and closures are common in
38
+ this codebase. Fixed by giving `stopBy` its own RULE (the same
39
+ function-kind `any:` list) so the ancestor walk halts at the
40
+ nearest enclosing function no matter what — it can find a
41
+ satisfying guard there or fail, but it can never look further out.
42
+ - **F2 (medium):** the `has: pattern: $M.has($K)` search is blind to
43
+ branch polarity — `if (!m.has(k)) { return m.get(k)!; }` (a REAL
44
+ bug: the key is proven ABSENT on that branch) was suppressed
45
+ exactly like `if (m.has(k)) { return m.get(k)!; }` (safe). ast-grep
46
+ has no dataflow model to tell "guards the branch I'm in" from
47
+ "guards the branch I'm NOT in," so the fix is a blunter, safer
48
+ instrument: `not: inside: { kind: unary_expression }` on the `has`
49
+ pattern removes ANY negated `.has()` call from counting as a guard,
50
+ full stop. This closes the real-bug shape but also cost one
51
+ previously-correct suppression: `if (!m.has(k)) return; ...
52
+ m.get(k)!` (an early-return guard clause, genuinely safe) now flags
53
+ again, because ast-grep can't distinguish it from the bug shape
54
+ that shares its `!m.has(k)` syntax. Accepted: the two shapes are
55
+ structurally identical to a syntax matcher, and re-flagging safe
56
+ code is cheaper than missing the bug shape. Both directions are
57
+ fixtured in `rule-tests/no-non-null-assertion-test.yml`.
58
+
59
+ Approximation caveat: even after F1/F2, ast-grep matches
60
+ structurally, not semantically. It cannot verify the guard genuinely
61
+ DOMINATES the use (no intervening mutation of `$M`/`$A` or
62
+ reassignment of the narrowed variable) or that the key is the same
63
+ value at runtime versus merely the same source text. It also can't
64
+ read branch polarity beyond the single `!` case F2 special-cases —
65
+ `if (x.has(k) === false)` or `if (x.has(k) ? false : true)` would
66
+ still slip past undetected. The suppression is deliberately biased
67
+ toward false negatives — leaving a real risk unflagged — over false
68
+ positives, which is the correct default bias for a lint the census
69
+ showed fires mostly on legitimate code; F2 is the one place that
70
+ bias is deliberately overridden, because a same-branch bug is worse
71
+ than an unnecessary warning on safe code.
72
+
73
+ Re-census on the F1/F2/F5-fixed rule, four corpora, hit count before
74
+ (no exclusions) → after:
75
+ - pi-lens (this repo, `clients/` `tools/` `index.ts`): 43 → 36 (7
76
+ suppressed, -16%). All 7 verified by hand: `.get()!`-after-`.has()`
77
+ guard clauses in `tree-sitter-client.ts` (`loadLanguage`,
78
+ `getParser`) and `review-graph/builder.ts`, plus
79
+ `pop()!`/`shift()!` inside `while (x.length > 0)` loops in
80
+ `call-graph.ts`, `pipeline.ts`, `tree-sitter-client.ts`
81
+ (`bindingNames`), and `review-graph/workspace-modules.ts`.
82
+ `project-report.ts:531`'s `indices.get(w)!` was an 8th hit
83
+ suppressed by the PRE-F2 rule — its only `indices.has(w)` in scope
84
+ is `if (!indices.has(w))`, i.e. exactly the F2 negation blind spot,
85
+ and it happened to land on genuinely safe code (the `else` branch
86
+ where `w` having been visited already implies `indices` has an
87
+ entry) purely by accident, not because the rule proved anything.
88
+ The F2 fix removes that accidental suppression along with the real
89
+ ones, so it correctly flags again post-fix.
90
+ - inspiration-pi: 674 → 655 (19 suppressed, -2.8%).
91
+ - inspiration-opencode: 1067 → 1060 (7 suppressed, -0.7%).
92
+ - inspiration-oh-my-pi: 3569 → 3544 (25 suppressed, -0.7%).
93
+
94
+ Honest read of the residual: pi-lens's own residual (36) is NOT
95
+ dominated by the genuine cross-boundary-risk class
96
+ (`dart.getCommand(cwd)!` right after `dart.isAvailableAsync(cwd)`,
97
+ and similar) — that class accounts for roughly 7 of the 36. The rest
98
+ (~29) are still legitimate-idiom shaped, just not expressible by
99
+ these two structural constraints: a property re-asserted after its
100
+ parent was checked (`r.enclosingSymbol!.name` after `.filter((r) =>
101
+ r.enclosingSymbol)` in `read-guard.ts`), a boolean flag standing in
102
+ for a narrowed variable, a value narrowed by a ternary rather than
103
+ `.has()` (`index.forward!` in `word-index.ts`), and a
104
+ module-singleton pattern (`format-service.ts`'s
105
+ `globalFormatService!`). Tracked as #1818.
106
+
107
+ 2026-08-20 (#1818 round 2): two of the four named unexpressed shapes
108
+ DO have a cheap structural signature after all, and are now
109
+ excluded:
110
+
111
+ 1. **Ternary-narrow**: `$TO.$TP ? ...$TO.$TP!... : ...` — the
112
+ `$TO.$TP!` sits under the `consequence` field of a ternary whose
113
+ `condition` is the identical `$TO.$TP` truthy check, even when
114
+ the assertion is nested inside a closure passed to `.map()` (the
115
+ `word-index.ts` and `lsp/index.ts` cases). `field: consequence`
116
+ on the `inside` relation ties the MATCHED NODE ITSELF to the
117
+ consequence branch, so a same-shaped assertion sitting in the
118
+ `alternative` branch (a real narrowing bug: falsy there) is left
119
+ unaffected, and so is one nested inside an unrelated INNER
120
+ ternary whose own condition does not match (see the review-round-1
121
+ fixtures below).
122
+ 2. **Filter-then-map re-assert**: `$OBJ.filter(($F) => $F.$PROP)
123
+ .map(($M) => ...$M.$PROP!...)` — `$M` is the SAME metavariable as
124
+ both the map callback's own parameter and the asserted receiver,
125
+ so the exclusion fires only when the narrowed value is literally
126
+ that parameter, not an unrelated same-named variable elsewhere
127
+ (the `read-guard.ts` case, 2 sites × 3 properties each).
128
+
129
+ Both follow the same discipline as the `#1777` exclusions above:
130
+ `stopBy` is a RULE (nearest ternary, never `end`) on the ternary
131
+ exclusion, and the suppression is guarded by same-metavariable
132
+ binding, not mere presence of the guard shape anywhere in scope.
133
+ Fixtured (suppressed shape, mismatched-binding lookalike, and — for
134
+ the ternary — the opposite-branch and nested-ternary bug lookalikes)
135
+ in `rule-tests/no-non-null-assertion-test.yml`.
136
+
137
+ 2026-08-20, review round 1 (four findings, all fixed in this
138
+ revision):
139
+
140
+ - **N1 (medium):** the original ternary exclusion used `has: field:
141
+ consequence` — an EXISTENCE check on the ternary as a whole, not
142
+ an identity check on the matched node. `o.y ? o.y!.length :
143
+ o.y!.length` (the identical assertion in BOTH branches) made the
144
+ alternative-branch instance inherit the suppression, because the
145
+ consequence branch's matching text satisfied the existence check
146
+ regardless of which instance was actually being evaluated. Fixed
147
+ by switching to `field: consequence` directly on the `inside`
148
+ relation, which IS an identity check on the matched node's actual
149
+ position. Fixtured as an `invalid` case (both-branches-same-shape
150
+ must still flag on the alternative instance).
151
+ - **N2 (medium):** two mutation-proof gaps. (a) The ternary
152
+ `stopBy: kind: ternary_expression` was provably load-bearing but
153
+ had no fixture proving it: `o.y ? (flag ? 1 : o.y!.length) : 0` —
154
+ the assertion's NEAREST ternary is the inner one, whose own
155
+ condition (`flag`) does not match `$TO.$TP`, so it must still
156
+ flag; weakening `stopBy` to `end` lets the search escalate past
157
+ the inner ternary to the outer one (whose condition DOES match)
158
+ and wrongly suppresses it. (b) The filter-map `$M` binding had no
159
+ fixture proving an unrelated variable inside the SAME callback
160
+ still flags: `rs.filter((r) => r.sym).map((m) => stray.sym!.name)`
161
+ — decoupling `$M` from the map callback's own parameter (e.g. to
162
+ an unconstrained `$ANY`) wrongly suppresses `stray.sym!` too, since
163
+ the filter-map SHAPE would match even though the asserted value is
164
+ not the map's own parameter. Both fixtured as `invalid` cases.
165
+ - **N3 (low):** the filter-map exclusion's intermediate "nearest
166
+ enclosing arrow_function" `inside`/`stopBy` layer could not be
167
+ shown load-bearing by any constructed fixture — removed; see the
168
+ exclusion's own comment below for why it was redundant.
169
+ - **N4 (low):** this rule's `note:` is unaffected; the mismatched
170
+ before/after scope pairing N4 named lives in
171
+ `no-unknown-returns.yml`'s note, fixed there.
172
+
173
+ Re-census, pi-lens `clients/` `tools/` `index.ts`: 36 → 27 (9
174
+ suppressed). All 9 verified by hand: 1 in `word-index.ts`, 2 in
175
+ `lsp/index.ts` (an `AbortSignal`-narrowed-by-truthy-ternary variant
176
+ of the same idiom), and the 6 `read-guard.ts` sites already named
177
+ above. Four-corpus census (F1/F2-fixed rule → round-2 rule; these
178
+ corpora move independently of pi-lens's own history and the
179
+ upstream trees have drifted since the #1777 note, so treat this as
180
+ a fresh baseline rather than a delta against the numbers above):
181
+ inspiration-pi 659 → 657, inspiration-opencode 1078 → 1071,
182
+ inspiration-oh-my-pi 3548 → 3543.
183
+
184
+ The two remaining named shapes — a boolean flag standing in for a
185
+ narrowed variable, and a property re-asserted after its PARENT
186
+ (rather than itself) was checked — were re-probed and are still not
187
+ expressible: both require proving that an assignment or a `.filter`
188
+ predicate on a DIFFERENT expression than the one being asserted
189
+ actually dominates the assertion, which needs a dataflow model, not
190
+ a syntax-tree relation. The module-singleton case
191
+ (`format-service.ts`'s `globalFormatService!`) was also re-probed: a
192
+ direct `if (!$X) { $X = ...; }` guard immediately before `return
193
+ $X!` would be structurally expressible the same way as the
194
+ `#1777` `.has()` exclusion, but `format-service.ts`'s actual
195
+ instance routes the check through an intermediate boolean
196
+ (`shouldCreateNew`) rather than testing `$X` directly, which is the
197
+ boolean-flag shape, not a new one — so no rule was added for it
198
+ rather than risk a suppression that can't tell "just assigned" from
199
+ "assigned in an unrelated earlier branch." The residual (27, was 36)
200
+ is smaller but still idiom-dominated: pending the maintainer's
201
+ standing decision, severity stays `warning`.
9
202
  rule:
10
203
  pattern: $X!
11
204
  not:
12
205
  any:
13
206
  - kind: function_type
14
207
  - kind: method_signature
208
+ - all:
209
+ # #1818 round 2 (review round 1 N1 fix): ternary-narrow.
210
+ # `$TO.$TP ? ...$TO.$TP!... : ...` — the consequence branch is
211
+ # reached only when `$TO.$TP` is truthy, but a closure nested in
212
+ # that branch (an arrow passed to `.map()`, etc.) loses TS's own
213
+ # narrowing across the function boundary. `stopBy` bounds the
214
+ # walk to the NEAREST enclosing ternary (never an outer one —
215
+ # see the round-1-N2a fixture below for why that matters).
216
+ # `field: consequence` on the `inside` relation is an IDENTITY
217
+ # check on the matched node's own position in that ternary's
218
+ # subtree — it ties OUR SPECIFIC node to the consequence branch,
219
+ # not merely to "a same-shaped node exists somewhere in the
220
+ # consequence." The original version used `has: field:
221
+ # consequence` instead, which is an EXISTENCE check on the
222
+ # ternary as a whole: `o.y ? o.y!.length : o.y!.length` (the
223
+ # same assertion repeated in BOTH branches) made the
224
+ # alternative-branch instance — a real narrowing bug, since
225
+ # `o.y` is falsy on that branch — inherit the suppression,
226
+ # because the consequence branch's identical text satisfied the
227
+ # existence check for both instances. `field: consequence`
228
+ # closes that gap: it only matches a node that IS reachable via
229
+ # the consequence field specifically, so the alternative-branch
230
+ # instance is left flagged. Named `$TO`/`$TP`, not `$X`/`$P`:
231
+ # the outer `pattern: $X!` already binds `$X` to the WHOLE
232
+ # asserted expression (e.g. `index.forward`), so reusing `$X`
233
+ # here would force it to match `index.forward.$P!` — a
234
+ # different shape — instead of decomposing `index.forward` into
235
+ # object+property.
236
+ - pattern: $TO.$TP!
237
+ - inside:
238
+ stopBy:
239
+ kind: ternary_expression
240
+ kind: ternary_expression
241
+ field: consequence
242
+ has:
243
+ field: condition
244
+ pattern: $TO.$TP
245
+ - all:
246
+ # #1818 round 2 (review round 1 N3: simplified): a property
247
+ # re-asserted after a `.filter()` on that SAME property,
248
+ # immediately chained into `.map()` — TS's narrowing from
249
+ # `.filter((r) => r.$PROP)` does not carry into the separate
250
+ # `.map()` callback closure. `$M` (the map callback's
251
+ # parameter) is the SAME metavariable as the assertion's
252
+ # receiver, so the exclusion only fires when the asserted value
253
+ # is literally the map callback's own parameter, not an
254
+ # unrelated same-named variable (fixtured: `stray.sym!` inside
255
+ # a `.filter(...).map((m) => ...)` callback must still flag,
256
+ # because `$M` can only bind to "m", never to "stray"); `$PROP`
257
+ # must match on both the filter predicate and the assertion.
258
+ # An earlier version of this exclusion added an intermediate
259
+ # "nearest enclosing arrow_function" boundary before this
260
+ # `inside`; review round 1 could not construct a case where
261
+ # that boundary changed the result — the outer `stopBy: end`
262
+ # below already walks to the SAME call_expression regardless of
263
+ # which arrow_function ancestor the search starts from, because
264
+ # the pattern match on that call_expression is a self-contained
265
+ # structural check independent of the path taken to reach it —
266
+ # so the intermediate layer was removed rather than kept as
267
+ # decoration that looked load-bearing but wasn't.
268
+ - pattern: $M.$PROP!
269
+ - inside:
270
+ stopBy: end
271
+ kind: call_expression
272
+ pattern: $OBJ.filter(($F) => $F.$PROP).map(($M) => $BODY)
273
+ - all:
274
+ - pattern: $M.get($K)!
275
+ - inside:
276
+ # stopBy is a boundary RULE, not a search-depth flag: the
277
+ # ancestor walk stops at the nearest node matching this
278
+ # rule, so it can never escalate past the nearest
279
+ # enclosing function into an outer scope (#1777 F1 fix).
280
+ stopBy:
281
+ any:
282
+ - kind: function_declaration
283
+ - kind: method_definition
284
+ - kind: arrow_function
285
+ - kind: function_expression
286
+ any:
287
+ - kind: function_declaration
288
+ - kind: method_definition
289
+ - kind: arrow_function
290
+ - kind: function_expression
291
+ has:
292
+ stopBy: end
293
+ pattern: $M.has($K)
294
+ # Exclude a negated has() check from counting as a guard
295
+ # (#1777 F2 fix): ast-grep can't read branch polarity, so
296
+ # this can't tell a `if (!m.has(k)) return;` early-return
297
+ # guard clause (safe) from `if (!m.has(k)) { ...
298
+ # m.get(k)! }` (a real bug — the key is proven ABSENT in
299
+ # that branch). Refusing to treat ANY negated has() as a
300
+ # guard is the only structural signal available; it
301
+ # trades a few now-unflagged-turned-flagged early-return
302
+ # guard clauses for closing the real-bug shape. See the
303
+ # rule note for the accepted regression.
304
+ not:
305
+ inside:
306
+ kind: unary_expression
307
+ - all:
308
+ - any:
309
+ - pattern: $A.pop()!
310
+ - pattern: $A.shift()!
311
+ - inside:
312
+ # Same stopBy boundary fix as the get/has exclusion above.
313
+ stopBy:
314
+ any:
315
+ - kind: function_declaration
316
+ - kind: method_definition
317
+ - kind: arrow_function
318
+ - kind: function_expression
319
+ # No function kinds here (#1777 F5): a function node has no
320
+ # `condition` field, so it could never satisfy the `has`
321
+ # check below — the stopBy boundary above already keeps
322
+ # the walk from escalating past the function regardless.
323
+ any:
324
+ - kind: while_statement
325
+ - kind: for_statement
326
+ - kind: if_statement
327
+ has:
328
+ field: condition
329
+ stopBy: end
330
+ pattern: $A.length
@@ -1,6 +1,8 @@
1
1
  id: no-raw-json-store-write
2
2
  language: TypeScript
3
3
  severity: warning
4
+ metadata:
5
+ category: pi-lens-self-scan
4
6
  message: "Use the atomic write seam for JSON stores instead of writeFileSync"
5
7
  note: |
6
8
  JSON-backed durable state must be committed through clients/durable-store.ts
@@ -8,10 +10,15 @@ note: |
8
10
  clients/atomic-write.ts. This rule covers the direct
9
11
  writeFileSync(path, JSON.stringify(data)) shape. Build scripts and the
10
12
  installer's wx lock writes are intentionally outside this rule's scope.
13
+ Test fixtures that write throwaway JSON files for a test's own setup are
14
+ not durable production state either (#1718 self-scan triage: 200 hits,
15
+ all in tests/, none carrying read-modify-write isolation requirements) --
16
+ excluded the same way build scripts already are.
11
17
  ignores:
12
18
  - "**/clients/atomic-write.ts"
13
19
  - "**/clients/installer/index.ts"
14
20
  - "**/scripts/**"
21
+ - "**/tests/**"
15
22
  rule:
16
23
  any:
17
24
  - pattern: writeFileSync($PATH, JSON.stringify($$$ARGS))
@@ -1,9 +1,29 @@
1
1
  id: no-reflect-apply-js
2
2
  language: JavaScript
3
- severity: warning
3
+ severity: error
4
4
  message: "Reflect.apply() — use a typed call (fn.apply(...) or fn(...args)) instead"
5
+ metadata:
6
+ category: pi-lens-self-scan
5
7
  note: |
6
8
  Reflect.apply reaches for reflection where a typed call already works.
7
9
  Prefer Function#apply or a direct call with spread arguments.
10
+
11
+ This rule has no autofix because a function can have a shadowed own `.apply`
12
+ property. The semantically exact `Function.prototype.apply.call` rewrite is
13
+ worse than the diagnostic.
14
+
15
+ 2026-08-20 (refs #1856): PROMOTED from `warning` to `error` with the
16
+ same structural Proxy apply-trap carve-out as the TypeScript twin.
8
17
  rule:
9
- pattern: Reflect.apply($$$ARGS)
18
+ all:
19
+ - pattern: Reflect.apply($$$ARGS)
20
+ - not:
21
+ inside:
22
+ kind: method_definition
23
+ stopBy: end
24
+ has:
25
+ field: name
26
+ regex: "^apply$"
27
+ inside:
28
+ pattern: new Proxy($TARGET, $HANDLER)
29
+ stopBy: end
@@ -1,9 +1,30 @@
1
1
  id: no-reflect-apply
2
2
  language: TypeScript
3
- severity: warning
3
+ severity: error
4
4
  message: "Reflect.apply() — use a typed call (fn.apply(...) or fn(...args)) instead"
5
+ metadata:
6
+ category: pi-lens-self-scan
5
7
  note: |
6
8
  Reflect.apply reaches for reflection where a typed call already works.
7
9
  Prefer Function#apply or a direct call with spread arguments.
10
+
11
+ This rule has no autofix because a function can have a shadowed own `.apply`
12
+ property. The semantically exact `Function.prototype.apply.call` rewrite is
13
+ worse than the diagnostic.
14
+
15
+ 2026-08-20 (refs #1856): PROMOTED from `warning` to `error`. Standard
16
+ forwarding inside an inline `new Proxy` apply trap is excluded
17
+ structurally; a method merely named `apply` elsewhere remains in scope.
8
18
  rule:
9
- pattern: Reflect.apply($$$ARGS)
19
+ all:
20
+ - pattern: Reflect.apply($$$ARGS)
21
+ - not:
22
+ inside:
23
+ kind: method_definition
24
+ stopBy: end
25
+ has:
26
+ field: name
27
+ regex: "^apply$"
28
+ inside:
29
+ pattern: new Proxy($TARGET, $HANDLER)
30
+ stopBy: end
@@ -1,13 +1,41 @@
1
1
  id: no-reflect-get-js
2
2
  language: JavaScript
3
- severity: warning
3
+ severity: error
4
4
  message: "Reflect.get(obj, key) — use a typed property access (obj.prop or obj[key]) instead"
5
+ metadata:
6
+ category: pi-lens-self-scan
5
7
  note: |
6
8
  Reflect.get reaches for reflection where a typed property access
7
9
  already works. Prefer dot or bracket access.
8
10
 
9
- Scoped to the 2-argument form only see no-reflect-get.yml's note:
10
- the 3-argument receiver-forwarding form is the standard Proxy `get`
11
- trap idiom.
11
+ 2026-08-20 (refs #1856): PROMOTED from `warning` to `error` with the
12
+ same structural Proxy get-trap carve-out as the TypeScript twin. Both
13
+ arities remain diagnostic elsewhere, but only the two-argument branch is
14
+ fixable because a receiver changes access semantics.
12
15
  rule:
13
- pattern: Reflect.get($OBJ, $KEY)
16
+ all:
17
+ - pattern: $CALL
18
+ - any:
19
+ - pattern: Reflect.get($OBJ, $KEY)
20
+ - pattern: Reflect.get($GET_TARGET, $PROP, $RECEIVER)
21
+ - not:
22
+ inside:
23
+ kind: method_definition
24
+ stopBy: end
25
+ has:
26
+ field: name
27
+ regex: "^get$"
28
+ inside:
29
+ pattern: new Proxy($TARGET, $HANDLER)
30
+ stopBy: end
31
+ rewriters:
32
+ - id: rewrite-two-argument-reflect-get-js
33
+ rule:
34
+ pattern: Reflect.get($OBJ, $KEY)
35
+ fix: "$OBJ[$KEY]"
36
+ transform:
37
+ REWRITTEN:
38
+ rewrite:
39
+ rewriters: [rewrite-two-argument-reflect-get-js]
40
+ source: $CALL
41
+ fix: $REWRITTEN
@@ -1,16 +1,42 @@
1
1
  id: no-reflect-get
2
2
  language: TypeScript
3
- severity: warning
3
+ severity: error
4
4
  message: "Reflect.get(obj, key) — use a typed property access (obj.prop or obj[key]) instead"
5
+ metadata:
6
+ category: pi-lens-self-scan
5
7
  note: |
6
8
  Reflect.get reaches for reflection where a typed property access
7
9
  already works. Prefer dot or bracket access.
8
10
 
9
- Scoped to the 2-argument form only. The 3-argument form
10
- (`Reflect.get(target, key, receiver)`) is the standard, correct way to
11
- forward a `receiver` inside a Proxy `get` trap an FP-scan of the
12
- pi-lens codebase found 2 hits, both inside a Proxy trap using the
13
- 3-argument receiver-forwarding form, so that arity is excluded rather
14
- than allowlisted by call site.
11
+ 2026-08-20 (refs #1856): PROMOTED from `warning` to `error`. The
12
+ standard receiver-forwarding call inside an inline `new Proxy` get
13
+ trap is excluded structurally. Both arities remain in scope elsewhere,
14
+ including a method merely named `get` outside a Proxy call. Only the
15
+ two-argument branch is fixable because a receiver changes access semantics.
15
16
  rule:
16
- pattern: Reflect.get($OBJ, $KEY)
17
+ all:
18
+ - pattern: $CALL
19
+ - any:
20
+ - pattern: Reflect.get($OBJ, $KEY)
21
+ - pattern: Reflect.get($GET_TARGET, $PROP, $RECEIVER)
22
+ - not:
23
+ inside:
24
+ kind: method_definition
25
+ stopBy: end
26
+ has:
27
+ field: name
28
+ regex: "^get$"
29
+ inside:
30
+ pattern: new Proxy($TARGET, $HANDLER)
31
+ stopBy: end
32
+ rewriters:
33
+ - id: rewrite-two-argument-reflect-get
34
+ rule:
35
+ pattern: Reflect.get($OBJ, $KEY)
36
+ fix: "$OBJ[$KEY]"
37
+ transform:
38
+ REWRITTEN:
39
+ rewrite:
40
+ rewriters: [rewrite-two-argument-reflect-get]
41
+ source: $CALL
42
+ fix: $REWRITTEN
@@ -12,9 +12,23 @@ note: |
12
12
 
13
13
  The rule matches a `function_definition` that contains BOTH a
14
14
  `yield` node AND a `return_statement` with a value (`return\s+\S`).
15
- The `stopBy: end` on each `has:` is required without it, `has`
16
- only checks immediate children (the function body is wrapped in a
17
- `block` node, not directly in `function_definition`).
15
+ Each `has:` uses `stopBy: {kind: function_definition}` (not the
16
+ plain `stopBy: end` this rule shipped with originally) it needs
17
+ to search past the `block` wrapper (the function body isn't a
18
+ direct child of `function_definition`), but must NOT cross into a
19
+ nested `function_definition`. A bare `stopBy: end` searches every
20
+ descendant regardless of depth, so a `yield` in an outer
21
+ `async def lifespan(app):` and an unrelated `return 42` inside a
22
+ nested `def handler():` got conflated into one false positive
23
+ (#1806 audit: 3 FP hits, none were actual generators — the yield
24
+ and the value-return belonged to different functions).
25
+
26
+ A nested function that is itself a real generator (has its own
27
+ `yield` AND its own value-`return`) is still flagged: the scanner
28
+ visits every `function_definition` node independently, including
29
+ nested ones, and `stopBy: {kind: function_definition}` only blocks
30
+ the OUTER function's search from reaching into the inner one — it
31
+ doesn't stop the inner function from being checked on its own.
18
32
 
19
33
  Bare `return` (no value) is allowed and intentionally not flagged.
20
34
  metadata:
@@ -24,8 +38,11 @@ rule:
24
38
  - kind: function_definition
25
39
  - has:
26
40
  kind: yield
27
- stopBy: end
41
+ stopBy:
42
+ kind: function_definition
28
43
  - has:
29
44
  kind: return_statement
30
45
  regex: 'return\s+\S'
31
- stopBy: end
46
+ stopBy:
47
+ kind: function_definition
48
+