@herbertgao/pi-extensions 2026.8.5 → 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 (389) hide show
  1. package/README.md +5 -5
  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 +272 -22
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +74 -5
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +48 -6
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +1 -1
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +14 -0
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +55 -17
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +41 -2
  14. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +75 -6
  15. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +7 -3
  16. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +64 -1
  17. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  18. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +16 -0
  19. package/node_modules/@herbertgao/pi-subagents/README.md +30 -22
  20. package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +5 -5
  21. package/node_modules/@herbertgao/pi-subagents/package.json +7 -7
  22. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +7 -1
  23. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +48 -19
  24. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +22 -15
  25. package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +26 -2
  26. package/node_modules/@herbertgao/pi-subagents/src/index.ts +219 -40
  27. package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +101 -3
  28. package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +18 -4
  29. package/node_modules/@herbertgao/pi-subagents/src/settings.ts +99 -0
  30. package/node_modules/@herbertgao/pi-subagents/src/types.ts +22 -3
  31. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +51 -3
  32. package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +20 -2
  33. package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +34 -10
  34. package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
  35. package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +29 -5
  36. package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +3 -0
  37. package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +46 -10
  38. package/node_modules/@juicesharp/rpiv-ask-user-question/config.ts +25 -0
  39. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/configuration.md +13 -4
  40. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +8 -1
  41. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +3 -1
  42. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +2 -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 +3 -1
  47. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +30 -7
  48. package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
  49. package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +30 -4
  50. package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +26 -5
  51. package/node_modules/@narumitw/pi-btw/README.md +119 -103
  52. package/node_modules/@narumitw/pi-btw/dist/index.ts +2898 -0
  53. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +7 -0
  54. package/node_modules/@narumitw/pi-btw/package.json +13 -9
  55. package/node_modules/@narumitw/pi-btw/src/btw.ts +40 -42
  56. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +55 -10
  57. package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +390 -0
  58. package/node_modules/@narumitw/pi-btw/src/menu.ts +78 -15
  59. package/node_modules/@narumitw/pi-btw/src/settings.ts +22 -2
  60. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
  61. package/node_modules/pi-lens/CHANGELOG.md +1004 -0
  62. package/node_modules/pi-lens/README.md +11 -3
  63. package/node_modules/pi-lens/config/ruff/core.toml +42 -0
  64. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +130 -27
  65. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +427 -0
  66. package/node_modules/pi-lens/dist/clients/agent-nudge.js +79 -16
  67. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +9 -3
  68. package/node_modules/pi-lens/dist/clients/atomic-write.js +9 -3
  69. package/node_modules/pi-lens/dist/clients/bash-file-access.js +285 -8
  70. package/node_modules/pi-lens/dist/clients/biome-client.js +176 -37
  71. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
  72. package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +119 -0
  73. package/node_modules/pi-lens/dist/clients/bootstrap.js +12 -1
  74. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +12 -3
  75. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +192 -0
  76. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +62 -6
  77. package/node_modules/pi-lens/dist/clients/bus-publish.js +11 -3
  78. package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
  79. package/node_modules/pi-lens/dist/clients/cascade-format.js +76 -2
  80. package/node_modules/pi-lens/dist/clients/cascade-types.js +9 -1
  81. package/node_modules/pi-lens/dist/clients/child-unref.js +54 -6
  82. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +76 -24
  83. package/node_modules/pi-lens/dist/clients/console-guard-install.js +16 -4
  84. package/node_modules/pi-lens/dist/clients/dead-code-client.js +249 -52
  85. package/node_modules/pi-lens/dist/clients/deadline-utils.js +8 -1
  86. package/node_modules/pi-lens/dist/clients/debug-handles.js +5 -0
  87. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +62 -13
  88. package/node_modules/pi-lens/dist/clients/dependency-checker.js +43 -9
  89. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +153 -37
  90. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
  91. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +10 -3
  92. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +165 -11
  93. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +325 -72
  94. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +7 -4
  95. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +5 -0
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +234 -18
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +187 -19
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +6 -3
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +11 -9
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +398 -0
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +11 -3
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +12 -7
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +18 -0
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +4 -0
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +16 -3
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +81 -41
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -0
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +23 -0
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +331 -55
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +38 -5
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +97 -19
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +14 -0
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +20 -0
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +22 -0
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +10 -0
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +18 -6
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +73 -12
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +488 -0
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +84 -0
  121. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +260 -27
  122. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +943 -93
  123. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +86 -11
  124. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +72 -0
  125. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +106 -0
  126. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +9 -0
  127. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -1
  128. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
  129. package/node_modules/pi-lens/dist/clients/disposition-publish.js +10 -3
  130. package/node_modules/pi-lens/dist/clients/eval-timestamp.js +17 -0
  131. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
  132. package/node_modules/pi-lens/dist/clients/extension-log.js +317 -3
  133. package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
  134. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +294 -0
  135. package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
  136. package/node_modules/pi-lens/dist/clients/fix-worklog.js +5 -1
  137. package/node_modules/pi-lens/dist/clients/format-events-publish.js +39 -8
  138. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +3 -2
  139. package/node_modules/pi-lens/dist/clients/formatters.js +500 -115
  140. package/node_modules/pi-lens/dist/clients/generation-guard.js +216 -0
  141. package/node_modules/pi-lens/dist/clients/git-guard.js +49 -21
  142. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
  143. package/node_modules/pi-lens/dist/clients/go-client.js +21 -39
  144. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +219 -10
  145. package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
  146. package/node_modules/pi-lens/dist/clients/host-ports.js +9 -1
  147. package/node_modules/pi-lens/dist/clients/installer/index.js +1119 -101
  148. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +58 -0
  149. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +715 -0
  150. package/node_modules/pi-lens/dist/clients/instance-reaper.js +643 -97
  151. package/node_modules/pi-lens/dist/clients/instance-registry.js +87 -17
  152. package/node_modules/pi-lens/dist/clients/jscpd-client.js +86 -15
  153. package/node_modules/pi-lens/dist/clients/knip-client.js +361 -24
  154. package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
  155. package/node_modules/pi-lens/dist/clients/language-profile.js +2 -0
  156. package/node_modules/pi-lens/dist/clients/latency-logger.js +487 -9
  157. package/node_modules/pi-lens/dist/clients/lazy-import.js +21 -0
  158. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -0
  159. package/node_modules/pi-lens/dist/clients/lens-events.js +56 -25
  160. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +16 -0
  161. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +45 -2
  162. package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +30 -4
  163. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +160 -20
  164. package/node_modules/pi-lens/dist/clients/lsp/client.js +1666 -148
  165. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +111 -0
  166. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
  167. package/node_modules/pi-lens/dist/clients/lsp/index.js +2496 -171
  168. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +215 -0
  169. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +146 -14
  170. package/node_modules/pi-lens/dist/clients/lsp/language.js +48 -4
  171. package/node_modules/pi-lens/dist/clients/lsp/server.js +517 -69
  172. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +22 -0
  173. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +43 -0
  174. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +172 -0
  175. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +21 -5
  176. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +61 -3
  177. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +422 -28
  178. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +30 -0
  179. package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +175 -0
  180. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +3 -2
  181. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +4 -0
  182. package/node_modules/pi-lens/dist/clients/mcp/session.js +39 -18
  183. package/node_modules/pi-lens/dist/clients/model-provider.js +53 -0
  184. package/node_modules/pi-lens/dist/clients/module-report.js +8 -0
  185. package/node_modules/pi-lens/dist/clients/opengrep-client.js +15 -1
  186. package/node_modules/pi-lens/dist/clients/package-manager.js +170 -14
  187. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +27 -0
  188. package/node_modules/pi-lens/dist/clients/path-utils.js +160 -0
  189. package/node_modules/pi-lens/dist/clients/pipeline.js +178 -30
  190. package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +37 -0
  191. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +17 -3
  192. package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +89 -22
  193. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +85 -15
  194. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +15 -3
  195. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +23 -2
  196. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +50 -2
  197. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +5 -0
  198. package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
  199. package/node_modules/pi-lens/dist/clients/project-snapshot.js +299 -0
  200. package/node_modules/pi-lens/dist/clients/quiet-window-config.js +47 -0
  201. package/node_modules/pi-lens/dist/clients/quiet-window.js +11 -25
  202. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +1 -1
  203. package/node_modules/pi-lens/dist/clients/read-guard.js +184 -10
  204. package/node_modules/pi-lens/dist/clients/resource-sampler.js +49 -17
  205. package/node_modules/pi-lens/dist/clients/reverse-deps.js +50 -11
  206. package/node_modules/pi-lens/dist/clients/review-graph/query.js +76 -4
  207. package/node_modules/pi-lens/dist/clients/run-duration.js +55 -0
  208. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +248 -13
  209. package/node_modules/pi-lens/dist/clients/runtime-context.js +112 -12
  210. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +472 -61
  211. package/node_modules/pi-lens/dist/clients/runtime-session.js +359 -13
  212. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
  213. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +269 -22
  214. package/node_modules/pi-lens/dist/clients/runtime-turn.js +948 -87
  215. package/node_modules/pi-lens/dist/clients/rust-client.js +21 -37
  216. package/node_modules/pi-lens/dist/clients/safe-spawn.js +220 -7
  217. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +161 -0
  218. package/node_modules/pi-lens/dist/clients/search-read-registration.js +34 -6
  219. package/node_modules/pi-lens/dist/clients/security-scan-client.js +224 -8
  220. package/node_modules/pi-lens/dist/clients/sg-runner.js +249 -37
  221. package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
  222. package/node_modules/pi-lens/dist/clients/smells-rollup.js +18 -11
  223. package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
  224. package/node_modules/pi-lens/dist/clients/startup-timing.js +26 -2
  225. package/node_modules/pi-lens/dist/clients/test-runner-client.js +574 -32
  226. package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
  227. package/node_modules/pi-lens/dist/clients/tool-policy.js +127 -20
  228. package/node_modules/pi-lens/dist/clients/tool-set-policy.js +76 -0
  229. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +75 -1
  230. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +769 -64
  231. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +11 -0
  232. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +90 -0
  233. package/node_modules/pi-lens/dist/clients/trivy-client.js +19 -1
  234. package/node_modules/pi-lens/dist/clients/warm-attach.js +17 -0
  235. package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
  236. package/node_modules/pi-lens/dist/clients/word-index.js +305 -33
  237. package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
  238. package/node_modules/pi-lens/dist/index.js +64677 -49484
  239. package/node_modules/pi-lens/dist/mcp/server.js +8 -2
  240. package/node_modules/pi-lens/dist/tools/activate-tools.js +17 -5
  241. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +9 -4
  242. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +5 -2
  243. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +469 -56
  244. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +190 -46
  245. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
  246. package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -1
  247. package/node_modules/pi-lens/docs/agent-guide.md +44 -14
  248. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +518 -501
  249. package/node_modules/pi-lens/docs/dispositions.md +21 -0
  250. package/node_modules/pi-lens/docs/features.md +33 -6
  251. package/node_modules/pi-lens/docs/globalconfig.md +14 -0
  252. package/node_modules/pi-lens/docs/language-coverage.md +71 -5
  253. package/node_modules/pi-lens/docs/mcp.md +2 -2
  254. package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
  255. package/node_modules/pi-lens/docs/settings.md +25 -1
  256. package/node_modules/pi-lens/docs/usage.md +24 -5
  257. package/node_modules/pi-lens/docs/word-index.md +35 -0
  258. package/node_modules/pi-lens/package.json +10 -6
  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 +22 -0
  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-conditional-empty-object-spread-js-test.yml +9 -0
  266. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-test.yml +9 -0
  267. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-dupe-class-members-test.yml +33 -0
  268. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-js-test.yml +7 -1
  269. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-test.yml +7 -1
  270. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-known-value-widening-test.yml +9 -0
  271. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml +216 -0
  272. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +9 -0
  273. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +9 -0
  274. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +9 -0
  275. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +9 -0
  276. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-return-value-in-generator-test.yml +12 -0
  277. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-runtime-typeof-test.yml +33 -0
  278. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-server-bind-wildcard-test.yml +9 -0
  279. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-shape-in-symbol-names-test.yml +13 -0
  280. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-js-test.yml +5 -1
  281. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-test.yml +5 -1
  282. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-laundering-test.yml +11 -0
  283. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-parameters-test.yml +12 -0
  284. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-returns-test.yml +16 -0
  285. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-any-test.yml +10 -0
  286. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-unknown-test.yml +8 -0
  287. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/redundant-unsafe-function-test.yml +35 -0
  288. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/require-safety-comment-for-as-unknown-as-test.yml +177 -0
  289. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ts-void-zero-test.yml +1 -0
  290. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member-js.yml +13 -2
  291. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member.yml +13 -2
  292. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +2 -0
  293. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-object-param.yml +60 -0
  294. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +66 -0
  295. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-compile-call.yml +63 -5
  296. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread-js.yml +21 -0
  297. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread.yml +29 -0
  298. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-dupe-class-members.yml +52 -8
  299. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html-js.yml +27 -2
  300. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html.yml +27 -2
  301. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-known-value-widening.yml +71 -0
  302. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-non-null-assertion.yml +316 -0
  303. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +7 -0
  304. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +29 -0
  305. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +30 -0
  306. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +41 -0
  307. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +42 -0
  308. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-return-value-in-generator.yml +22 -5
  309. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-runtime-typeof.yml +121 -0
  310. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-server-bind-wildcard.yml +23 -7
  311. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-shape-in-symbol-names.yml +68 -0
  312. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +41 -2
  313. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code.yml +41 -2
  314. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +32 -0
  315. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-parameters.yml +67 -0
  316. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-returns.yml +106 -0
  317. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-any.yml +50 -0
  318. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-unknown.yml +56 -0
  319. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +2 -0
  320. package/node_modules/pi-lens/rules/ast-grep-rules/rules/redundant-unsafe-function.yml +32 -0
  321. package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml +184 -0
  322. package/node_modules/pi-lens/rules/ast-grep-rules/rules/ts-void-zero.yml +5 -0
  323. package/node_modules/pi-lens/rules/ast-grep-rules/self-scan-baseline.json +5 -0
  324. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +132 -1
  325. package/node_modules/pi-lens/scripts/download-grammars.js +25 -0
  326. package/node_modules/pi-lens/scripts/grammars.lock.json +9 -0
  327. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +12 -11
  328. package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +22 -22
  329. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +87 -116
  330. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +170 -0
  331. package/node_modules/pi-lens/skills/pi-lens-write-tree-sitter-rule/SKILL.md +3 -1
  332. package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
  333. package/node_modules/pi-mcp-adapter/CHANGELOG.md +49 -0
  334. package/node_modules/pi-mcp-adapter/README.md +51 -6
  335. package/node_modules/pi-mcp-adapter/agent-dir.ts +12 -4
  336. package/node_modules/pi-mcp-adapter/cli.js +188 -5
  337. package/node_modules/pi-mcp-adapter/commands.ts +128 -22
  338. package/node_modules/pi-mcp-adapter/config.ts +28 -10
  339. package/node_modules/pi-mcp-adapter/direct-tools.ts +23 -19
  340. package/node_modules/pi-mcp-adapter/index.ts +219 -32
  341. package/node_modules/pi-mcp-adapter/init.ts +36 -4
  342. package/node_modules/pi-mcp-adapter/lifecycle.ts +315 -24
  343. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +39 -6
  344. package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +387 -0
  345. package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +27 -3
  346. package/node_modules/pi-mcp-adapter/mcp-code.ts +4 -0
  347. package/node_modules/pi-mcp-adapter/mcp-panel.ts +42 -13
  348. package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +2 -1
  349. package/node_modules/pi-mcp-adapter/metadata-cache.ts +46 -25
  350. package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
  351. package/node_modules/pi-mcp-adapter/package.json +4 -1
  352. package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
  353. package/node_modules/pi-mcp-adapter/request-headers-command.ts +330 -0
  354. package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
  355. package/node_modules/pi-mcp-adapter/server-manager.ts +145 -2
  356. package/node_modules/pi-mcp-adapter/session-recovery.ts +7 -0
  357. package/node_modules/pi-mcp-adapter/tool-approval.ts +15 -2
  358. package/node_modules/pi-mcp-adapter/tool-metadata.ts +38 -18
  359. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
  360. package/node_modules/pi-mcp-adapter/types.ts +95 -10
  361. package/node_modules/pi-mcp-adapter/ui-server.ts +18 -16
  362. package/node_modules/pi-mcp-adapter/utils.ts +70 -0
  363. package/node_modules/pi-web-access/CHANGELOG.md +37 -0
  364. package/node_modules/pi-web-access/README.md +38 -14
  365. package/node_modules/pi-web-access/anysearch.ts +4 -2
  366. package/node_modules/pi-web-access/auth-fetch.ts +148 -0
  367. package/node_modules/pi-web-access/brave.ts +16 -4
  368. package/node_modules/pi-web-access/chrome-cookies.ts +110 -23
  369. package/node_modules/pi-web-access/curator-page.ts +8 -3
  370. package/node_modules/pi-web-access/curator-server.ts +5 -1
  371. package/node_modules/pi-web-access/exa.ts +18 -7
  372. package/node_modules/pi-web-access/extract.ts +134 -37
  373. package/node_modules/pi-web-access/fetch-params.ts +17 -3
  374. package/node_modules/pi-web-access/firecrawl.ts +172 -12
  375. package/node_modules/pi-web-access/gemini-search.ts +33 -7
  376. package/node_modules/pi-web-access/index.ts +160 -104
  377. package/node_modules/pi-web-access/package.json +2 -2
  378. package/node_modules/pi-web-access/page-query.ts +4 -2
  379. package/node_modules/pi-web-access/parallel-mcp.ts +249 -0
  380. package/node_modules/pi-web-access/parallel.ts +2 -2
  381. package/node_modules/pi-web-access/query-rewrite.ts +51 -0
  382. package/node_modules/pi-web-access/serper.ts +211 -0
  383. package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
  384. package/node_modules/pi-web-access/summary-review.ts +51 -23
  385. package/node_modules/pi-web-access/tavily.ts +16 -4
  386. package/node_modules/pi-web-access/utils.ts +87 -0
  387. package/node_modules/pi-web-access/valyu.ts +199 -0
  388. package/node_modules/pi-web-access/youtube-extract.ts +2 -2
  389. package/package.json +13 -13
@@ -1,6 +1,8 @@
1
1
  id: no-win32-isabsolute-for-qualification
2
2
  language: TypeScript
3
3
  severity: warning
4
+ metadata:
5
+ category: pi-lens-self-scan
4
6
  message: "Use isFullyQualified for path qualification instead of win32.isAbsolute"
5
7
  note: |
6
8
  Qualification must follow the input path's shape. Use clients/path-utils.ts
@@ -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
+ }
@@ -12,6 +12,7 @@
12
12
  * ~/.pi-lens/actionable-warnings*.log JSONL advisory pipeline (inject/suppress)
13
13
  * ~/.pi-lens/ast-grep-tools*.log JSONL MCP ast-grep search/replace telemetry
14
14
  * ~/.pi-lens/logs/*.jsonl JSONL diagnostic findings
15
+ * ~/.pi-lens/projects/<slug>/worklog.jsonl JSONL fix worklog (rule/tool/model/provider, #1448)
15
16
  */
16
17
 
17
18
  import fs from "node:fs";
@@ -69,6 +70,7 @@ async function main() {
69
70
  analyzeSessionStart(files.sessionStart, state),
70
71
  analyzeActionableWarnings(files.actionableWarnings, state),
71
72
  analyzeAstGrepTools(files.astGrepTools, state),
73
+ analyzeWorklog(files.worklog, state),
72
74
  ]);
73
75
 
74
76
  const report = buildReport(state);
@@ -139,6 +141,13 @@ function discoverLogFiles(logRoot, archived) {
139
141
  .filter((name) => name.endsWith(".jsonl"))
140
142
  .map((name) => path.join(logsDir, name));
141
143
 
144
+ // worklog.jsonl lives per-project under projects/<slug>/ (getProjectDataDir),
145
+ // not at the log root — walk one level to find every project's file (#1448).
146
+ const projectsDir = path.join(logRoot, "projects");
147
+ const worklogs = safeReaddir(projectsDir)
148
+ .map((slug) => path.join(projectsDir, slug, "worklog.jsonl"))
149
+ .filter((file) => fs.existsSync(file));
150
+
142
151
  const byPrefix = (prefix) =>
143
152
  allRootFiles.filter((file) => {
144
153
  const base = path.basename(file);
@@ -156,6 +165,7 @@ function discoverLogFiles(logRoot, archived) {
156
165
  actionableWarnings: byPrefix("actionable-warnings"),
157
166
  astGrepTools: byPrefix("ast-grep-tools"),
158
167
  diagnostics: dailyLogs,
168
+ worklog: worklogs,
159
169
  };
160
170
  }
161
171
 
@@ -192,6 +202,13 @@ function createState(files) {
192
202
  aborted: 0,
193
203
  timedOutSweeps: 0,
194
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(),
195
212
  sweeps: [],
196
213
  progress: [],
197
214
  },
@@ -263,6 +280,14 @@ function createState(files) {
263
280
  errors: [],
264
281
  slow: [],
265
282
  },
283
+ worklog: {
284
+ // key: "<rule>||<model>" (model "" when the entry predates #1448 or the
285
+ // runtime didn't know it) -> { total, autoFixed }
286
+ byRuleModel: new Map(),
287
+ byModel: counter(),
288
+ byModelAutoFixed: counter(),
289
+ byProvider: counter(),
290
+ },
266
291
  };
267
292
  }
268
293
 
@@ -349,6 +374,27 @@ async function analyzeLatency(files, state) {
349
374
  if (timedOut > 0) {
350
375
  ws.timedOutSweeps += 1;
351
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
+ }
352
398
  state.smellTotals.inc("lsp-workspace-file-timeouts");
353
399
  pushTop(
354
400
  ws.sweeps,
@@ -737,6 +783,39 @@ async function analyzeAstGrepTools(files, state) {
737
783
  }
738
784
  }
739
785
 
786
+ /**
787
+ * Per-model rollup (#1448): rule × model counts and auto-fixed vs
788
+ * agent-required rates, from worklog.jsonl's optional `model`/`provider`
789
+ * fields. Entries predating #1448 (or written outside a live agent turn)
790
+ * have neither field — bucketed under the empty-string model/provider key so
791
+ * "unattributed" volume stays visible rather than silently dropped.
792
+ */
793
+ async function analyzeWorklog(files, state) {
794
+ for (const file of files) {
795
+ await forEachJsonLine(file, "worklog", state, (entry) => {
796
+ const ts = dateOf(entry.timestamp);
797
+ if (!inWindow(ts)) return;
798
+ state.seen.inc("worklog");
799
+ const rule = entry.rule ?? "unknown";
800
+ const model = entry.model ?? "";
801
+ const provider = entry.provider ?? "";
802
+ const key = `${rule}||${model}`;
803
+ const row = state.worklog.byRuleModel.get(key) ?? {
804
+ rule,
805
+ model,
806
+ total: 0,
807
+ autoFixed: 0,
808
+ };
809
+ row.total += 1;
810
+ if (entry.autoFixed) row.autoFixed += 1;
811
+ state.worklog.byRuleModel.set(key, row);
812
+ state.worklog.byModel.inc(model || "(unknown)");
813
+ if (entry.autoFixed) state.worklog.byModelAutoFixed.inc(model || "(unknown)");
814
+ state.worklog.byProvider.inc(provider || "(unknown)");
815
+ });
816
+ }
817
+ }
818
+
740
819
  async function forEachJsonLine(file, bucket, state, visitor) {
741
820
  await forEachLine(file, async (line) => {
742
821
  if (!line.trim()) return;
@@ -1166,11 +1245,21 @@ function buildReport(state) {
1166
1245
  "Full LSP workspace sweeps that logged a start but never a completion (hang/kill signature — the 8h-hang class #383 hardened)",
1167
1246
  ws.progress.slice(0, limit),
1168
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(", ");
1169
1257
  addSmell(
1170
1258
  smells,
1171
1259
  "lsp-workspace-file-timeouts",
1172
1260
  smellCount("lsp-workspace-file-timeouts"),
1173
- `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}` : ""),
1174
1263
  ws.sweeps.slice(0, limit),
1175
1264
  );
1176
1265
 
@@ -1206,6 +1295,11 @@ function buildReport(state) {
1206
1295
  aborted: ws.aborted,
1207
1296
  timedOutSweeps: ws.timedOutSweeps,
1208
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(),
1209
1303
  },
1210
1304
  },
1211
1305
  cascade: {
@@ -1259,6 +1353,17 @@ function buildReport(state) {
1259
1353
  errors: state.astGrep.errors.slice(0, limit),
1260
1354
  slow: state.astGrep.slow.slice(0, limit),
1261
1355
  },
1356
+ worklog: {
1357
+ byModel: state.worklog.byModel.top(limit * 2),
1358
+ byProvider: state.worklog.byProvider.top(limit * 2),
1359
+ byRuleModel: [...state.worklog.byRuleModel.values()]
1360
+ .map((row) => ({
1361
+ ...row,
1362
+ autoFixedRate: row.total ? row.autoFixed / row.total : 0,
1363
+ }))
1364
+ .sort((a, b) => b.total - a.total)
1365
+ .slice(0, limit * 3),
1366
+ },
1262
1367
  };
1263
1368
  }
1264
1369
 
@@ -1396,7 +1501,33 @@ function printReport(report) {
1396
1501
  console.log(
1397
1502
  ` started=${ws.started} completed=${ws.completed} incomplete=${ws.incomplete} aborted=${ws.aborted} fileTimeouts=${ws.timedOutFilesTotal} (in ${ws.timedOutSweeps} sweeps)`,
1398
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
+ }
1399
1513
  }
1514
+ const wl = report.worklog;
1515
+ if (wl && (wl.byModel.length || wl.byRuleModel.length)) {
1516
+ console.log("\nWorklog per-model rollup (#1448)");
1517
+ console.log(
1518
+ ` by model: ${wl.byModel.map((x) => `${x.key}=${x.count}`).join(", ")}`,
1519
+ );
1520
+ if (wl.byProvider.length)
1521
+ console.log(
1522
+ ` by provider: ${wl.byProvider.map((x) => `${x.key}=${x.count}`).join(", ")}`,
1523
+ );
1524
+ console.log(" rule × model (auto-fixed vs agent-required):");
1525
+ for (const row of wl.byRuleModel.slice(0, limit))
1526
+ console.log(
1527
+ ` ${String(row.total).padStart(5)} ${row.rule} [${row.model || "(unknown)"}] autoFixed=${row.autoFixed} (${(row.autoFixedRate * 100).toFixed(0)}%)`,
1528
+ );
1529
+ }
1530
+
1400
1531
  const timeouts = Object.entries(report.latency.phaseTimeouts ?? {});
1401
1532
  if (timeouts.length) {
1402
1533
  console.log("\nPhase timeouts");
@@ -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
  }
@@ -52,12 +52,17 @@ Use `$$$` when you don't need the captured value; `$$$NAME` when you do.
52
52
 
53
53
  Use these instead of writing raw YAML:
54
54
 
55
- | Parameter | What it does |
56
- |---|---|
57
- | `insideKind` | Only match inside an ancestor of this node kind |
58
- | `hasKind` | Only match nodes that contain a descendant of this kind |
59
- | `follows` | Only match nodes preceded by a sibling matching this pattern |
60
- | `precedes` | Only match nodes followed by a sibling matching this pattern |
55
+ | Parameter | Tool | What it does |
56
+ |---|---|---|
57
+ | `insideKind` | both | Only match inside an ancestor of this node kind (searches ALL ancestors, `stopBy: end`) |
58
+ | `hasKind` | both | Only match nodes whose **immediate child** has this kind (`stopBy: neighbor` — NOT recursive) |
59
+ | `hasDescendantKind` | both | Only match nodes containing this kind **anywhere in their descendants** (`stopBy: end`) — use this instead of `hasKind` when the target isn't a direct child |
60
+ | `follows` | both | Only match nodes preceded by a sibling matching this pattern |
61
+ | `precedes` | both | Only match nodes followed by a sibling matching this pattern |
62
+
63
+ `hasKind` and `hasDescendantKind` are mutually exclusive on both tools — combining them errors.
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.
61
66
 
62
67
  ```
63
68
  # console.log only inside functions
@@ -152,13 +157,9 @@ Use these as starting points, then scope `paths` tightly.
152
157
 
153
158
  | Task | Pattern / params |
154
159
  |---|---|
155
- | Find pi lifecycle handlers | `pattern: pi.on($EVENT, $HANDLER)` |
156
- | Find timers | `pattern: setTimeout($CALLBACK, $$$REST)` or `setInterval($CALLBACK, $$$REST)` |
157
- | Find immediate/deferred work | `pattern: setImmediate($CALLBACK)` |
158
- | Find promise callbacks | `pattern: $PROMISE.then($CALLBACK)` / `.catch($CALLBACK)` / `.finally($CALLBACK)` |
159
160
  | Find object-literal function dependency by name | `pattern: { resetLSPService: $FN, $$$REST }` |
160
- | Find fire-and-forget async calls | `pattern: void $CALL` |
161
161
  | Find empty catches | `pattern: try { $$$BODY } catch ($ERR) { }` |
162
+ | Find fire-and-forget async calls | `pattern: void $CALL` |
162
163
 
163
164
  For lifecycle bugs, search first, then use the returned `details.matchLocations[].readSlice` handle for bounded context.
164
165
 
@@ -13,39 +13,39 @@ Use `lsp_diagnostics` before builds/tests or after touching several files:
13
13
 
14
14
  | Need | Tool call |
15
15
  |---|---|
16
- | Check one file | `lsp_diagnostics({ filePath: "src/file.ts" })` |
17
- | Check a folder | `lsp_diagnostics({ filePath: "src/", severity: "error" })` |
18
- | Check exact touched files | `lsp_diagnostics({ filePaths: ["src/a.ts", "src/b.ts"], concurrency: 8 })` |
19
- | Slow server (Rust, Java) | `lsp_diagnostics({ filePaths: files, waitMs: 2000 })` |
20
- | Include warnings | `lsp_diagnostics({ filePaths: files, severity: "all" })` |
16
+ | Check one file | `lsp_diagnostics({ path: "src/file.ts" })` |
17
+ | Check a folder | `lsp_diagnostics({ path: "src/", severity: "error" })` |
18
+ | Check exact touched files | `lsp_diagnostics({ paths: ["src/a.ts", "src/b.ts"], concurrency: 8 })` |
19
+ | Slow server (Rust, Java) | `lsp_diagnostics({ paths: files, waitMs: 2000 })` |
20
+ | Include warnings | `lsp_diagnostics({ paths: files, severity: "all" })` |
21
21
 
22
- Prefer explicit `filePaths` batches after multi-file edits — bounded concurrency, no unrelated directory noise.
22
+ Prefer explicit `paths` batches after multi-file edits — bounded concurrency, no unrelated directory noise.
23
23
 
24
24
  ## Navigation (Code Intelligence)
25
25
 
26
26
  | Question | Operation | Parameters |
27
27
  |---|---|---|
28
- | Where is this defined? | `definition` | filePath, line, character |
29
- | Where is this symbol's *type* defined? | `typeDefinition` | filePath, line, character |
30
- | Where is this declared (vs defined)? | `declaration` | filePath, line, character |
31
- | Find all usages | `references` | filePath, line, character |
32
- | What type is this? | `hover` | filePath, line, character |
33
- | Call signature | `signatureHelp` | filePath, line, character (at arg position) |
34
- | Symbols in this file | `documentSymbol` | filePath |
35
- | Find symbol across project | `workspaceSymbol` | query + filePath (strongly recommended) |
36
- | Quick fixes available | `codeAction` | filePath, line, character, endLine, endCharacter |
37
- | Rename symbol safely | `rename` | filePath, line, character, newName |
38
- | Who implements this? | `implementation` | filePath, line, character |
39
- | Who calls this function? | `prepareCallHierarchy` → `incomingCalls` | filePath, line, character |
40
- | What does this call? | `prepareCallHierarchy` → `outgoingCalls` | filePath, line, character |
41
- | What commands does the server offer? | `capabilities` | (optional filePath) — lists advertised commands |
28
+ | Where is this defined? | `definition` | path, line, character |
29
+ | Where is this symbol's *type* defined? | `typeDefinition` | path, line, character |
30
+ | Where is this declared (vs defined)? | `declaration` | path, line, character |
31
+ | Find all usages | `references` | path, line, character |
32
+ | What type is this? | `hover` | path, line, character |
33
+ | Call signature | `signatureHelp` | path, line, character (at arg position) |
34
+ | Symbols in this file | `documentSymbol` | path |
35
+ | Find symbol across project | `workspaceSymbol` | query + path (strongly recommended) |
36
+ | Quick fixes available | `codeAction` | path, line, character, endLine, endCharacter |
37
+ | Rename symbol safely | `rename` | path, line, character, newName |
38
+ | Who implements this? | `implementation` | path, line, character |
39
+ | Who calls this function? | `prepareCallHierarchy` → `incomingCalls` | path, line, character |
40
+ | What does this call? | `prepareCallHierarchy` → `outgoingCalls` | path, line, character |
41
+ | What commands does the server offer? | `capabilities` | (optional path) — lists advertised commands |
42
42
  | Run a server command (e.g. organize imports) | `executeCommand` | command (+ commandArguments); dry-run unless `apply:true` |
43
43
 
44
44
  ## Call Hierarchy Pattern
45
45
 
46
46
  ```
47
47
  // Step 1
48
- lsp_navigation(operation="prepareCallHierarchy", filePath="src/api.ts", line=42, character=10)
48
+ lsp_navigation(operation="prepareCallHierarchy", path="src/api.ts", line=42, character=10)
49
49
  // → returns callHierarchyItem
50
50
 
51
51
  // Step 2
@@ -56,7 +56,7 @@ lsp_navigation(operation="outgoingCalls", callHierarchyItem=<item from step 1>)
56
56
  ## Operational Notes
57
57
 
58
58
  - **`definition` returns nothing?** The file may not be open/indexed yet. Read it first, then retry.
59
- - **`workspaceSymbol` empty?** Always pass `filePath`. Unscoped queries are best-effort and frequently return nothing. If TypeScript returns "No Project", open the scoped file first.
59
+ - **`workspaceSymbol` empty?** Always pass `path`. Unscoped queries are best-effort and frequently return nothing. If TypeScript returns "No Project", open the scoped file first.
60
60
  - **`references`** — query from the *definition site* for full cross-file coverage; usage-site queries can be partial.
61
61
  - **`signatureHelp`** — only valid at call-site argument positions; declaration positions return empty.
62
62
  - **`workspaceDiagnostics`** — tracked push snapshot only, not an active check. Use `lsp_diagnostics` when you need fresh results.