@herbertgao/pi-extensions 2026.8.6 → 2026.8.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (385) hide show
  1. package/README.md +8 -6
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +2 -2
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -2
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +19 -7
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +30 -9
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +320 -22
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +79 -17
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +27 -0
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +66 -17
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +41 -2
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +75 -6
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +7 -3
  14. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +64 -1
  15. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  16. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
  17. package/node_modules/@herbertgao/pi-subagents/README.md +30 -22
  18. package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +5 -5
  19. package/node_modules/@herbertgao/pi-subagents/package.json +7 -7
  20. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +7 -1
  21. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +48 -19
  22. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +17 -13
  23. package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +26 -2
  24. package/node_modules/@herbertgao/pi-subagents/src/index.ts +219 -40
  25. package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +101 -3
  26. package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +18 -4
  27. package/node_modules/@herbertgao/pi-subagents/src/settings.ts +99 -0
  28. package/node_modules/@herbertgao/pi-subagents/src/types.ts +22 -3
  29. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +51 -3
  30. package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +20 -2
  31. package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +21 -6
  32. package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
  33. package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +20 -0
  34. package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +5 -4
  35. package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +174 -100
  36. package/node_modules/@juicesharp/rpiv-ask-user-question/config.ts +25 -0
  37. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/configuration.md +13 -4
  38. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +5 -1
  39. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +10 -2
  40. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +10 -6
  41. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/tool-schema.md +11 -5
  42. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +5 -2
  43. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/zh.json +2 -2
  44. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +3 -2
  45. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +10 -0
  46. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +140 -97
  47. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +63 -28
  48. package/node_modules/@juicesharp/rpiv-ask-user-question/state/selectors/projections.ts +22 -15
  49. package/node_modules/@juicesharp/rpiv-ask-user-question/state/state-reducer.ts +11 -1
  50. package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
  51. package/node_modules/@juicesharp/rpiv-ask-user-question/tool/response-envelope.ts +11 -0
  52. package/node_modules/@juicesharp/rpiv-ask-user-question/tool/types.ts +11 -0
  53. package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/multi-select-view.ts +31 -17
  54. package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/preview/preview-block-renderer.ts +15 -6
  55. package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/wrapping-select.ts +15 -6
  56. package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +86 -38
  57. package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +76 -9
  58. package/node_modules/@narumitw/pi-btw/README.md +120 -111
  59. package/node_modules/@narumitw/pi-btw/dist/index.ts +2898 -0
  60. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +7 -0
  61. package/node_modules/@narumitw/pi-btw/package.json +10 -6
  62. package/node_modules/@narumitw/pi-btw/src/btw.ts +36 -40
  63. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +55 -10
  64. package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +390 -0
  65. package/node_modules/@narumitw/pi-btw/src/menu.ts +45 -2
  66. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
  67. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +44 -1856
  68. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
  69. package/node_modules/@pi-plugins/fast-mode/package.json +4 -6
  70. package/node_modules/pi-lens/CHANGELOG.md +999 -0
  71. package/node_modules/pi-lens/README.md +117 -3
  72. package/node_modules/pi-lens/config/ruff/core.toml +42 -0
  73. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +130 -27
  74. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +126 -13
  75. package/node_modules/pi-lens/dist/clients/agent-nudge.js +67 -11
  76. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +9 -3
  77. package/node_modules/pi-lens/dist/clients/atomic-write.js +9 -3
  78. package/node_modules/pi-lens/dist/clients/bash-file-access.js +381 -13
  79. package/node_modules/pi-lens/dist/clients/biome-client.js +61 -30
  80. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
  81. package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +129 -0
  82. package/node_modules/pi-lens/dist/clients/bootstrap.js +12 -1
  83. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +12 -3
  84. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +206 -0
  85. package/node_modules/pi-lens/dist/clients/cache-observability.js +353 -76
  86. package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
  87. package/node_modules/pi-lens/dist/clients/cascade-format.js +20 -1
  88. package/node_modules/pi-lens/dist/clients/cascade-types.js +9 -1
  89. package/node_modules/pi-lens/dist/clients/child-unref.js +54 -6
  90. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +76 -24
  91. package/node_modules/pi-lens/dist/clients/dead-code-client.js +123 -31
  92. package/node_modules/pi-lens/dist/clients/deadline-utils.js +8 -1
  93. package/node_modules/pi-lens/dist/clients/debug-handles.js +5 -0
  94. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +84 -14
  95. package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +155 -0
  96. package/node_modules/pi-lens/dist/clients/dependency-checker.js +25 -3
  97. package/node_modules/pi-lens/dist/clients/deps/pi-tui.js +8 -2
  98. package/node_modules/pi-lens/dist/clients/deps/typebox.js +8 -3
  99. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +147 -33
  100. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
  101. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +52 -2
  102. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +256 -88
  103. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +7 -4
  104. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +5 -0
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +234 -18
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +187 -19
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +6 -3
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +11 -9
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +398 -0
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +9 -6
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +11 -3
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +12 -7
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +18 -0
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +9 -7
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +8 -6
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +4 -0
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +16 -3
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +60 -53
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -2
  121. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +25 -2
  122. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +20 -5
  123. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +44 -11
  124. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +331 -55
  125. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +38 -5
  126. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +97 -19
  127. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +17 -8
  128. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +32 -4
  129. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +47 -3
  130. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +14 -4
  131. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +127 -28
  132. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +12 -7
  133. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +73 -12
  134. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +275 -13
  135. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +21 -6
  136. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +260 -27
  137. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +734 -64
  138. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +86 -11
  139. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +188 -0
  140. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +9 -0
  141. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +21 -10
  142. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -2
  143. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
  144. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
  145. package/node_modules/pi-lens/dist/clients/extension-log.js +22 -1
  146. package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
  147. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +316 -0
  148. package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
  149. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +3 -2
  150. package/node_modules/pi-lens/dist/clients/formatters.js +500 -115
  151. package/node_modules/pi-lens/dist/clients/generation-guard.js +216 -0
  152. package/node_modules/pi-lens/dist/clients/git-guard.js +31 -0
  153. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
  154. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +109 -9
  155. package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
  156. package/node_modules/pi-lens/dist/clients/host-ports.js +8 -0
  157. package/node_modules/pi-lens/dist/clients/installer/index.js +1114 -100
  158. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +58 -0
  159. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +715 -0
  160. package/node_modules/pi-lens/dist/clients/instance-reaper.js +643 -97
  161. package/node_modules/pi-lens/dist/clients/instance-registry.js +87 -17
  162. package/node_modules/pi-lens/dist/clients/jscpd-client.js +87 -8
  163. package/node_modules/pi-lens/dist/clients/knip-client.js +310 -10
  164. package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
  165. package/node_modules/pi-lens/dist/clients/language-profile.js +9 -2
  166. package/node_modules/pi-lens/dist/clients/latency-logger.js +440 -11
  167. package/node_modules/pi-lens/dist/clients/lazy-import.js +21 -0
  168. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -0
  169. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
  170. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +128 -8
  171. package/node_modules/pi-lens/dist/clients/lsp/client.js +1660 -164
  172. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +83 -1
  173. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
  174. package/node_modules/pi-lens/dist/clients/lsp/index.js +2423 -151
  175. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +215 -0
  176. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +146 -14
  177. package/node_modules/pi-lens/dist/clients/lsp/language.js +48 -4
  178. package/node_modules/pi-lens/dist/clients/lsp/server.js +277 -16
  179. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +22 -0
  180. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +43 -0
  181. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +79 -3
  182. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +43 -0
  183. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +422 -28
  184. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +30 -0
  185. package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +175 -0
  186. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +3 -2
  187. package/node_modules/pi-lens/dist/clients/mcp/session.js +10 -2
  188. package/node_modules/pi-lens/dist/clients/module-report.js +22 -1
  189. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +114 -23
  190. package/node_modules/pi-lens/dist/clients/opengrep-client.js +15 -1
  191. package/node_modules/pi-lens/dist/clients/package-manager.js +170 -14
  192. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +27 -0
  193. package/node_modules/pi-lens/dist/clients/path-utils.js +160 -0
  194. package/node_modules/pi-lens/dist/clients/pipeline.js +154 -33
  195. package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +37 -0
  196. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +17 -3
  197. package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +89 -22
  198. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +84 -14
  199. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +15 -3
  200. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +50 -2
  201. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +23 -9
  202. package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
  203. package/node_modules/pi-lens/dist/clients/project-report.js +62 -27
  204. package/node_modules/pi-lens/dist/clients/project-snapshot.js +299 -0
  205. package/node_modules/pi-lens/dist/clients/quiet-window-config.js +47 -0
  206. package/node_modules/pi-lens/dist/clients/quiet-window.js +11 -25
  207. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +8 -3
  208. package/node_modules/pi-lens/dist/clients/read-guard.js +253 -10
  209. package/node_modules/pi-lens/dist/clients/resource-sampler.js +49 -17
  210. package/node_modules/pi-lens/dist/clients/reverse-deps.js +50 -11
  211. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +194 -31
  212. package/node_modules/pi-lens/dist/clients/review-graph/query.js +52 -4
  213. package/node_modules/pi-lens/dist/clients/review-graph/revision-drift.js +21 -0
  214. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +6 -3
  215. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +96 -7
  216. package/node_modules/pi-lens/dist/clients/runtime-context.js +8 -1
  217. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +352 -45
  218. package/node_modules/pi-lens/dist/clients/runtime-session.js +373 -9
  219. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
  220. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +212 -79
  221. package/node_modules/pi-lens/dist/clients/runtime-turn.js +620 -67
  222. package/node_modules/pi-lens/dist/clients/safe-spawn.js +220 -7
  223. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +161 -0
  224. package/node_modules/pi-lens/dist/clients/search-read-registration.js +34 -6
  225. package/node_modules/pi-lens/dist/clients/security-scan-client.js +157 -24
  226. package/node_modules/pi-lens/dist/clients/session-event-guard.js +184 -0
  227. package/node_modules/pi-lens/dist/clients/sg-runner.js +116 -22
  228. package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
  229. package/node_modules/pi-lens/dist/clients/source-filter.js +6 -2
  230. package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
  231. package/node_modules/pi-lens/dist/clients/startup-scan.js +5 -2
  232. package/node_modules/pi-lens/dist/clients/startup-timing.js +19 -1
  233. package/node_modules/pi-lens/dist/clients/test-runner-client.js +151 -16
  234. package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
  235. package/node_modules/pi-lens/dist/clients/tool-policy.js +125 -20
  236. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +75 -1
  237. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +769 -64
  238. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +1 -0
  239. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +11 -0
  240. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +90 -0
  241. package/node_modules/pi-lens/dist/clients/trivy-client.js +19 -1
  242. package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
  243. package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
  244. package/node_modules/pi-lens/dist/index.js +61407 -48577
  245. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +476 -57
  246. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +132 -43
  247. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
  248. package/node_modules/pi-lens/docs/agent-guide.md +6 -1
  249. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +515 -506
  250. package/node_modules/pi-lens/docs/dispositions.md +21 -0
  251. package/node_modules/pi-lens/docs/features.md +19 -5
  252. package/node_modules/pi-lens/docs/globalconfig.md +3 -0
  253. package/node_modules/pi-lens/docs/language-coverage.md +71 -5
  254. package/node_modules/pi-lens/docs/mcp.md +2 -2
  255. package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
  256. package/node_modules/pi-lens/docs/settings.md +19 -1
  257. package/node_modules/pi-lens/docs/usage.md +1 -0
  258. package/node_modules/pi-lens/package.json +27 -10
  259. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-js-snapshot.yml +23 -0
  260. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-snapshot.yml +23 -0
  261. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/ts-void-zero-snapshot.yml +23 -0
  262. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-object-param-test.yml +16 -0
  263. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +15 -1
  264. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-compile-call-test.yml +29 -1
  265. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-dupe-class-members-test.yml +33 -0
  266. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-js-test.yml +7 -1
  267. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-test.yml +7 -1
  268. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-known-value-widening-test.yml +9 -0
  269. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml +216 -0
  270. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +2 -0
  271. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +2 -0
  272. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +2 -1
  273. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +2 -1
  274. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-return-value-in-generator-test.yml +12 -0
  275. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-runtime-typeof-test.yml +33 -0
  276. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-server-bind-wildcard-test.yml +9 -0
  277. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-shape-in-symbol-names-test.yml +13 -0
  278. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-js-test.yml +5 -1
  279. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-test.yml +5 -1
  280. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-parameters-test.yml +12 -0
  281. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-returns-test.yml +16 -0
  282. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-any-test.yml +10 -0
  283. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-unknown-test.yml +8 -0
  284. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/redundant-unsafe-function-test.yml +35 -0
  285. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/require-safety-comment-for-as-unknown-as-test.yml +177 -0
  286. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ts-void-zero-test.yml +1 -0
  287. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member-js.yml +13 -2
  288. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member.yml +13 -2
  289. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +2 -0
  290. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-object-param.yml +60 -0
  291. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +57 -12
  292. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-compile-call.yml +63 -5
  293. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-dupe-class-members.yml +52 -8
  294. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html-js.yml +27 -2
  295. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html.yml +27 -2
  296. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-known-value-widening.yml +71 -0
  297. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-non-null-assertion.yml +316 -0
  298. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +7 -0
  299. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +22 -2
  300. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +23 -2
  301. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +33 -5
  302. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +34 -8
  303. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-return-value-in-generator.yml +22 -5
  304. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-runtime-typeof.yml +121 -0
  305. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-server-bind-wildcard.yml +23 -7
  306. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-shape-in-symbol-names.yml +68 -0
  307. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +41 -2
  308. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code.yml +41 -2
  309. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +6 -1
  310. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-parameters.yml +67 -0
  311. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-returns.yml +106 -0
  312. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-any.yml +50 -0
  313. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-unknown.yml +56 -0
  314. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +2 -0
  315. package/node_modules/pi-lens/rules/ast-grep-rules/rules/redundant-unsafe-function.yml +32 -0
  316. package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml +184 -0
  317. package/node_modules/pi-lens/rules/ast-grep-rules/rules/ts-void-zero.yml +5 -0
  318. package/node_modules/pi-lens/rules/ast-grep-rules/self-scan-baseline.json +5 -0
  319. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +53 -1
  320. package/node_modules/pi-lens/scripts/download-grammars.js +25 -0
  321. package/node_modules/pi-lens/scripts/grammars.lock.json +9 -0
  322. package/node_modules/pi-lens/scripts/install-selftest.mjs +99 -11
  323. package/node_modules/pi-lens/scripts/lib/host-provided-deps.mjs +75 -0
  324. package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +285 -0
  325. package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +233 -0
  326. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +2 -0
  327. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +80 -3
  328. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +41 -0
  329. package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
  330. package/node_modules/pi-mcp-adapter/CHANGELOG.md +36 -0
  331. package/node_modules/pi-mcp-adapter/README.md +47 -5
  332. package/node_modules/pi-mcp-adapter/cli.js +163 -1
  333. package/node_modules/pi-mcp-adapter/commands.ts +128 -22
  334. package/node_modules/pi-mcp-adapter/config.ts +25 -7
  335. package/node_modules/pi-mcp-adapter/direct-tools.ts +5 -4
  336. package/node_modules/pi-mcp-adapter/index.ts +219 -32
  337. package/node_modules/pi-mcp-adapter/init.ts +36 -4
  338. package/node_modules/pi-mcp-adapter/lifecycle.ts +315 -24
  339. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +39 -6
  340. package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +387 -0
  341. package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +27 -3
  342. package/node_modules/pi-mcp-adapter/mcp-code.ts +4 -0
  343. package/node_modules/pi-mcp-adapter/mcp-panel.ts +42 -13
  344. package/node_modules/pi-mcp-adapter/metadata-cache.ts +32 -21
  345. package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
  346. package/node_modules/pi-mcp-adapter/package.json +3 -1
  347. package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
  348. package/node_modules/pi-mcp-adapter/request-headers-command.ts +31 -37
  349. package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
  350. package/node_modules/pi-mcp-adapter/server-manager.ts +140 -2
  351. package/node_modules/pi-mcp-adapter/session-recovery.ts +7 -0
  352. package/node_modules/pi-mcp-adapter/tool-approval.ts +15 -2
  353. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
  354. package/node_modules/pi-mcp-adapter/types.ts +2 -0
  355. package/node_modules/pi-mcp-adapter/ui-server.ts +18 -16
  356. package/node_modules/pi-mcp-adapter/utils.ts +70 -0
  357. package/node_modules/pi-web-access/CHANGELOG.md +37 -0
  358. package/node_modules/pi-web-access/README.md +32 -13
  359. package/node_modules/pi-web-access/anysearch.ts +4 -2
  360. package/node_modules/pi-web-access/brave.ts +16 -4
  361. package/node_modules/pi-web-access/chrome-cookies.ts +86 -15
  362. package/node_modules/pi-web-access/curator-page.ts +6 -3
  363. package/node_modules/pi-web-access/curator-server.ts +4 -1
  364. package/node_modules/pi-web-access/data-uri-sanitize.ts +406 -0
  365. package/node_modules/pi-web-access/exa.ts +18 -7
  366. package/node_modules/pi-web-access/extract.ts +40 -5
  367. package/node_modules/pi-web-access/firecrawl.ts +18 -2
  368. package/node_modules/pi-web-access/gemini-search.ts +16 -4
  369. package/node_modules/pi-web-access/github-extract.ts +65 -36
  370. package/node_modules/pi-web-access/index.ts +60 -61
  371. package/node_modules/pi-web-access/openai-search.ts +17 -6
  372. package/node_modules/pi-web-access/package.json +1 -1
  373. package/node_modules/pi-web-access/page-query.ts +4 -2
  374. package/node_modules/pi-web-access/parallel-mcp.ts +249 -0
  375. package/node_modules/pi-web-access/parallel.ts +2 -2
  376. package/node_modules/pi-web-access/pdf-extract.ts +18 -5
  377. package/node_modules/pi-web-access/query-rewrite.ts +51 -0
  378. package/node_modules/pi-web-access/serper.ts +211 -0
  379. package/node_modules/pi-web-access/ssrf-protection.ts +12 -2
  380. package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
  381. package/node_modules/pi-web-access/summary-review.ts +44 -22
  382. package/node_modules/pi-web-access/tavily.ts +16 -4
  383. package/node_modules/pi-web-access/utils.ts +87 -0
  384. package/node_modules/pi-web-access/valyu.ts +199 -0
  385. package/package.json +14 -14
@@ -0,0 +1,196 @@
1
+ /**
2
+ * Cascade neighbour-budget sizing (#1462).
3
+ *
4
+ * The flat neighbour cap (40) and the turn-end settle wait (5000 ms) were set in
5
+ * two different files with nothing relating them. Dogfood 2026-08-15 measured
6
+ * what that costs: n=50 cascades, median 30 ms, max 3.88 s at nbr=40 — and with
7
+ * a `reverse_deps_cache` refresh ahead of the graph build (2046 ms for
8
+ * `logger.ts`) the run overran the turn_end cap, so `cascade_settle_wait`
9
+ * returned `settled: 0` and the finding arrived a turn late.
10
+ *
11
+ * ## What a slow run actually costs
12
+ *
13
+ * It is NOT lost. `RuntimeCoordinator.settleCascadeRuns` re-parks a promise
14
+ * still in flight at the cap, `agent_settled` gives it a second and more
15
+ * generous drain (`cascade_carry_over_settle`, `quietWindowWaitMs`, 15 000 ms),
16
+ * and `beginTurn` deliberately keeps `_pendingCascadeRuns` so anything still
17
+ * running surfaces at a later turn_end — that is #1443, and pre-#450 these
18
+ * findings were always awaited. So the real trade is:
19
+ *
20
+ * full neighbour set, one turn late vs. a narrowed set, on time,
21
+ * with the remainder lost for good
22
+ *
23
+ * Narrowing is therefore only worth paying for when it genuinely converts a
24
+ * late run into an on-time one. That gives three zones, and the derivation
25
+ * below is exactly those three:
26
+ *
27
+ * fits the full walk still fits the on-time window — nothing to do
28
+ * narrowed the RESCUE BAND: the full walk no longer fits but a shorter
29
+ * one does, so trading the tail for on-time delivery buys
30
+ * something real
31
+ * past-rescue not even a floor-sized walk fits any more, so narrowing would
32
+ * drop neighbours permanently AND still miss the window. Keep
33
+ * the full budget and let the carry-over deliver it complete.
34
+ * This is the cold-session case: a fresh graph build measures up
35
+ * to ~19 s (see `runtime-coordinator.ts`'s carry-over note), and
36
+ * a floor-sized stub there is strictly worse than pre-#1462.
37
+ *
38
+ * One more guard, for the same reason. If the on-time window could not fit a
39
+ * full walk even at zero prelude, there is no LATE run to rescue — every
40
+ * cascade would be permanently downsized because a *wait* was configured small.
41
+ * That is a budget change wearing a timeout's clothes, so the derivation stands
42
+ * down entirely (`no-rescue-window`) and the flat cap applies. This is what
43
+ * keeps `PI_LENS_CASCADE_SETTLE_WAIT_MS` from doubling as a neighbour-count
44
+ * knob: at the 5000/100/40 defaults the band is a prelude of 1.0–4.5 s, and
45
+ * shrinking the wait to 1000 ms disables narrowing rather than capping every
46
+ * cascade at ~10 neighbours.
47
+ */
48
+ import { recordDegradationOnce } from "./degradation-ledger.js";
49
+ import { toPositiveFinite } from "./env-utils.js";
50
+ // The knobs only, never the scheduler — this module is arithmetic and has no
51
+ // business depending on a task registry to read two numbers (#1462 review N4).
52
+ // Note it buys nothing at load time: `runtime-config.js` below already reaches
53
+ // `pidusage` via `lens-config.js`.
54
+ import { isQuietWindowEnabled, quietWindowWaitMs, } from "./quiet-window-config.js";
55
+ import { RUNTIME_CONFIG } from "./runtime-config.js";
56
+ /**
57
+ * Bounded wait for the turn's deferred cascade computes (#450) to settle before
58
+ * they are merged at turn_end. A late compute is carried over, never dropped.
59
+ *
60
+ * `0` is a meaningful setting (never block turn_end), so this deliberately does
61
+ * NOT use `lazyEnvNumber` — that helper treats 0 as "unset" and would silently
62
+ * restore the 5000 ms default.
63
+ */
64
+ export function cascadeSettleWaitMs() {
65
+ const raw = Number(process.env.PI_LENS_CASCADE_SETTLE_WAIT_MS);
66
+ return Number.isFinite(raw) && raw >= 0 ? raw : 5000;
67
+ }
68
+ /** The budget floor, and the minimum any env override of the cap can produce. */
69
+ const MIN_NEIGHBOUR_BUDGET = RUNTIME_CONFIG.pipeline.cascadeMaxFiles;
70
+ /**
71
+ * The flat per-run cap: the most neighbours a cascade walks. Still the ceiling
72
+ * — the derivation below only ever narrows it, and only inside the rescue band.
73
+ */
74
+ const DEFAULT_NEIGHBOUR_BUDGET = 40;
75
+ export const CASCADE_NEIGHBOUR_BUDGET = Math.max(MIN_NEIGHBOUR_BUDGET, Number.parseInt(process.env.PI_LENS_CASCADE_NEIGHBOUR_BUDGET ?? "40", 10) ||
76
+ DEFAULT_NEIGHBOUR_BUDGET);
77
+ /**
78
+ * True when `PI_LENS_CASCADE_NEIGHBOUR_BUDGET` moved the ceiling away from the
79
+ * default (#1462 review F-E). Raising it far enough can push
80
+ * `ceiling * perNeighbourMs` past the settle window, so EVERY cascade reads
81
+ * `no-rescue-window` — the whole derivation disarmed by a cap change nobody
82
+ * meant as a timeout change. Read once at load, same lifetime as the constant
83
+ * it describes.
84
+ */
85
+ const NEIGHBOUR_BUDGET_OVERRIDDEN = process.env.PI_LENS_CASCADE_NEIGHBOUR_BUDGET !== undefined &&
86
+ CASCADE_NEIGHBOUR_BUDGET !== DEFAULT_NEIGHBOUR_BUDGET;
87
+ /**
88
+ * Marginal wall-clock cost of one more neighbour in the walk, in ms. Calibrated
89
+ * on the 2026-08-15 dogfood tail: 3.88 s at nbr=40 and 3.71 s at nbr=38, both
90
+ * ~97 ms per neighbour. Touches fan out in parallel, so this is the observed
91
+ * marginal cost under LSP contention, not one touch's own latency.
92
+ *
93
+ * It is an ESTIMATE, and the derivation is sensitive to it: if the true cost is
94
+ * materially above this, a walk sized against it still overruns (the rescue
95
+ * fails and the tail was dropped for nothing). `scripts/bench-cascade-budget.mjs
96
+ * --true-cost-ms=<n>` measures that sensitivity directly. Rounded UP from the
97
+ * measurement so the estimate errs toward narrowing less.
98
+ */
99
+ const DEFAULT_NEIGHBOUR_COST_MS = 100;
100
+ /** Read per call — sized once per cascade run, never on a hot path. */
101
+ function neighbourCostMs() {
102
+ return (toPositiveFinite(process.env.PI_LENS_CASCADE_NEIGHBOUR_COST_MS) ||
103
+ DEFAULT_NEIGHBOUR_COST_MS);
104
+ }
105
+ function neighbourFloor() {
106
+ return (toPositiveFinite(process.env.PI_LENS_CASCADE_NEIGHBOUR_FLOOR) ||
107
+ MIN_NEIGHBOUR_BUDGET);
108
+ }
109
+ /**
110
+ * Size one run's neighbour walk against the on-time window supplied by its
111
+ * caller.
112
+ *
113
+ * `elapsedMs` is arithmetic input, not an observation made by this function.
114
+ * The production caller measures it against the active turn_end settle window
115
+ * and passes that elapsed time here. When that boundary is unavailable, the
116
+ * caller passes zero to preserve the flat cap. Legacy callers may still pass
117
+ * deferred run age for compatibility.
118
+ *
119
+ * Every override exists so the derivation can be tested and benchmarked as a
120
+ * pure function; the function itself does not observe a deferred run's age.
121
+ */
122
+ export function deriveCascadeNeighbourBudget(options) {
123
+ const ceiling = options.ceiling ?? CASCADE_NEIGHBOUR_BUDGET;
124
+ // The floor can never exceed the ceiling — a floor above the cap would make
125
+ // the derived budget LARGER than the flat one it exists to bound.
126
+ const floor = Math.min(ceiling, options.floor ?? neighbourFloor());
127
+ const onTimeMs = options.settleWaitMs ?? cascadeSettleWaitMs();
128
+ const perNeighbourMs = options.perNeighbourMs ?? neighbourCostMs();
129
+ const elapsedMs = toPositiveFinite(options.elapsedMs);
130
+ const remainingMs = onTimeMs - elapsedMs;
131
+ const deliveryWindowMs = onTimeMs +
132
+ (options.quietDrainMs ??
133
+ (isQuietWindowEnabled() ? quietWindowWaitMs() : 0));
134
+ const full = { budget: ceiling, ceiling, remainingMs, deliveryWindowMs };
135
+ // No on-time window at all, or one too small to ever fit a full walk. There
136
+ // is no late run to rescue here, only every run to shrink — stand down.
137
+ //
138
+ // Boundary, acknowledged rather than special-cased: at exactly
139
+ // `onTimeMs === ceiling * perNeighbourMs` this does not fire and the `fits`
140
+ // zone has zero width, so ANY prelude narrows. Not slightly, either — at
141
+ // 4000/100/40 a 2 s prelude gives 20 and a 3.5 s prelude gives the floor.
142
+ // Left alone because the narrowing is honest at that setting: with the
143
+ // window sized to exactly one full walk, a run that has spent any of it
144
+ // really would miss, so every one of those cuts is a genuine rescue rather
145
+ // than the `no-rescue-window` case this guard exists to catch. What it does
146
+ // cost is headroom — see the divisor bands in the bench's `--sweep` text.
147
+ if (onTimeMs <= 0 || onTimeMs < ceiling * perNeighbourMs) {
148
+ // #1462 review F-E: name the override, once per session, when it is the
149
+ // REASON the derivation stood down — not when a caller under test asked
150
+ // for a specific ceiling, and not on every one of the cascades this
151
+ // disarms for the rest of the session.
152
+ if (options.ceiling === undefined && NEIGHBOUR_BUDGET_OVERRIDDEN) {
153
+ recordDegradationOnce({
154
+ kind: "cascade-budget-override-disarmed",
155
+ subject: "cascade-neighbour-budget",
156
+ reason: `PI_LENS_CASCADE_NEIGHBOUR_BUDGET=${CASCADE_NEIGHBOUR_BUDGET} needs ` +
157
+ `${ceiling * perNeighbourMs}ms to walk the full cap, which exceeds ` +
158
+ `the ${onTimeMs}ms settle window — the rescue band is disarmed and ` +
159
+ `every cascade keeps the flat (overridden) cap`,
160
+ });
161
+ }
162
+ return { ...full, zone: "no-rescue-window" };
163
+ }
164
+ // The full walk still fits. Nothing to buy.
165
+ if (remainingMs >= ceiling * perNeighbourMs) {
166
+ return { ...full, zone: "fits" };
167
+ }
168
+ // Past rescue: not even a floor-sized walk fits, so narrowing would drop the
169
+ // tail permanently and still miss the window. The carry-over delivers the
170
+ // whole set one turn later instead.
171
+ //
172
+ // #1462 review F-B, kept rather than shrunk: one dogfood log measured this
173
+ // zone at 0/1090 cascades, and asked whether a 3-zone module earns its keep
174
+ // at that frequency. It was measured against the WRITE-relative clock this
175
+ // same round fixed, which charges elapsed time no cascade actually spent
176
+ // waiting — so it under-counts how often a genuinely slow compute (a cold
177
+ // graph build, ~19 s) overlaps an already-running settle window, which is
178
+ // exactly what this zone exists to catch (F3, a real regression the first
179
+ // review round found: a floor-sized stub on that cold-start case is
180
+ // strictly worse than pre-#1462). Reachability under the corrected clock
181
+ // has not been re-measured; shrinking on a stale sample would trade a
182
+ // cheap, already-tested guard against a proven regression for a paper
183
+ // simplification. Revisit if a post-fix dogfood window confirms it still
184
+ // never fires.
185
+ if (remainingMs < floor * perNeighbourMs) {
186
+ return { ...full, zone: "past-rescue" };
187
+ }
188
+ // The rescue band: a shorter walk lands on time.
189
+ return {
190
+ budget: Math.min(ceiling, Math.max(floor, Math.floor(remainingMs / perNeighbourMs))),
191
+ ceiling,
192
+ remainingMs,
193
+ deliveryWindowMs,
194
+ zone: "narrowed",
195
+ };
196
+ }
@@ -3,8 +3,18 @@ import { toRunnerDisplayPath } from "./dispatch/runner-context.js";
3
3
  export function formatCascadeNeighborDiagnostics(cwd, neighbors, options = {}) {
4
4
  const withErrors = neighbors.filter((n) => n.diagnostics.length > 0);
5
5
  const inconclusive = neighbors.filter((n) => n.inconclusive === true && n.diagnostics.length === 0);
6
- if (withErrors.length === 0 && inconclusive.length === 0)
6
+ // #1459: a neighbour whose scanner never looked at it is not a clean leaf. It
7
+ // is also not `inconclusive` — the language server answered — so it gets its
8
+ // own honest line instead of being folded into either bucket. Only the
9
+ // zero-diagnostic case needs saying: a neighbour with findings already renders.
10
+ const uncovered = neighbors.filter((n) => n.diagnostics.length === 0 &&
11
+ n.inconclusive !== true &&
12
+ (n.unconfirmedServerIds?.length ?? 0) > 0);
13
+ if (withErrors.length === 0 &&
14
+ inconclusive.length === 0 &&
15
+ uncovered.length === 0) {
7
16
  return "";
17
+ }
8
18
  const noun = options.noun ?? "neighbor";
9
19
  let out = withErrors.length > 0
10
20
  ? `📐 Cascade errors in ${withErrors.length} ${noun} file(s) — fix before finishing turn:`
@@ -29,6 +39,15 @@ export function formatCascadeNeighborDiagnostics(cwd, neighbors, options = {}) {
29
39
  out += `\n ${toRunnerDisplayPath(cwd, neighbor.filePath)}`;
30
40
  }
31
41
  }
42
+ if (uncovered.length > 0) {
43
+ if (out)
44
+ out += "\n";
45
+ out += `⚠️ Cascade scanners did not cover ${uncovered.length} ${noun} file(s) — no findings does NOT mean clean here:`;
46
+ for (const neighbor of uncovered) {
47
+ const servers = (neighbor.unconfirmedServerIds ?? []).join(", ");
48
+ out += `\n ${toRunnerDisplayPath(cwd, neighbor.filePath)} (not scanned by ${servers})`;
49
+ }
50
+ }
32
51
  return out;
33
52
  }
34
53
  /**
@@ -1 +1,9 @@
1
- export {};
1
+ /**
2
+ * How long a cascade neighbour's diagnostics stay usable (#1816).
3
+ *
4
+ * One constant for two consumers that each declared their own `240_000`:
5
+ * `clients/lsp/index.ts` (the neighbour-diagnostics cache) and
6
+ * `clients/dispatch/integration.ts` (the cascade turn scope). They must move
7
+ * together — a split pair reads as two independent policies and drifts.
8
+ */
9
+ export const CASCADE_DIAGNOSTICS_TTL_MS = 240_000;
@@ -60,13 +60,24 @@ export function unrefChildAndPipes(child) {
60
60
  * here already has).
61
61
  */
62
62
  export function spawnCollectStdout(command, args, options) {
63
+ return spawnCollectStdoutResult(command, args, options).then((result) => result.stdout);
64
+ }
65
+ /**
66
+ * `spawnCollectStdout` plus the reason the output is what it is. Same spawn,
67
+ * unref, collect, settle plumbing; the only additions are an optional hard
68
+ * timeout and a status discriminator. Never rejects.
69
+ */
70
+ export function spawnCollectStdoutResult(command, args, options, collectOptions = {}) {
63
71
  return new Promise((resolve) => {
64
72
  let settled = false;
65
- const settle = (value) => {
73
+ let timer;
74
+ const settle = (result) => {
66
75
  if (settled)
67
76
  return;
68
77
  settled = true;
69
- resolve(value);
78
+ if (timer)
79
+ clearTimeout(timer);
80
+ resolve(result);
70
81
  };
71
82
  try {
72
83
  const child = nodeSpawn(command, args, options);
@@ -75,11 +86,48 @@ export function spawnCollectStdout(command, args, options) {
75
86
  child.stdout?.on("data", (chunk) => {
76
87
  out += chunk.toString();
77
88
  });
78
- child.once("error", () => settle(""));
79
- child.once("close", () => settle(out));
89
+ child.once("error", (error) => settle({ stdout: "", status: "spawn-error", error }));
90
+ child.once("close", (code, signal) => settle(code === 0 && signal === null
91
+ ? { stdout: out, status: "ok" }
92
+ : {
93
+ stdout: "",
94
+ status: "exit-error",
95
+ exitCode: code,
96
+ exitSignal: signal,
97
+ }));
98
+ const timeoutMs = collectOptions.timeoutMs;
99
+ if (typeof timeoutMs === "number" && timeoutMs > 0) {
100
+ timer = setTimeout(() => {
101
+ // Settle only AFTER the child's fate is known. Killing and
102
+ // resolving in the same tick bounds the caller and abandons the
103
+ // child, which is the leak this timeout exists to prevent.
104
+ void terminateTimedOutChild(child, collectOptions.onTimeout).then((timeoutKill) => settle({ stdout: out, status: "timeout", timeoutKill }));
105
+ }, timeoutMs);
106
+ timer.unref();
107
+ }
80
108
  }
81
- catch {
82
- settle("");
109
+ catch (error) {
110
+ settle({ stdout: "", status: "spawn-error", error });
83
111
  }
84
112
  });
85
113
  }
114
+ /** Run the caller's termination handler, or the bare-signal default, and
115
+ * never let either throw out of the timeout path. */
116
+ async function terminateTimedOutChild(child, onTimeout) {
117
+ if (onTimeout) {
118
+ try {
119
+ return await onTimeout(child);
120
+ }
121
+ catch {
122
+ // A handler that threw did not verify anything.
123
+ return "unverified";
124
+ }
125
+ }
126
+ try {
127
+ child.kill();
128
+ }
129
+ catch {
130
+ // best-effort — the child may already be gone
131
+ }
132
+ return "unverified";
133
+ }
@@ -1,29 +1,47 @@
1
- import { createHash } from "node:crypto";
2
1
  import * as fs from "node:fs";
3
2
  import * as path from "node:path";
4
3
  import { toRunnerDisplayPath } from "./dispatch/runner-context.js";
5
4
  import { getProjectDataDir } from "./file-utils.js";
5
+ import { normalizeMessage, stableFindingId } from "./finding-identity.js";
6
6
  import { normalizeMapKey } from "./path-utils.js";
7
- function normalizeMessage(message) {
8
- return message.replace(/\s+/g, " ").trim().toLowerCase();
9
- }
10
- function hashText(value, length = 10) {
11
- return createHash("sha256").update(value).digest("hex").slice(0, length);
12
- }
13
- function relativeFile(filePath, cwd) {
14
- const rel = path.relative(cwd, filePath).replace(/\\/g, "/");
15
- return rel && !rel.startsWith("..") ? rel : normalizeMapKey(filePath);
16
- }
7
+ /**
8
+ * Report-budget precedence (#1777). A hint is an opinion; a warning is a
9
+ * finding. When the report is capped, warnings must be spent first, or an
10
+ * alphabetically-early file's hints can push every real warning out of the
11
+ * agent's view — the exact "hints dominate the stream" failure the hint tier
12
+ * exists to prevent.
13
+ */
14
+ const TIER_BUDGET_ORDER = [
15
+ "warning",
16
+ "info",
17
+ "hint",
18
+ ];
19
+ /** #1816: was a local `relativeFile|tool|rule|code|normalizedMessage|line`
20
+ * hash (raw, non-canonicalized `relativeFile`, 10-char hash), independently
21
+ * hand-rolled from `actionable-warnings.ts`'s twin and
22
+ * `diagnostic-dispositions.ts`'s canonicalizing original. Now the shared
23
+ * `finding-identity.js` builder (canonicalizes `cwd`/`filePath` through
24
+ * `normalizeMapKey`, hashes to 12 chars). No back-compat migration needed
25
+ * here: `cq:` ids are never a keyed lookup — `buildCodeQualityWarningsReport`
26
+ * regenerates the whole report fresh every turn, callers only ever cache and
27
+ * replay the report wholesale (`tools/lens-diagnostics.ts` reads it via
28
+ * `cacheManager.readCache<CodeQualityWarningsReport>`, never by `id`), and
29
+ * `appendCodeQualityWarningsHistory` just append-only-logs the id for
30
+ * observability, never look it back up. Contrast `actionable-warnings.ts`,
31
+ * whose `actionable-warning-state.json` DOES key a persisted suppression
32
+ * store on `aw:` — that one migrates. */
17
33
  function createCodeQualityWarningId(args) {
18
- const parts = [
19
- relativeFile(args.filePath, args.cwd),
20
- args.tool ?? "",
21
- args.rule ?? "",
22
- String(args.code ?? ""),
23
- normalizeMessage(args.message),
24
- String(args.line ?? ""),
25
- ];
26
- return `cq:${hashText(parts.join("|"))}`;
34
+ return stableFindingId("cq:", {
35
+ cwd: args.cwd,
36
+ filePath: args.filePath,
37
+ parts: [
38
+ args.tool,
39
+ args.rule,
40
+ args.code,
41
+ normalizeMessage(args.message),
42
+ args.line,
43
+ ],
44
+ });
27
45
  }
28
46
  function categorize(diagnostic) {
29
47
  const haystack = `${diagnostic.tool} ${diagnostic.rule ?? ""} ${diagnostic.code ?? ""} ${diagnostic.message}`.toLowerCase();
@@ -93,11 +111,22 @@ export function buildCodeQualityWarningsReport(args) {
93
111
  continue;
94
112
  byId.set(warning.id, warning);
95
113
  }
96
- const merged = [...byId.values()]
97
- .sort((a, b) => a.displayPath.localeCompare(b.displayPath) ||
114
+ const byDisplayOrder = (a, b) => a.displayPath.localeCompare(b.displayPath) ||
98
115
  (a.line ?? 0) - (b.line ?? 0) ||
99
- a.message.localeCompare(b.message))
100
- .slice(0, maxWarnings);
116
+ a.message.localeCompare(b.message);
117
+ // Spend the budget tier by tier (see TIER_BUDGET_ORDER), then restore
118
+ // display order so the report still reads file by file, line by line.
119
+ const candidates = [...byId.values()].sort(byDisplayOrder);
120
+ const merged = [];
121
+ for (const tier of TIER_BUDGET_ORDER) {
122
+ for (const warning of candidates) {
123
+ if (merged.length >= maxWarnings)
124
+ break;
125
+ if (warning.severity === tier)
126
+ merged.push(warning);
127
+ }
128
+ }
129
+ merged.sort(byDisplayOrder);
101
130
  const byFile = new Map();
102
131
  for (const warning of merged) {
103
132
  const arr = byFile.get(warning.filePath) ?? [];
@@ -131,6 +160,11 @@ export function buildCodeQualityWarningsReport(args) {
131
160
  summary: {
132
161
  warnings: merged.length,
133
162
  files: files.length,
163
+ byTier: {
164
+ warning: merged.filter((w) => w.severity === "warning").length,
165
+ info: merged.filter((w) => w.severity === "info").length,
166
+ hint: merged.filter((w) => w.severity === "hint").length,
167
+ },
134
168
  topRules,
135
169
  },
136
170
  };
@@ -205,8 +239,26 @@ export function formatCodeQualityWarningsAdvisory(report) {
205
239
  .slice(0, 3)
206
240
  .map((entry) => `${entry.rule}×${entry.count}`)
207
241
  .join(", ");
242
+ // #1777: name the tiers, in the same descending-loudness order the on-demand
243
+ // ast-grep surface uses (`formatDiagnostics`, clients/ast-grep-client.ts).
244
+ // A tier with no findings is omitted rather than printed as zero.
245
+ const byTier = report.summary.byTier ?? { warning: 0, info: 0, hint: 0 };
246
+ // The line is worth its space only when a quiet tier is present; an
247
+ // all-warning turn already says everything in the count above.
248
+ const tiers = byTier.hint || byTier.info
249
+ ? [
250
+ byTier.warning ? `${byTier.warning} warning` : undefined,
251
+ byTier.info ? `${byTier.info} info` : undefined,
252
+ byTier.hint ? `${byTier.hint} hint` : undefined,
253
+ ]
254
+ .filter(Boolean)
255
+ .join(", ")
256
+ : "";
208
257
  return [
209
258
  `Code-quality warnings introduced/touched this turn: ${report.summary.warnings} across ${report.summary.files} file(s).`,
259
+ tiers
260
+ ? `By tier: ${tiers}. Hint and info are style opinions, not defects.`
261
+ : undefined,
210
262
  topRules ? `Top rules: ${topRules}` : undefined,
211
263
  "Details written to .pi-lens/cache/code-quality-warnings.json",
212
264
  "No action required unless you are already refactoring these areas.",