@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
@@ -9,6 +9,31 @@ note: |
9
9
  the `unsafe` keyword should be removed) or it is misplaced (an unsafe
10
10
  operation lives outside an `unsafe { … }` block and should be wrapped).
11
11
  Either case warrants review.
12
+
13
+ Exempt when a `/// # Safety` doc-comment section precedes the function:
14
+ Rust's own convention (rustdoc's `missing_safety_doc` lint, and
15
+ clippy's `undocumented_unsafe_blocks`) is that an `unsafe fn` states
16
+ its caller obligations in a `# Safety` doc section instead of wrapping
17
+ its whole body in a redundant `unsafe { ... }` block — the function
18
+ signature IS the unsafe boundary, the doc section is where the
19
+ contract lives.
20
+
21
+ 2026-08-20 (review round, refs #1806): the first ship of this valve
22
+ used `follows: {stopBy: end, kind: line_comment, regex: '#\s*Safety'}`,
23
+ copying the `SAFETY:`-comment shape from `no-chained-type-assertions`
24
+ too literally. `stopBy: end` scans EVERY preceding sibling all the way
25
+ to the top of the file — one `# Safety` comment ANYWHERE earlier
26
+ (a stray file-top note, or a doc block that belongs to a DIFFERENT,
27
+ earlier function) exempted every `unsafe fn` after it. Probe: a
28
+ documented function followed by two undocumented ones scored 0 hits;
29
+ the two alone scored 2. Fixed by bounding the backward scan with
30
+ `stopBy: {not: {kind: line_comment}}` — it stops at the first
31
+ non-comment sibling, so only the CONTIGUOUS run of `///`/`//` lines
32
+ directly above the function is searched, never an earlier function's
33
+ doc block or an unrelated comment further up the file. (This valve
34
+ shipped with zero corpus hits either side in the original PR —
35
+ corpus silence isn't proof of correctness; the fixtures below are
36
+ the whole evidence, deliberately adversarial.)
12
37
  rule:
13
38
  all:
14
39
  - kind: function_item
@@ -19,3 +44,10 @@ rule:
19
44
  has:
20
45
  kind: unsafe_block
21
46
  stopBy: end
47
+ - not:
48
+ follows:
49
+ stopBy:
50
+ not:
51
+ kind: line_comment
52
+ kind: line_comment
53
+ regex: '#\s*Safety'
@@ -0,0 +1,184 @@
1
+ id: require-safety-comment-for-as-unknown-as
2
+ language: TypeScript
3
+ severity: error
4
+ metadata:
5
+ category: pi-lens-self-scan
6
+ message: "'x as unknown as T' with no nearby SAFETY: comment — state the invariant TypeScript can't check"
7
+ note: |
8
+ Narrowed port of dmmulroy/anti-slop's
9
+ `require-safety-comment-for-type-assertion`
10
+ (src/rules/require-safety-comment-for-type-assertion.ts, MIT).
11
+ Upstream requires a `SAFETY:` comment before EVERY non-const type
12
+ assertion (`as`/angle-bracket), walking up through statement-owner
13
+ node kinds looking for a preceding comment. This port narrows the
14
+ target to `x as unknown as T` specifically — the two-hop cast through
15
+ `unknown`. The 2026-08-19 audit found 2,180 non-const assertions
16
+ repo-wide and ZERO `SAFETY:` comments; requiring one on every
17
+ assertion would mean authoring ~1,750 comments in one PR. `as unknown
18
+ as` is the form that actually launders evidence (routes through the
19
+ top type rather than a single verifiable hop), and it is the exact
20
+ shape AGENTS.md's defect shape 13 already asks for in prose: "when a
21
+ call site hands the policy an outcome it did NOT derive... justify it
22
+ in a comment at the call site." This rule makes that convention
23
+ checkable for its most evidence-destroying form.
24
+
25
+ 2026-08-20 (refs #1727, #1777): promoted `hint` -> `error`. `error` is
26
+ the only tier that maps to semantic `blocking`
27
+ (`clients/dispatch/runners/ast-grep-napi.ts`), so AGENTS.md's severity
28
+ policy requires a documented zero-false-positive audit here. Two
29
+ changes make that audit come out clean.
30
+
31
+ 1. STRUCTURAL SCOPING: test paths are excluded (`ignores:` below). In a
32
+ test, `x as unknown as T` is almost always a partial test double —
33
+ reaching into a private field or stubbing the two methods of a
34
+ surface the subject actually calls. The "invariant TypeScript can't
35
+ check" there is "this stub covers what the code under test touches",
36
+ which is the test's own subject matter, not a hidden runtime claim.
37
+ Four-corpus census (2026-08-20) confirms the shape concentrates in
38
+ test paths rather than assuming it:
39
+
40
+ | corpus | total | test-path | non-test | suppressed |
41
+ |---|---:|---:|---:|---:|
42
+ | pi-lens (`clients/`+`tests/`) | 305 | 289 | 16 | 95% |
43
+ | pi core (`packages/`) | 182 | 155 | 27 | 85% |
44
+ | opencode (`packages/`) | 194 | 154 | 40 | 79% |
45
+ | oh-my-pi (`packages/`) | 1803 | 1644 | 159 | 91% |
46
+
47
+ This is a FALSE-NEGATIVE bias, deliberately, and it is not small:
48
+ 289 uncommented `as unknown as` sites in pi-lens's own `tests/`
49
+ now raise NO diagnostic at all, where each previously raised an
50
+ `error` through `no-chained-type-assertions.yml`'s `unknown` arm.
51
+ The same trade costs 1,644 sites on oh-my-pi. It is a path glob,
52
+ not a semantic check — ast-grep cannot verify a cast is really a
53
+ test double, only that it lives under a test path.
54
+
55
+ 2. REPO-SIDE REMEDIATION: the 16 remaining `clients/` sites were read
56
+ individually and each was given a truthful `SAFETY:` comment
57
+ naming the specific invariant (an optional Node API absent from
58
+ `@types/node`, a two-phase-init field filled before first read, a
59
+ `Object.fromEntries` key-type loss, a process-global stash). None
60
+ was a comment written to silence the rule; where the cast had no
61
+ justification it was replaced instead
62
+ (`clients/runtime-context.ts`).
63
+
64
+ Post-narrowing census on pi-lens: 0 findings over `clients/` +
65
+ `tests/`. The rule is tagged `metadata.category: pi-lens-self-scan`,
66
+ so CI's `npm run astgrep:self-scan` lane keeps it at zero.
67
+
68
+ Placement contract: a `SAFETY:` comment may directly precede the cast,
69
+ its enclosing statement, or an object-literal member (`pair`) containing
70
+ the cast. Array elements and call arguments are also supported through the
71
+ direct-cast arm when the comment is immediately above the cast expression.
72
+ JSX attributes, class static blocks, and switch cases are not comment
73
+ anchors for this valve; place those comments on the enclosing statement.
74
+ Inline comments remain valid, for example `/* SAFETY: ... */ x as unknown
75
+ as T`. Upstream walks an arbitrary number of statement-owner levels looking
76
+ for ANY preceding comment in the file; this port only checks one level up
77
+ from the assertion and one level up from its immediate containing
78
+ statement or supported object member. There is NO dominance verification:
79
+ the rule proves a comment is adjacent, never that the comment is true or
80
+ that it describes this cast.
81
+
82
+ 2026-08-20 (#1847, found in #1843's review): the "one level up from
83
+ its immediate containing statement" kind list omitted
84
+ `export_statement` and `public_field_definition`, so a `SAFETY:`
85
+ comment placed directly above an exported cast (`export const b =
86
+ (x as unknown as T).y;`) or a class-field cast (`bar: unknown = (x as
87
+ unknown as T).y;`) could not satisfy the valve — the rule is
88
+ `error`-tier and semantically `blocking`, so this left no escape for
89
+ those two shapes. Added both kinds. Verified the containing-statement
90
+ walk already covers casts nested deeper without a new kind: a cast
91
+ inside a `static {}` init block or an arrow-function body still
92
+ resolves to an ancestor `lexical_declaration`/`variable_declaration`
93
+ already in the list (probed with ast-grep's own `--rule` scan, not
94
+ reasoning about the grammar from memory), and a `SAFETY:` comment on
95
+ an `export const` nested inside a `namespace` block clears the valve
96
+ through the same `export_statement` kind — `stopBy: end` already
97
+ walks past the namespace wrapper to find it. `readonly`/`abstract`/
98
+ `static`/private-`#name` class fields all parse to the same
99
+ `public_field_definition` kind, so one entry covers all of them.
100
+
101
+ 2026-08-20 (#1852 review, F1): the same defect shape one more time —
102
+ an enum member's initializer cast (`enum Foo { A = (x as unknown as
103
+ T).y }`) has no recognized ancestor either. The member's own kind is
104
+ `enum_assignment` (probed the same way: `ast-grep scan --rule` against
105
+ a real `enum`/`const enum`/`export enum` snippet rather than guessing
106
+ from the export/field precedent). One `enum_assignment` kind entry
107
+ covers plain, `const`, and `export` enums alike, the same way
108
+ `public_field_definition` covered every class-field modifier —
109
+ `enum_assignment` is the member-list node itself, unaffected by
110
+ keywords on the enclosing `enum_declaration`. `declare enum` members
111
+ have no initializer expression to cast, so there is nothing to probe
112
+ there.
113
+
114
+ Matched pair with `no-chained-type-assertions.yml`. As of 2026-08-20
115
+ the two PARTITION the assertion space instead of overlapping: this
116
+ rule owns `x as unknown as T` (with the `SAFETY:` escape valve); that
117
+ rule owns the concrete `x as A as B` chain, which has no escape valve
118
+ because it has no legitimate reading. Before the split both rules
119
+ matched the identical `as unknown as` site list (verified: 16/16
120
+ pi-lens, 182/182 pi, 194/194 opencode), so every uncommented site
121
+ raised two diagnostics for one defect.
122
+
123
+ 2026-08-20 (#1834): both `follows` checks used `stopBy: end`, which
124
+ scans EVERY preceding sibling all the way to the top of the enclosing
125
+ block, not just the comment directly above the cast. A `SAFETY:`
126
+ comment attached to one cast silently exempted every LATER cast in the
127
+ same block, including casts on a different subject with no
128
+ justification of their own. Probe: `// SAFETY: ...` above `const a =
129
+ (y as unknown as string).length` followed by an undocumented `const b
130
+ = (x as unknown as string).length` scored 0 hits; `b`'s cast should
131
+ have been flagged. Fixed the same way as `redundant-unsafe-function`'s
132
+ identical valve (PR #1821, refs #1806): bound the backward scan with
133
+ `stopBy: {not: {kind: comment}}`, so it stops at the first non-comment
134
+ sibling and only ever searches the CONTIGUOUS comment run directly
135
+ above the cast (or its containing statement), never an earlier
136
+ statement's comment. The "Scope and known gap" note above already
137
+ described this contiguous-comment intent; the shipped pattern didn't
138
+ implement it.
139
+
140
+ 2026-08-20 (#1870): the pair arm is bounded by the nearest `pair`. An
141
+ outer object member's SAFETY comment must not suppress a cast in a nested
142
+ member, and a nested member's comment must not suppress a parent cast.
143
+ The direct-cast arm remains the precise escape valve for comments adjacent
144
+ to casts in array elements and call arguments.
145
+ ignores:
146
+ - "**/*.test.ts"
147
+ - "**/*.test.tsx"
148
+ - "**/*.test.mts"
149
+ - "**/*.test.cts"
150
+ - "**/*.spec.ts"
151
+ - "**/*.spec.tsx"
152
+ - "**/tests/**"
153
+ - "**/test/**"
154
+ - "**/__tests__/**"
155
+ rule:
156
+ pattern: $X as unknown as $Y
157
+ not:
158
+ any:
159
+ - follows:
160
+ kind: comment
161
+ regex: 'SAFETY\s*:'
162
+ stopBy: { not: { kind: comment } }
163
+ - inside:
164
+ stopBy: { kind: pair }
165
+ any:
166
+ - kind: pair
167
+ follows:
168
+ kind: comment
169
+ regex: 'SAFETY\s*:'
170
+ stopBy: { not: { kind: comment } }
171
+ - inside:
172
+ stopBy: end
173
+ any:
174
+ - kind: expression_statement
175
+ - kind: lexical_declaration
176
+ - kind: variable_declaration
177
+ - kind: return_statement
178
+ - kind: export_statement
179
+ - kind: public_field_definition
180
+ - kind: enum_assignment
181
+ follows:
182
+ kind: comment
183
+ regex: 'SAFETY\s*:'
184
+ stopBy: { not: { kind: comment } }
@@ -5,6 +5,11 @@ message: void 0 for undefined - use undefined directly
5
5
  metadata:
6
6
  weight: 2
7
7
  category: slop
8
+ note: |
9
+ Replacing `void 0` with `undefined` can change behavior when a local binding
10
+ shadows `undefined`. Shadowing `undefined` is itself a defect, and this fix
11
+ does not attempt to detect it.
8
12
  rule:
9
13
  kind: unary_expression
10
14
  pattern: "void 0"
15
+ fix: undefined
@@ -0,0 +1,5 @@
1
+ {
2
+ "_comment": "Regenerate with `npm run astgrep:self-scan -- --update-baseline` AFTER triaging every new entry (fix the underlying finding, or confirm it's a legitimate exception and document why in the same PR). Never regenerate to silently swallow an unreviewed hit.",
3
+ "generatedAt": "2026-08-19T20:44:05.206Z",
4
+ "allowed": []
5
+ }
@@ -202,6 +202,13 @@ function createState(files) {
202
202
  aborted: 0,
203
203
  timedOutSweeps: 0,
204
204
  timedOutFilesTotal: 0,
205
+ // #1618: per-reason breakdown of the same total. Populated from each
206
+ // sweep's `unconfirmedByReason` metadata when present; a sweep logged
207
+ // by a pre-#1618 build carries no such field, so its files are
208
+ // bucketed under "budget (pre-#1618 build)" — the ABSENT field is
209
+ // itself the vintage signal, not an assumption that every one of
210
+ // those files really was a budget timeout.
211
+ unconfirmedByReason: counter(),
205
212
  sweeps: [],
206
213
  progress: [],
207
214
  },
@@ -367,6 +374,27 @@ async function analyzeLatency(files, state) {
367
374
  if (timedOut > 0) {
368
375
  ws.timedOutSweeps += 1;
369
376
  ws.timedOutFilesTotal += timedOut;
377
+ // #1618: attribute by the REAL per-reason tally when the build
378
+ // that wrote this log line has it — a service-destroyed file
379
+ // must never count toward "hit the per-file budget" the way it
380
+ // used to (the forensics tool that found #1618 in the first
381
+ // place read this exact field and mis-blamed budget exhaustion
382
+ // for what were mostly service-destroyed files).
383
+ const byReason = entry.metadata?.unconfirmedByReason;
384
+ if (byReason && typeof byReason === "object") {
385
+ for (const [reason, count] of Object.entries(byReason)) {
386
+ const n = Number(count) || 0;
387
+ if (n > 0) ws.unconfirmedByReason.inc(reason, n);
388
+ }
389
+ } else {
390
+ // Vintage-attribution fallback: no `unconfirmedByReason` means
391
+ // this line predates #1618 — the absent field IS the signal,
392
+ // not proof every file here was really a budget timeout.
393
+ ws.unconfirmedByReason.inc(
394
+ "budget (pre-#1618 build)",
395
+ timedOut,
396
+ );
397
+ }
370
398
  state.smellTotals.inc("lsp-workspace-file-timeouts");
371
399
  pushTop(
372
400
  ws.sweeps,
@@ -1217,11 +1245,21 @@ function buildReport(state) {
1217
1245
  "Full LSP workspace sweeps that logged a start but never a completion (hang/kill signature — the 8h-hang class #383 hardened)",
1218
1246
  ws.progress.slice(0, limit),
1219
1247
  );
1248
+ // #1618: "hit the per-file budget" used to be this smell's blanket
1249
+ // description regardless of WHY a file was unconfirmed — the exact
1250
+ // mislabeling the forensics pass on this class found (81/111 "budget"
1251
+ // files were actually service-destroyed). Render the real breakdown when
1252
+ // available.
1253
+ const unconfirmedReasonBreakdown = ws.unconfirmedByReason
1254
+ .top(limit)
1255
+ .map(({ key, count }) => `${key}=${count}`)
1256
+ .join(", ");
1220
1257
  addSmell(
1221
1258
  smells,
1222
1259
  "lsp-workspace-file-timeouts",
1223
1260
  smellCount("lsp-workspace-file-timeouts"),
1224
- `Full LSP sweeps where files hit the per-file budget (${ws.timedOutFilesTotal} files across ${ws.timedOutSweeps} sweeps)`,
1261
+ `Full LSP sweeps produced an unconfirmed file (${ws.timedOutFilesTotal} files across ${ws.timedOutSweeps} sweeps)` +
1262
+ (unconfirmedReasonBreakdown ? ` — by reason: ${unconfirmedReasonBreakdown}` : ""),
1225
1263
  ws.sweeps.slice(0, limit),
1226
1264
  );
1227
1265
 
@@ -1257,6 +1295,11 @@ function buildReport(state) {
1257
1295
  aborted: ws.aborted,
1258
1296
  timedOutSweeps: ws.timedOutSweeps,
1259
1297
  timedOutFilesTotal: ws.timedOutFilesTotal,
1298
+ // #1618: the real per-reason breakdown of `timedOutFilesTotal`.
1299
+ // "budget (pre-#1618 build)" means those log lines predate the
1300
+ // per-reason tally entirely — an older build's absence of the field,
1301
+ // not a claim those files really timed out.
1302
+ unconfirmedByReason: ws.unconfirmedByReason.toJSON(),
1260
1303
  },
1261
1304
  },
1262
1305
  cascade: {
@@ -1458,6 +1501,15 @@ function printReport(report) {
1458
1501
  console.log(
1459
1502
  ` started=${ws.started} completed=${ws.completed} incomplete=${ws.incomplete} aborted=${ws.aborted} fileTimeouts=${ws.timedOutFilesTotal} (in ${ws.timedOutSweeps} sweeps)`,
1460
1503
  );
1504
+ // #1618: never let a flat count alone read as "budget exhaustion" —
1505
+ // print the real per-reason split (or its absence, which itself means
1506
+ // every line here predates the tally).
1507
+ const reasons = Object.entries(ws.unconfirmedByReason ?? {});
1508
+ if (reasons.length) {
1509
+ console.log(
1510
+ ` by reason: ${reasons.map(([reason, count]) => `${reason}=${count}`).join(", ")}`,
1511
+ );
1512
+ }
1461
1513
  }
1462
1514
  const wl = report.worklog;
1463
1515
  if (wl && (wl.byModel.length || wl.byRuleModel.length)) {
@@ -39,6 +39,24 @@ export const SOURCE_OVERRIDES = {
39
39
  url: "https://unpkg.com/@tree-sitter-grammars/tree-sitter-yaml@0.7.1/tree-sitter-yaml.wasm",
40
40
  },
41
41
  };
42
+ /**
43
+ * Grammars committed under `vendor/grammars/` rather than fetched.
44
+ *
45
+ * tree-sitter-cue: no published wasm exists — npm's `tree-sitter-cue` is a
46
+ * native binding, the `tree-sitter-wasms` aggregator has no CUE, and upstream
47
+ * cuts no releases — so we build it from a pinned commit (#1522).
48
+ */
49
+ export const VENDORED_GRAMMARS = {
50
+ "tree-sitter-cue.wasm": {
51
+ repo: "https://github.com/eonpatapon/tree-sitter-cue",
52
+ commit: "dd7b90e0770ff18070c515937ba3c3d6d93db00e",
53
+ license: "MIT",
54
+ buildCommand: "npx tree-sitter-cli build --wasm",
55
+ sha256: "sha256:751f8cc8ccf72da760133e3d365562ff7bbf5b951e0b73568576fd159db7d601",
56
+ },
57
+ };
58
+ /** Directory the committed grammars live in, relative to the package root. */
59
+ export const VENDORED_DIR = "vendor/grammars";
42
60
  /** The package a grammar's sidecar records (override or the global aggregator). */
43
61
  export function expectedPackage(filename, manifest) {
44
62
  return manifest.overrides?.[filename]?.package ?? SOURCE_OVERRIDES[filename]?.package ?? manifest.package;
@@ -210,6 +228,13 @@ async function regenerateManifest() {
210
228
  version: TREE_SITTER_WASMS_VERSION,
211
229
  grammars: sorted,
212
230
  ...(Object.keys(SOURCE_OVERRIDES).length ? { overrides: SOURCE_OVERRIDES } : {}),
231
+ // Re-emitted from the map above, not copied from the old manifest: a
232
+ // `--write-manifest` run on a tree-sitter-wasms bump must not silently
233
+ // drop the committed grammars' provenance, which would leave the guard
234
+ // with nothing to check.
235
+ ...(Object.keys(VENDORED_GRAMMARS).length
236
+ ? { vendored: VENDORED_GRAMMARS }
237
+ : {}),
213
238
  };
214
239
  writeFileSync(MANIFEST_PATH, `${JSON.stringify(manifest, null, 2)}\n`);
215
240
  console.error(`Wrote ${MANIFEST_PATH} (${GRAMMARS.length} grammars).`);
@@ -40,5 +40,14 @@
40
40
  "version": "0.7.1",
41
41
  "url": "https://unpkg.com/@tree-sitter-grammars/tree-sitter-yaml@0.7.1/tree-sitter-yaml.wasm"
42
42
  }
43
+ },
44
+ "vendored": {
45
+ "tree-sitter-cue.wasm": {
46
+ "repo": "https://github.com/eonpatapon/tree-sitter-cue",
47
+ "commit": "dd7b90e0770ff18070c515937ba3c3d6d93db00e",
48
+ "license": "MIT",
49
+ "buildCommand": "npx tree-sitter-cli build --wasm",
50
+ "sha256": "sha256:751f8cc8ccf72da760133e3d365562ff7bbf5b951e0b73568576fd159db7d601"
51
+ }
43
52
  }
44
53
  }
@@ -19,6 +19,20 @@
19
19
  * build-script-provided assets (ast-grep CLI binary + tree-sitter grammars)
20
20
  * that pnpm/bun skip by default. It runs no model and needs no credentials.
21
21
  *
22
+ * WHAT IT NO LONGER COVERS (#1926)
23
+ * pi supplies `typebox` and `@earendil-works/pi-tui` from its own runtime, so
24
+ * they are optional peers and no install vendors them. This probe is not pi, so
25
+ * those specifiers cannot resolve here, and `dist/index.js` throws on the FIRST
26
+ * one it imports. A host-provided miss is therefore recorded as EXPECTED rather
27
+ * than failed. The cost is real and stated plainly: evaluation stops there, so
28
+ * the entry probe no longer proves the whole bundled graph resolves, which is
29
+ * what #285 and #335 asked it to prove. Any OTHER unresolved specifier still
30
+ * fails hard, and the per-module probes below (file-utils, complexity-client,
31
+ * bootstrap) still cover that graph directly. The surviving POSITIVE proof that
32
+ * the entry loads in full is the install-smoke `pi-load` job: it installs pi,
33
+ * installs pi-lens through pi, and confirms over RPC that pi-lens registered
34
+ * its commands.
35
+ *
22
36
  * USAGE
23
37
  * bun scripts/install-selftest.mjs # faithful: pi's runtime is bun
24
38
  * node scripts/install-selftest.mjs # also works
@@ -28,10 +42,11 @@
28
42
  */
29
43
 
30
44
  import { execFileSync } from "node:child_process";
45
+ import * as fs from "node:fs";
31
46
  import { createRequire } from "node:module";
32
- import { fileURLToPath } from "node:url";
33
47
  import * as path from "node:path";
34
- import * as fs from "node:fs";
48
+ import { fileURLToPath } from "node:url";
49
+ import { HOST_PROVIDED_PACKAGES } from "./lib/host-provided-deps.mjs";
35
50
 
36
51
  const here = path.dirname(fileURLToPath(import.meta.url));
37
52
  const pkgRoot = path.resolve(here, "..");
@@ -42,6 +57,26 @@ const results = [];
42
57
  const record = (name, kind, ok, detail = "") =>
43
58
  results.push({ name, kind, ok, detail });
44
59
 
60
+ /**
61
+ * Which host-provided package, if any, a resolution error is about. Returns
62
+ * undefined for every other error, so an unrelated missing package still fails.
63
+ */
64
+ function hostProvidedMiss(err) {
65
+ const text = `${err?.code || ""} ${err?.message || err}`;
66
+ if (
67
+ !/ERR_MODULE_NOT_FOUND|Cannot find (package|module)|ResolveMessage/.test(
68
+ text,
69
+ )
70
+ ) {
71
+ return undefined;
72
+ }
73
+ return HOST_PROVIDED_PACKAGES.find((name) =>
74
+ new RegExp(
75
+ `['"\`]${name.replace(/[/\\^$*+?.()|[\]{}]/g, "\\$&")}['"\`]`,
76
+ ).test(text),
77
+ );
78
+ }
79
+
45
80
  /** Import a module by URL and record whether its (eager) dep graph resolved. */
46
81
  async function probeImport(name, relPath) {
47
82
  const url = new URL(
@@ -51,7 +86,24 @@ async function probeImport(name, relPath) {
51
86
  await import(url.href);
52
87
  record(name, "resolve", true);
53
88
  } catch (err) {
54
- record(name, "resolve", false, `${err?.code || ""} ${err?.message || err}`.trim());
89
+ // #1926: pi supplies these; outside pi they cannot resolve, and the entry
90
+ // throws on the first one. Expected, not a regression. Anything else is.
91
+ const host = hostProvidedMiss(err);
92
+ if (host) {
93
+ record(
94
+ name,
95
+ "expected",
96
+ true,
97
+ `stopped at host-provided '${host}' — pi supplies it; graph beyond this point unproven here (#1926)`,
98
+ );
99
+ return;
100
+ }
101
+ record(
102
+ name,
103
+ "resolve",
104
+ false,
105
+ `${err?.code || ""} ${err?.message || err}`.trim(),
106
+ );
55
107
  }
56
108
  }
57
109
 
@@ -61,27 +113,53 @@ function probeResolve(spec) {
61
113
  require.resolve(spec);
62
114
  record(spec, "resolve", true);
63
115
  } catch (err) {
64
- record(spec, "resolve", false, `${err?.code || ""} ${err?.message || err}`.trim());
116
+ record(
117
+ spec,
118
+ "resolve",
119
+ false,
120
+ `${err?.code || ""} ${err?.message || err}`.trim(),
121
+ );
65
122
  }
66
123
  }
67
124
 
68
125
  // --- 1. The documented failure-point modules (eager bare imports) ----------
69
126
  await probeImport("dist/index.js (entry)", "dist/index.js");
70
- await probeImport("clients/file-utils.js (→ minimatch)", "dist/clients/file-utils.js");
71
- await probeImport("clients/complexity-client.js (→ tree-sitter)", "dist/clients/complexity-client.js");
72
- await probeImport("clients/bootstrap.js (→ all analyzers)", "dist/clients/bootstrap.js");
127
+ await probeImport(
128
+ "clients/file-utils.js (→ minimatch)",
129
+ "dist/clients/file-utils.js",
130
+ );
131
+ await probeImport(
132
+ "clients/complexity-client.js (→ tree-sitter)",
133
+ "dist/clients/complexity-client.js",
134
+ );
135
+ await probeImport(
136
+ "clients/bootstrap.js (→ all analyzers)",
137
+ "dist/clients/bootstrap.js",
138
+ );
73
139
 
74
140
  // --- 2. Direct bare-specifier resolution -----------------------------------
75
- for (const spec of [
141
+ // Host-provided packages are subtracted, not listed as exceptions: pi resolves
142
+ // them from its own runtime, so nothing installs them and probing one here is
143
+ // guaranteed to fail (#1926). The subtraction reads the same list the bundler
144
+ // and the packaging tests use, so it cannot drift.
145
+ const BARE_SPECIFIERS = [
76
146
  "minimatch",
77
147
  "typebox",
78
148
  "js-yaml",
79
149
  "vscode-jsonrpc",
80
150
  "web-tree-sitter",
81
151
  "@ast-grep/napi",
82
- ]) {
152
+ ].filter((spec) => !HOST_PROVIDED_PACKAGES.includes(spec));
153
+
154
+ for (const spec of BARE_SPECIFIERS) {
83
155
  probeResolve(spec);
84
156
  }
157
+ record(
158
+ "host-provided specifiers skipped",
159
+ "expected",
160
+ true,
161
+ `${HOST_PROVIDED_PACKAGES.join(", ")} — pi supplies these (#1926)`,
162
+ );
85
163
 
86
164
  // --- 3. Spawned-binary tools (the universal net) ----------------------------
87
165
  // For every tool that ships its binary in a per-platform npm package
@@ -121,11 +199,21 @@ try {
121
199
  });
122
200
  record(label, "tool", true, bin);
123
201
  } catch (err) {
124
- record(label, "tool", false, `${bin} failed to run: ${err?.message || err}`);
202
+ record(
203
+ label,
204
+ "tool",
205
+ false,
206
+ `${bin} failed to run: ${err?.message || err}`,
207
+ );
125
208
  }
126
209
  }
127
210
  } catch (err) {
128
- record("spawned-tool probe", "tool", false, `installer load failed: ${err?.message || err}`);
211
+ record(
212
+ "spawned-tool probe",
213
+ "tool",
214
+ false,
215
+ `installer load failed: ${err?.message || err}`,
216
+ );
129
217
  }
130
218
 
131
219
  // tree-sitter grammars — download-grammars.js postinstall writes them into
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Single source of truth for the packages `scripts/bundle-dist.mjs` keeps out of
3
+ * the dist bundle, split by the REASON they stay external. #1926.
4
+ *
5
+ * HOST_PROVIDED_PACKAGES
6
+ * pi ships these inside its own runtime (`@earendil-works/pi-coding-agent`'s
7
+ * node_modules). They must be declared as OPTIONAL peer dependencies plus dev
8
+ * dependencies, never as runtime `dependencies`, because a runtime dependency
9
+ * makes `npm install --omit=dev` — the command pi runs for a `git:` install —
10
+ * vendor a private second copy into the extension's own node_modules. Node
11
+ * then resolves the bare specifier to that copy and evaluates a whole extra
12
+ * module graph at import. That is #1926: vendoring `typebox` and
13
+ * `@earendil-works/pi-tui` cost 720ms of the 838ms git-install import, and
14
+ * removing the copies took the PI_TIMING module import from 941ms to ~180ms.
15
+ *
16
+ * The three entries are NOT interchangeable at runtime. pi resolves the bare
17
+ * specifiers `typebox` and `@earendil-works/pi-tui` for an extension, so
18
+ * VALUE imports of those work with no copy on disk — verified by hiding both
19
+ * from the dogfood install and re-running under PI_TIMING (#1926), and by
20
+ * `@tintinweb/pi-subagents`, which declares pi-tui as a peer and ships no
21
+ * copy. `@earendil-works/pi-coding-agent` is different: it is not resolvable
22
+ * from an extension at all, so pi-lens imports it TYPE-ONLY and inlines the
23
+ * runtime helpers it needs. `tests/host-sdk-type-only.test.ts` enforces that
24
+ * separate rule (#1334 S6); do not read this list as permission to
25
+ * value-import the host SDK.
26
+ *
27
+ * LAZY_NATIVE_PACKAGES
28
+ * Native addon / wasm, dynamic-imported by absolute file:// URL at call time.
29
+ * They stay external because esbuild cannot inline a .node or .wasm, and they
30
+ * cost nothing at load because nothing imports them statically.
31
+ *
32
+ * `tests/packaging.test.ts` pins both invariants against package.json and
33
+ * against the built dist entry, so this list cannot drift from what ships.
34
+ */
35
+
36
+ /**
37
+ * Host-provided packages the extension VALUE-imports. pi resolves these bare
38
+ * specifiers at runtime, so the compiled entry cannot load without them.
39
+ * Outside pi — a bare `node dist/index.js` in a CI smoke check — nothing
40
+ * supplies them, so a job that wants a FULL load has to install them first, the
41
+ * way pi does. `scripts/supply-host-provided-deps.mjs` does that.
42
+ */
43
+ export const HOST_PROVIDED_RUNTIME_PACKAGES = Object.freeze([
44
+ "typebox",
45
+ "@earendil-works/pi-tui",
46
+ ]);
47
+
48
+ /**
49
+ * Host-provided packages the extension imports TYPE-ONLY. pi does not resolve
50
+ * these for an extension at all, which is why every runtime helper pi-lens
51
+ * needs from the host SDK is inlined instead; `tests/host-sdk-type-only.test.ts`
52
+ * enforces that (#1334 S6). Never install one of these to make a load succeed:
53
+ * the transitive tree has nested paths that exceed Windows MAX_PATH.
54
+ */
55
+ export const HOST_PROVIDED_TYPE_ONLY_PACKAGES = Object.freeze([
56
+ "@earendil-works/pi-coding-agent",
57
+ ]);
58
+
59
+ /** Everything pi supplies, so pi-lens must never declare it a dependency. */
60
+ export const HOST_PROVIDED_PACKAGES = Object.freeze([
61
+ ...HOST_PROVIDED_RUNTIME_PACKAGES,
62
+ ...HOST_PROVIDED_TYPE_ONLY_PACKAGES,
63
+ ]);
64
+
65
+ /** Native/wasm packages dynamic-imported by absolute path at call time. */
66
+ export const LAZY_NATIVE_PACKAGES = Object.freeze([
67
+ "@ast-grep/napi",
68
+ "web-tree-sitter",
69
+ ]);
70
+
71
+ /** Everything esbuild must NOT inline into dist/index.js. */
72
+ export const BUNDLE_EXTERNALS = Object.freeze([
73
+ ...HOST_PROVIDED_PACKAGES,
74
+ ...LAZY_NATIVE_PACKAGES,
75
+ ]);