@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
@@ -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
  }
@@ -62,6 +62,8 @@ Use these instead of writing raw YAML:
62
62
 
63
63
  `hasKind` and `hasDescendantKind` are mutually exclusive on both tools — combining them errors.
64
64
 
65
+ ⚠ `insideKind` searches ALL ancestors (`stopBy: end`) with no boundary of its own — on a deeply nested file it can escalate past the enclosing function you meant and match against an unrelated outer scope; scope with `paths` or a raw YAML `rule:` with its own `stopBy` boundary if that matters.
66
+
65
67
  ```
66
68
  # console.log only inside functions
67
69
  ast_grep_search pattern="console.log($MSG)" lang="typescript" insideKind="function_declaration"
@@ -13,7 +13,7 @@ Same `id` as a built-in overrides it. Multiple rules per file: separate with `--
13
13
  ```yaml
14
14
  id: no-foo-bar
15
15
  language: TypeScript # PascalCase — see languages below
16
- severity: warning # error | warning | info
16
+ severity: warning # error | warning | hint | info — pick by evidence, see below
17
17
  message: "Avoid foo.bar() — use baz() instead"
18
18
  note: |
19
19
  Longer explanation / fix guidance here.
@@ -21,6 +21,39 @@ rule:
21
21
  pattern: foo.bar($ARG)
22
22
  ```
23
23
 
24
+ **Pick the severity by the evidence behind the rule, not by feel:**
25
+
26
+ - **`error`** — only with a documented zero-false-positive audit in the `note`.
27
+ Only `error` maps to semantic `blocking` and stops a turn.
28
+ - **`warning`** — a real finding with a known, bounded false-positive rate.
29
+ - **`hint` / `info`** — style opinions. They render as advisory text, never
30
+ block, and lose the report budget to warnings when a report is capped.
31
+
32
+ Full policy and the `error`-promotion procedure: AGENTS.md's "Severity policy
33
+ (#1777)" section. Read it before shipping anything above `warning`.
34
+
35
+ ## Before promoting to error
36
+
37
+ Three things must all be true, and the rule's `note` must record them:
38
+
39
+ 1. **A multi-corpus false-positive census**, not a single-tree count. Run the
40
+ rule over pi-lens's `clients/`/`tests/` plus at least one real external
41
+ codebase of the kind the rule targets, classify every hit, and put the
42
+ table in the note.
43
+ 2. **Structural narrowing before exemption.** Suppress a legitimate idiom
44
+ with a relational constraint (`inside`/`has`/`follows`, scoped path
45
+ globs), not with prose telling readers to ignore the hit. Narrow first —
46
+ don't reach for a lower tier as the easy way out. `no-non-null-assertion`
47
+ was demoted to `hint` (`0124608a`), then reverted back to `warning` once
48
+ the same false positives were closed with a structural exclusion instead
49
+ (`b3e1fd79`).
50
+ 3. **Self-scan wiring.** Tag the rule `metadata.category: pi-lens-self-scan`
51
+ so `npm run astgrep:self-scan` holds this tree at zero in CI. An `error`
52
+ rule that never runs against pi-lens's own source is an unaudited claim.
53
+
54
+ If the post-narrowing residual is still tens of legitimate hits, stop and
55
+ report the numbers instead of shipping at `error`.
56
+
24
57
  ## Language values
25
58
 
26
59
  `TypeScript` `JavaScript` `Python` `Go` `Rust` `Java` `C` `Cpp` `CSharp` `Kotlin` `Ruby` `Php`
@@ -69,6 +102,13 @@ constraints: # metavariable regex constraints work
69
102
  recursive descendant/ancestor search add `stopBy: end`. This is the #1 migration
70
103
  gotcha — see the `has` note in `reference.md`.
71
104
 
105
+ ⚠ **`stopBy: end` alone is not a boundary.** It's a search-depth control — how far
106
+ the walk searches — not a stop condition; the `any:` kind list only decides what
107
+ CAN satisfy the match, not where the walk halts. To scope a relation to the
108
+ nearest enclosing function (or any other boundary), give `stopBy` its own rule.
109
+ See "Scoping to the nearest enclosing X" in `reference.md` (#1794 F1 — this bug
110
+ shipped twice in one window).
111
+
72
112
  ## YAML quoting — REQUIRED (js-yaml will reject the rule otherwise)
73
113
 
74
114
  The parser is a real YAML parser, so unquoted special chars throw and the rule is
@@ -104,13 +144,50 @@ The parser is a real YAML parser, so unquoted special chars throw and the rule i
104
144
 
105
145
  `reference.md` (same directory) covers: ReDoS-safe regex authoring, node-text
106
146
  string-escape quirks, `has`/`inside` `stopBy` defaults (and when to override
107
- them), the `-js` twin dedup behavior (#657), boolean-parameter matching
108
- across the TS/JS grammars, and precision-over-recall heuristics for
147
+ them), scoping a relation to the nearest enclosing node with a `stopBy`
148
+ boundary rule, the `-js` twin dedup behavior (#657), boolean-parameter
149
+ matching across the TS/JS grammars, and precision-over-recall heuristics for
109
150
  denylist-shaped rules. Read it when a rule isn't matching (or over-matching)
110
151
  the way you expect, or before shipping a `regex`/`has`-heavy rule.
111
152
 
153
+ ## Testing a suppression
154
+
155
+ Every relational suppression (a `has`/`inside`/`not` exclusion for a
156
+ legitimate idiom) needs two fixtures per bound metavariable, not one:
157
+
158
+ 1. **A same-binding valid case** — the idiom the exclusion is meant to
159
+ suppress, with the metavariable bound consistently (same receiver, same
160
+ key).
161
+ 2. **A mutation-guard invalid case** — the same shape with the binding
162
+ broken: a different key, a different receiver, or a boundary-crossing
163
+ lookalike (the guard lives in the wrong scope). This proves the
164
+ exclusion checks the BINDING, not just the pattern's presence somewhere
165
+ in the file.
166
+
167
+ `rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml` is the model: alongside the
168
+ get-after-has/pop-after-length valid cases, it fixtures a different-key
169
+ guard, a different-map guard, and an outer-function guard that must NOT
170
+ suppress an inner closure — each one red if the corresponding binding check
171
+ is deleted.
172
+
173
+ Corpus silence is not evidence. A valve with zero corpus hits needs
174
+ adversarial fixtures MORE, not less — `redundant-unsafe-function` targets
175
+ Rust, so it has no pi-lens corpus to census against, and its `# Safety`
176
+ valve still shipped an unbounded backward scan that over-suppressed real
177
+ detections, caught only by adversarial fixtures in review (`00284bcc`). A
178
+ documented blind spot (an idiom the rule knowingly can't distinguish from a
179
+ bug) becomes an `invalid`-direction fixture with a comment naming the gap,
180
+ never silence.
181
+
182
+ Regenerate the catalog doc with `npm run docs:rule-catalogs` after adding or
183
+ changing a rule — never hand-edit the generated catalog.
184
+
112
185
  ## Validating a candidate rule against the REAL engine (not the warm MCP cache)
113
186
 
187
+ Live-binary discipline (AGENTS.md shape 16) applies here too: verify parsing
188
+ and match behavior against a real `ast-grep` run before you write it into a
189
+ rule note or a test fixture — a hand-written fixture pins a guess, not a fact.
190
+
114
191
  ```
115
192
 
116
193
  # inspect how a PATTERN parses → find the node kind you actually need
@@ -92,6 +92,47 @@ grammars, and precision-over-recall heuristics for denylist-shaped rules.
92
92
  the partition unique; flag only a single quantified atom inside the group).
93
93
  ```
94
94
 
95
+ ## Scoping to the nearest enclosing X (#1794 F1)
96
+
97
+ `stopBy` controls how far the ancestor/descendant walk searches. It is not a
98
+ stop CONDITION. An `any:` kind list inside `inside`/`has` decides which
99
+ nodes the walk is ALLOWED to match — it does not tell the walk where to
100
+ halt. `stopBy: end` alone searches every ancestor up to the file root, so a
101
+ guard several scopes out can suppress a finding inside an unrelated closure.
102
+
103
+ To scope a relation to the nearest enclosing function (or any other
104
+ boundary), give `stopBy` its OWN rule — the same kind list used as the
105
+ match target — so the walk stops at the first satisfying ancestor and can
106
+ never escalate past it:
107
+
108
+ ```yaml
109
+ inside:
110
+ stopBy: # the BOUNDARY: halts the walk here
111
+ any:
112
+ - kind: function_declaration
113
+ - kind: method_definition
114
+ - kind: arrow_function
115
+ - kind: function_expression
116
+ any: # the MATCH TARGET: same list, different job
117
+ - kind: function_declaration
118
+ - kind: method_definition
119
+ - kind: arrow_function
120
+ - kind: function_expression
121
+ has:
122
+ stopBy: end
123
+ pattern: $M.has($K)
124
+ ```
125
+
126
+ This is the fix for #1794 F1: an earlier `no-non-null-assertion` exclusion
127
+ used `stopBy: end` with only the `any:` kind list as the match target, so a
128
+ `.has()`/`.length` guard in an OUTER function suppressed a closure's `!`
129
+ several scopes in. The same defect shape — `stopBy: end` mistaken for a
130
+ boundary — shipped twice in the same 2026-08-20 window: once here, and once
131
+ in `redundant-unsafe-function`'s `# Safety` valve (an unbounded backward
132
+ comment scan, fixed in `00284bcc`). See
133
+ `rules/ast-grep-rules/rules/no-non-null-assertion.yml` for the full working
134
+ rule.
135
+
95
136
  ## Matching things a pattern can't express (#305)
96
137
 
97
138
  ```
@@ -7,6 +7,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.27.0] - 2026-08-20
11
+
12
+ ### Highlights
13
+ - MCP servers can now come from packages, runtime extension APIs, or the usual config files.
14
+ - Static bearer tokens can use the OS credential store, with a stdin-only CLI for safer token management.
15
+ - Long-lived sessions recover better when remote MCP servers are slow, refreshed, or reconnected.
16
+ - OAuth flows clean up their callback listener when idle and work better inside nested terminal UI prompts.
17
+ - Search, metadata cache writes, direct-tool counts, and UI stream pruning now do less repeated work.
18
+
19
+ ### Added
20
+ - `/pi-mcp` now works as an alias for `/mcp` when a host reserves `/mcp`. Thanks to [@inxeoz](https://github.com/inxeoz) for #391.
21
+ - `registerMcpServer({ pi, name, definition })` lets other extensions register and dispose session-scoped MCP servers at runtime. Registrations are proxy-tool-only, never persisted, and duplicate names fail closed. Thanks to [@bendavis78](https://github.com/bendavis78) and [@fmoda3](https://github.com/fmoda3) for the runtime API request in #376/#382.
22
+ - Pi packages can ship prefixed MCP server definitions with `pi.mcp` manifest entries, without asking users to edit MCP config files. Thanks to [@bendavis78](https://github.com/bendavis78) for #376 and [@fmoda3](https://github.com/fmoda3) for the manifest design.
23
+ - Static bearer tokens can opt into OS credential-store lookup with URL-bound records by setting `bearerTokenStore: true`. The new `pi-mcp-adapter token set|status|remove <server>` CLI reads tokens from stdin and never accepts a token as an argument. Thanks to [@AlexanderBartash](https://github.com/AlexanderBartash) for issue #366.
24
+
25
+ ### Changed
26
+ - Search ranking now reuses normalized MCP tool fields and keyword tokens per catalog.
27
+ - Per-request header commands collect process cleanup data in one snapshot per pass, reducing cold HTTP connect overhead.
28
+ - Metadata cache saves write compact JSON while preserving atomic replacement and cross-process merges.
29
+ - High-frequency UI stream event-log pruning tracks the latest checkpoint event ID instead of rescanning retained patches.
30
+ - The MCP panel reuses direct-tool counts and token totals across renders while keeping toggle and reconnect updates immediate.
31
+
32
+ ### Fixed
33
+ - Short-lived `mcpScript` workers no longer emit false unmanaged file-descriptor warnings on Node 24. Thanks to [@blalor](https://github.com/blalor) for PR #407.
34
+ - OAuth callback listeners are released after idle auth flows, and MCP pickers stay hidden while nested OAuth input is active. Thanks to [@trevorleibert-mixpanel](https://github.com/trevorleibert-mixpanel) for PRs #403 and #404.
35
+ - Request-header command cleanup can scan large process lists without overflowing `spawnSync`'s 1 MiB default buffer, which previously caused spurious `HTTP request headers command cleanup failed: ps exited with code unknown` refresh failures on busy hosts. Thanks to [@rtfpessoa](https://github.com/rtfpessoa) for PR #399.
36
+ - Slow but healthy remote keep-alive servers are no longer marked failed when a bounded tools/list refresh times out. Thanks to [@brightmeowso](https://github.com/brightmeowso) for #400.
37
+ - Cached metadata reconstruction now reuses one selector candidate index, avoiding repeated scans of large cached catalogs at startup.
38
+ - MCP status consumers no longer see a connected catalog before Pi's model-facing tool surface is current. The first connected status snapshot now waits for direct-tool synchronization. Thanks to [@dmorn](https://github.com/dmorn) for PR #380.
39
+ - JSON-string MCP tool-call arguments are normalized before approval and transport, preserving all fields and embedded quotes. Thanks to [@sebbean](https://github.com/sebbean) for PR #377.
40
+ - Session tool approvals are scoped to the approved argument payload instead of every later call to the same tool. Thanks to [@spaceshipmike](https://github.com/spaceshipmike) for #367.
41
+ - MCP panel commands no longer hang in RPC, JSON, and print modes when terminal-only custom UI is unavailable. Thanks to [@shixin-guo](https://github.com/shixin-guo) for PR #365.
42
+ - Compact MCP rows now show a bounded tool-input preview and skip leading blank output lines in collapsed result previews.
43
+ - MCP gateway requests nested inside proxy `args` are recovered instead of silently showing status, and invalid nested gateway requests now fail with guidance. Thanks to [@ibrmora](https://github.com/ibrmora) for #363.
44
+ - Remote keep-alive tool catalogs refresh before user input, adapter-triggered turns, and health checks. Expired Streamable HTTP sessions reconnect so long-lived Pi sessions can discover replacement catalogs without restarting. Thanks to [@dmorn](https://github.com/dmorn) for #369 and PR #370.
45
+
10
46
  ## [2.26.0] - 2026-08-14
11
47
 
12
48
  ### Added