@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,22 +1,97 @@
1
+ import { LEDGER_FIELD_MAX } from "../../../ledger-bounds.js";
2
+ /**
3
+ * The first non-empty line of a tool's output, bounded.
4
+ *
5
+ * Replaces six hand-rolled copies that spelled the same idea two ways —
6
+ * `text.trim().split("\n")[0]` and `(text ?? "").trim().split("\n")[0] ||
7
+ * fallback` — with differing (or absent) length caps. Two behaviours the
8
+ * copies got wrong and this does not: a leading blank line no longer yields an
9
+ * empty "first line", and `\r\n` output no longer keeps its carriage return.
10
+ *
11
+ * Returns `""` when the text is empty or all-whitespace, so callers keep using
12
+ * `firstOutputLine(x) || fallback`.
13
+ */
14
+ export function firstOutputLine(text, max = LEDGER_FIELD_MAX) {
15
+ for (const line of String(text ?? "").split(/\r?\n/)) {
16
+ const trimmed = line.trim();
17
+ if (!trimmed)
18
+ continue;
19
+ return trimmed.length > max ? `${trimmed.slice(0, max)}…` : trimmed;
20
+ }
21
+ return "";
22
+ }
23
+ /**
24
+ * Decide whether a tool ran, and if not, why (#1816).
25
+ *
26
+ * The defect this closes (the #1736 class): a runner that reads only its
27
+ * parsed diagnostics reports a CLEAN file whenever the parse yields nothing —
28
+ * including when the tool exited non-zero on an unknown flag, was killed by a
29
+ * signal, or never spawned at all. An empty result must distinguish clean from
30
+ * errored.
31
+ *
32
+ * Classification order, most specific first:
33
+ * 1. `result.error` or a signal — the process never completed. `did-not-run`.
34
+ * 2. `status === null` with no error — no exit status ever arrived, so no
35
+ * analysis can be claimed. `did-not-run`.
36
+ * 3. `reportMissing` — an artifact tool wrote no report. Nonzero exit means
37
+ * `report-missing`; exit 0 means a genuinely clean run that had nothing
38
+ * to write.
39
+ * 4. A nonzero status outside the caller's declared `ran` table.
40
+ * `rejected-invocation`.
41
+ * 5. A nonzero status with nothing to parse. `did-not-run` — a tool that
42
+ * analysed the file says SOMETHING, so silence plus failure is evidence
43
+ * it never got that far.
44
+ * Everything else ran.
45
+ *
46
+ * Note what is deliberately NOT a non-ran path: a nonzero status WITH output
47
+ * and no contradicting table. Most linters exit non-zero precisely because
48
+ * they found something, and their findings are on stdout.
49
+ */
50
+ export function classifyRunOutcome(input) {
51
+ const { result, exitCodes, reportMissing } = input;
52
+ const status = result.status ?? null;
53
+ const signal = result.signal ?? null;
54
+ const output = input.output ?? result.stdout;
55
+ const base = {
56
+ status,
57
+ signal,
58
+ firstOutputLine: firstOutputLine(result.stderr) ||
59
+ firstOutputLine(result.stdout) ||
60
+ firstOutputLine(result.error?.message),
61
+ };
62
+ if (result.error || signal)
63
+ return { kind: "did-not-run", ...base };
64
+ if (status === null)
65
+ return { kind: "did-not-run", ...base };
66
+ if (reportMissing) {
67
+ return status === 0
68
+ ? { kind: "ran", ...base }
69
+ : { kind: "report-missing", ...base };
70
+ }
71
+ if (status !== 0 && exitCodes && !exitCodes.ran.includes(status)) {
72
+ return { kind: "rejected-invocation", ...base };
73
+ }
74
+ if (status !== 0 && !output?.trim()) {
75
+ return { kind: "did-not-run", ...base };
76
+ }
77
+ return { kind: "ran", ...base };
78
+ }
1
79
  /**
2
80
  * True when a tool both failed and produced nothing to parse — it never got as
3
81
  * far as linting the file. Callers map this to `skipped`, never `succeeded`.
4
82
  *
5
- * Guarding on `result.error` alone covers only half of it: safe-spawn sets
6
- * `error` for spawn/timeout/signal failures and resolves a NORMAL exit with no
7
- * `error` at any status (see `SpawnResult.failure` "nonzero exit statuses are
8
- * not spawn failures"). An unknown subcommand, a rejected flag, or a config
9
- * that fails to load exits non-zero with the message on stderr and an empty
10
- * stdout, so an `error`-only guard falls through, parses "" into zero
11
- * diagnostics, and reports a clean file that nothing ever checked.
12
- *
13
- * Tools that exit non-zero *because* they found something are unaffected: their
14
- * findings are on stdout, so the output half of the test is false.
83
+ * Kept as its own export because callers outside the dispatch runners use it
84
+ * (`dead-code-client.ts`, `knip-client.ts`). It now DELEGATES to
85
+ * `classifyRunOutcome` rather than restating the rule, but keeps its exact
86
+ * historical semantics: the `!output.trim()` conjunct stays here so a spawn
87
+ * error that still produced partial output keeps reaching the parser, which is
88
+ * what today's callers depend on. `classifyRunOutcome` is the stricter,
89
+ * outcome-typed reading; migrate callers to it deliberately, not by accident.
15
90
  *
16
91
  * `output` defaults to stdout. Runners that parse stderr too pass the exact
17
92
  * string they are about to hand the parser, so "nothing to parse" means both
18
93
  * streams rather than just one.
19
94
  */
20
95
  export function spawnFailedWithNoOutput(result, output = result.stdout) {
21
- return (Boolean(result.error) || result.status !== 0) && !output?.trim();
96
+ return (classifyRunOutcome({ result, output }).kind !== "ran" && !output?.trim());
22
97
  }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * One wording for a tool that produced no usable result, and the runner gate
3
+ * that emits it to the degradation ledger (#1816).
4
+ */
5
+ import { incrementDegradationCount } from "../../../degradation-ledger.js";
6
+ import { truncateForLedger } from "../../../ledger-bounds.js";
7
+ import { classifyRunOutcome, firstOutputLine, } from "./spawn-outcome.js";
8
+ /**
9
+ * One wording for "this tool did not produce a usable result" (#1816).
10
+ *
11
+ * Before this, five reason builders spelled the same sentence five ways and
12
+ * twelve sites truncated with their own literal, and NONE of them named the
13
+ * signal — so a SIGKILLed tool read exactly like a clean exit 0. The wording
14
+ * here is fixed, the truncation is the ledger's own `LEDGER_FIELD_MAX` policy
15
+ * applied once at the end, and the signal is always named when present.
16
+ *
17
+ * Shape: `tool (k=v, k=v) <what happened> with <what was missing>: <detail>`
18
+ */
19
+ export function formatToolFailure(input) {
20
+ const entries = Object.entries(input.fields ?? {}).filter(([, value]) => value !== undefined && value !== "");
21
+ const identity = entries.length
22
+ ? `${input.tool} (${entries.map(([key, value]) => `${key}=${value}`).join(", ")})`
23
+ : input.tool;
24
+ // A signal is the strongest available explanation, so it displaces the exit
25
+ // status rather than sitting beside a `null` one.
26
+ const what = input.signal
27
+ ? `was killed by ${input.signal}`
28
+ : input.status === null
29
+ ? "did not run (spawn failure)"
30
+ : `exited ${input.status}`;
31
+ const missing = input.reportMissing ? "no report file" : "no output";
32
+ const detail = firstOutputLine(input.stderr) || firstOutputLine(input.stdout) || "no stderr";
33
+ return truncateForLedger(`${identity} ${what} with ${missing}: ${detail}`);
34
+ }
35
+ /**
36
+ * `formatToolFailure` fed straight from a `classifyRunOutcome` verdict — the
37
+ * path every migrated runner takes, so the outcome and the wording can never
38
+ * disagree about the status or the signal.
39
+ */
40
+ export function formatRunOutcomeFailure(tool, outcome, fields) {
41
+ return formatToolFailure({
42
+ tool,
43
+ status: outcome.status,
44
+ signal: outcome.signal,
45
+ stderr: outcome.firstOutputLine,
46
+ reportMissing: outcome.kind === "report-missing",
47
+ fields: { outcome: outcome.kind, ...fields },
48
+ });
49
+ }
50
+ /**
51
+ * The migrated runners' one call: classify the spawn, and when the tool did
52
+ * NOT run, record a bounded `runner-empty-result` row and hand back the
53
+ * `skipped` verdict. Returns `null` when the tool ran, meaning "carry on and
54
+ * parse".
55
+ *
56
+ * `incrementDegradationCount` keeps the record bounded — one latest-reason
57
+ * entry per (kind, subject) with an exact event tally — so a permanently
58
+ * broken tool costs one ledger row, not one per dispatched file. `subject` is
59
+ * the tool id, which is the discriminating identity a reader needs: WHICH tool
60
+ * is silently contributing nothing.
61
+ */
62
+ export function skipUnlessToolRan(tool, input, fields) {
63
+ const outcome = classifyRunOutcome(input);
64
+ if (outcome.kind === "ran")
65
+ return null;
66
+ incrementDegradationCount({
67
+ kind: "runner-empty-result",
68
+ subject: tool,
69
+ reason: formatRunOutcomeFailure(tool, outcome, fields),
70
+ });
71
+ return { status: "skipped", diagnostics: [], semantic: "none" };
72
+ }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Shared toolchain-availability lifecycle (#1476 Sonar follow-up).
3
+ *
4
+ * `candidate-probe.ts` factored out the PATH sweep the Go and Rust clients ran,
5
+ * but the LIFECYCLE around it stayed written twice: the transient-aware latch,
6
+ * the in-flight dedupe that keeps concurrent first-time callers to one sweep,
7
+ * the path memo, and the two `availability_decision` records. Two copies of one
8
+ * rule is how #1467's fix missed seven sites, so the rule lives here once and
9
+ * each client contributes only its configuration.
10
+ *
11
+ * Callers keep their own public method names — `isGoAvailableAsync`,
12
+ * `findCargoPathAsync` — because other modules call them; only the body moves.
13
+ */
14
+ import { createAvailabilityLatch, logAvailabilityDecision, } from "./availability-policy.js";
15
+ import { probeAvailabilityCandidates } from "./candidate-probe.js";
16
+ /**
17
+ * Own one toolchain's availability: sweep the platform candidate list, memoize
18
+ * the path that answered, and park the verdict behind the shared latch so a
19
+ * timed-out probe expires instead of latching "the toolchain is not installed"
20
+ * for the life of the process.
21
+ */
22
+ export function createToolchainAvailability(config) {
23
+ const availabilityLatch = createAvailabilityLatch();
24
+ let toolPath = null;
25
+ /** Classification of the candidate sweep, for the retry decision. */
26
+ let sweepSawTransient = false;
27
+ let sweepTransientCause = "probe-timeout";
28
+ let sweepHostStallMs = 0;
29
+ /** What the last classified candidate returned, for the decision record. */
30
+ let sweepEvidence;
31
+ let ensureInFlight = null;
32
+ async function findPath() {
33
+ if (toolPath)
34
+ return toolPath;
35
+ const paths = process.platform === "win32" ? config.windowsPaths : config.unixPaths;
36
+ const sweep = await probeAvailabilityCandidates(paths, config.probeArgs, config.budgetMs);
37
+ sweepSawTransient = sweep.sawTransient;
38
+ sweepTransientCause = sweep.transientCause;
39
+ sweepHostStallMs = sweep.hostStallMs;
40
+ sweepEvidence = sweep.evidence;
41
+ if (sweep.foundPath)
42
+ toolPath = sweep.foundPath;
43
+ return sweep.foundPath;
44
+ }
45
+ async function resolveAvailability() {
46
+ const startedAt = Date.now();
47
+ const found = (await findPath()) !== null;
48
+ if (found) {
49
+ availabilityLatch.noteAvailable();
50
+ config.log(`${config.label} found: ${toolPath}`);
51
+ logAvailabilityDecision({
52
+ tool: config.tool,
53
+ verdict: "available",
54
+ outcome: "success",
55
+ cause: "ok",
56
+ elapsedMs: Date.now() - startedAt,
57
+ latched: true,
58
+ hostStallMs: sweepHostStallMs,
59
+ budgetMs: config.budgetMs,
60
+ classifiedBy: "probe",
61
+ ...(sweepEvidence !== undefined && { evidence: sweepEvidence }),
62
+ });
63
+ return true;
64
+ }
65
+ // A timed-out version probe is evidence about this moment, not about
66
+ // whether the toolchain is installed; it expires instead of latching.
67
+ const outcome = sweepSawTransient ? "transient" : "missing";
68
+ const cause = sweepSawTransient ? sweepTransientCause : "not-found";
69
+ const retryAfterMs = availabilityLatch.noteUnavailable(outcome, cause);
70
+ logAvailabilityDecision({
71
+ tool: config.tool,
72
+ verdict: "unavailable",
73
+ outcome,
74
+ cause,
75
+ elapsedMs: Date.now() - startedAt,
76
+ latched: outcome !== "transient",
77
+ hostStallMs: sweepHostStallMs,
78
+ ...(retryAfterMs > 0 && { retryAfterMs }),
79
+ budgetMs: config.budgetMs,
80
+ // Derived from the sweep's own candidate probes, and carrying what the
81
+ // last of them returned (#1500).
82
+ classifiedBy: "probe",
83
+ ...(sweepEvidence !== undefined && { evidence: sweepEvidence }),
84
+ });
85
+ return false;
86
+ }
87
+ async function isAvailable() {
88
+ // `read()` returns null when the last verdict was transient and its
89
+ // cooldown expired, which re-enters the candidate sweep (#1476).
90
+ const memo = availabilityLatch.read();
91
+ if (memo !== null)
92
+ return memo;
93
+ // Now that a verdict can expire, concurrent callers arriving just after a
94
+ // cooldown must share ONE sweep rather than each spawning their own.
95
+ if (ensureInFlight)
96
+ return ensureInFlight;
97
+ ensureInFlight = resolveAvailability();
98
+ try {
99
+ return await ensureInFlight;
100
+ }
101
+ finally {
102
+ ensureInFlight = null;
103
+ }
104
+ }
105
+ return { findPath, isAvailable };
106
+ }
@@ -3,6 +3,7 @@ import * as path from "node:path";
3
3
  import { safeSpawnAsync } from "../../safe-spawn.js";
4
4
  import { PRIORITY } from "../priorities.js";
5
5
  import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
6
+ import { skipUnlessToolRan } from "./utils/tool-failure.js";
6
7
  const vale = createAvailabilityChecker("vale", ".exe");
7
8
  /**
8
9
  * Check for a .vale.ini config file in cwd or parent dirs.
@@ -89,6 +90,14 @@ const valeRunner = {
89
90
  return { status: "skipped", diagnostics: [], semantic: "none" };
90
91
  // Vale exits 0 even on findings, non-zero only on errors
91
92
  const result = await safeSpawnAsync(cmd, ["--output", "JSON", ctx.filePath], { cwd, timeout: 15000 });
93
+ // #1816: this runner read `result.status` zero times, so a Vale that
94
+ // rejected its config exited nonzero with an empty stdout, parsed to
95
+ // zero alerts, and reported clean prose. No exit-code table: Vale's
96
+ // nonzero codes vary with --minAlertLevel, so the conservative
97
+ // nothing-to-parse rule is the only safe discriminator here.
98
+ const skipped = skipUnlessToolRan("vale", { result });
99
+ if (skipped)
100
+ return skipped;
92
101
  const raw = result.stdout || "";
93
102
  const diagnostics = parseValeOutput(raw, ctx.filePath);
94
103
  if (diagnostics.length === 0) {
@@ -2,6 +2,7 @@ import { safeSpawnAsync } from "../../safe-spawn.js";
2
2
  import { getLinterPolicyForCwd, hasYamllintConfig } from "../../tool-policy.js";
3
3
  import { PRIORITY } from "../priorities.js";
4
4
  import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
5
+ import { skipUnlessToolRan } from "./utils/tool-failure.js";
5
6
  const yamllint = createAvailabilityChecker("yamllint", ".exe");
6
7
  export { hasYamllintConfig };
7
8
  function parseYamllintParsable(raw, filePath) {
@@ -55,7 +56,23 @@ const yamllintRunner = {
55
56
  const result = await safeSpawnAsync(cmd, ["-f", "parsable", ctx.filePath], {
56
57
  timeout: 15000,
57
58
  });
58
- const diagnostics = parseYamllintParsable(`${result.stdout ?? ""}${result.stderr ?? ""}`, ctx.filePath);
59
+ // #1816: this runner read `result.status` zero times, so a yamllint
60
+ // that rejected its config reported a clean YAML file.
61
+ //
62
+ // No exit-code table: yamllint returns 2 both for "warnings only" and
63
+ // for an argparse usage error, so declaring 2 a rejection would discard
64
+ // real warnings. The discriminator is the STREAM instead. `-f parsable`
65
+ // writes findings to stdout and nothing else; stderr carries usage text
66
+ // and tracebacks. So the gate judges "nothing to parse" on stdout alone,
67
+ // while the parser still reads both streams.
68
+ const raw = `${result.stdout ?? ""}${result.stderr ?? ""}`;
69
+ const skipped = skipUnlessToolRan("yamllint", {
70
+ result,
71
+ output: result.stdout,
72
+ });
73
+ if (skipped)
74
+ return skipped;
75
+ const diagnostics = parseYamllintParsable(raw, ctx.filePath);
59
76
  if (diagnostics.length === 0) {
60
77
  return { status: "succeeded", diagnostics: [], semantic: "none" };
61
78
  }
@@ -24,7 +24,9 @@ function parseZigOutput(raw, filePath) {
24
24
  line: Number.parseInt(lineStr, 10) || 1,
25
25
  column: Number.parseInt(colStr, 10) || 1,
26
26
  severity,
27
- semantic: severity === "error" ? "blocking" : "warning",
27
+ // `zig build-exe <file>` does not load build.zig module/import context.
28
+ // Its findings are useful evidence, but cannot prove a project blocker.
29
+ semantic: "warning",
28
30
  tool: "zig",
29
31
  rule: `zig-${level}`,
30
32
  fixable: false,
@@ -82,7 +84,7 @@ const zigCheckRunner = {
82
84
  return {
83
85
  status: hasErrors ? "failed" : "succeeded",
84
86
  diagnostics,
85
- semantic: hasErrors ? "blocking" : "warning",
87
+ semantic: "warning",
86
88
  };
87
89
  },
88
90
  };
@@ -24,7 +24,7 @@
24
24
  import { logBusEvent } from "./bus-events-logger.js";
25
25
  import { isBusPublishEnabled } from "./bus-publish.js";
26
26
  import { normalizeFilePath } from "./path-utils.js";
27
- import { createLiveBusEmitter, recordStaleBusFailure, } from "./live-bus-emitter.js";
27
+ import { createLiveBusEmitter, recordStaleBusFailure, resolveLiveBusEmitter, } from "./live-bus-emitter.js";
28
28
  export const BUS_DISPOSITION_EVENT = "pilens:diagnostic:disposition";
29
29
  export const BUS_DISPOSITION_VERSION = 1;
30
30
  const liveEmitter = createLiveBusEmitter();
@@ -67,8 +67,13 @@ export function publishDisposition(args) {
67
67
  }
68
68
  return;
69
69
  }
70
- const busEmit = liveEmitter.get();
71
- if (!busEmit) {
70
+ const resolution = resolveLiveBusEmitter(liveEmitter, () => ({
71
+ event: BUS_DISPOSITION_EVENT,
72
+ cwd: normalizeFilePath(args.cwd),
73
+ }));
74
+ if (resolution.outcome === "stale-session")
75
+ return;
76
+ if (resolution.outcome === "unwired") {
72
77
  if (!hasLoggedUnwired) {
73
78
  hasLoggedUnwired = true;
74
79
  logBusEvent({
@@ -79,6 +84,7 @@ export function publishDisposition(args) {
79
84
  }
80
85
  return;
81
86
  }
87
+ const busEmit = resolution.emit;
82
88
  try {
83
89
  const payload = {
84
90
  v: BUS_DISPOSITION_VERSION,
@@ -106,6 +112,7 @@ export function publishDisposition(args) {
106
112
  outcome: "emit_failed",
107
113
  cwd: normalizeFilePath(args.cwd),
108
114
  error: String(err),
115
+ ctxSource: resolution.ctxSource,
109
116
  });
110
117
  if (!hasLoggedFailure) {
111
118
  hasLoggedFailure = true;
@@ -0,0 +1,17 @@
1
+ import { performance } from "node:perf_hooks";
2
+ /**
3
+ * The moment pi-lens's module graph started evaluating, captured as this
4
+ * module's first statement (#1374 host-boot vs extension-eval split).
5
+ *
6
+ * This module is otherwise side-effect-free by design (#1434 S3d review): it
7
+ * does nothing but capture a timestamp. `clients/console-guard-install.ts`
8
+ * imports it as its FIRST import so the capture happens before the guard's
9
+ * own install work, and `clients/startup-timing.ts` imports it too, for the
10
+ * constant alone. Before this split, `startup-timing.ts` imported the
11
+ * constant FROM `console-guard-install.ts` — which meant importing
12
+ * startup-timing anywhere (e.g. a test measuring load time) silently
13
+ * installed the console guard as a side effect. Splitting the constant out
14
+ * means importing this module, or `startup-timing.ts`, never installs
15
+ * anything.
16
+ */
17
+ export const PI_LENS_EVAL_STARTED_MS = performance.now();
@@ -143,15 +143,38 @@ export function resetEventLoopMonitor() {
143
143
  windowStartCpuMs = cpuTotalMs();
144
144
  }
145
145
  /**
146
- * Decide whether a freeze is worth persisting to `latency.log`. Pure so the
147
- * threshold logic is testable without the (vitest-flaky) native histogram.
148
- * Logs only a *new* worst block (`maxMs > lastLoggedMs + deltaMs`) above a
149
- * floor (`minMs`), so a turn that froze worse than ever before is recorded
150
- * once — not the same growing max every turn.
146
+ * Decide whether THIS block beats the session's running high-water. Pure so
147
+ * the threshold logic is testable without the (vitest-flaky) native
148
+ * histogram. Requires `maxMs > lastLoggedMs + deltaMs` above a floor
149
+ * (`minMs`) so noise near the current max doesn't keep re-triggering the
150
+ * high-water bookkeeping.
151
+ *
152
+ * NOTE (#1723): this is no longer the logging gate — see
153
+ * `shouldLogLoopBlock` for that. This function now answers a narrower
154
+ * question ("is this a new session worst?", used for the `worstSoFar`
155
+ * metadata flag and for deciding whether to advance the high-water), because
156
+ * gating the LOG on it hid every sub-maximum block after a session's first
157
+ * large one, which made loop_block-vs-pull-timeout correlation undecidable.
151
158
  */
152
159
  export function shouldLogWorstBlock(maxMs, lastLoggedMs, minMs = 60, deltaMs = 25) {
153
160
  return maxMs >= minMs && maxMs > lastLoggedMs + deltaMs;
154
161
  }
162
+ /**
163
+ * Decide whether a block is worth persisting to `latency.log` AT ALL (#1723).
164
+ * Every block at or above the floor (`minMs`) qualifies — not only a new
165
+ * session worst — because a session's later blocks can be smaller than an
166
+ * early spike yet still be exactly the ones that starved an LSP pull
167
+ * (#1549/#1713) and are otherwise invisible to the correlation.
168
+ *
169
+ * Volume is bounded by CALL CADENCE, not by this gate: the `turn_end` caller
170
+ * invokes this at most once per turn (the histogram window is reset every
171
+ * turn), so the natural cap is one `loop_block` record per turn — a jittery
172
+ * session cannot flood the log because there is nowhere for a second sample
173
+ * to come from within the same turn.
174
+ */
175
+ export function shouldLogLoopBlock(maxMs, minMs = 60) {
176
+ return maxMs >= minMs;
177
+ }
155
178
  /** Test-only: stop and clear the monitor so cases don't leak into each other. */
156
179
  export function _stopEventLoopMonitorForTest() {
157
180
  histogram?.disable();