@herbertgao/pi-extensions 2026.8.6 → 2026.8.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (343) hide show
  1. package/README.md +5 -5
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +1 -1
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +1 -1
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +19 -7
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +30 -9
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +272 -22
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +1 -1
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +14 -0
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +55 -17
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +41 -2
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +75 -6
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +7 -3
  14. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +64 -1
  15. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  16. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
  17. package/node_modules/@herbertgao/pi-subagents/README.md +30 -22
  18. package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +5 -5
  19. package/node_modules/@herbertgao/pi-subagents/package.json +7 -7
  20. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +7 -1
  21. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +48 -19
  22. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +17 -13
  23. package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +26 -2
  24. package/node_modules/@herbertgao/pi-subagents/src/index.ts +219 -40
  25. package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +101 -3
  26. package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +18 -4
  27. package/node_modules/@herbertgao/pi-subagents/src/settings.ts +99 -0
  28. package/node_modules/@herbertgao/pi-subagents/src/types.ts +22 -3
  29. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +51 -3
  30. package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +20 -2
  31. package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +21 -6
  32. package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
  33. package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +20 -0
  34. package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +1 -0
  35. package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +26 -10
  36. package/node_modules/@juicesharp/rpiv-ask-user-question/config.ts +25 -0
  37. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/configuration.md +13 -4
  38. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +2 -1
  39. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +3 -1
  40. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +2 -2
  41. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/zh.json +2 -2
  42. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +3 -2
  43. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +10 -0
  44. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +3 -1
  45. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +30 -7
  46. package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
  47. package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +30 -4
  48. package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +26 -5
  49. package/node_modules/@narumitw/pi-btw/README.md +120 -111
  50. package/node_modules/@narumitw/pi-btw/dist/index.ts +2898 -0
  51. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +7 -0
  52. package/node_modules/@narumitw/pi-btw/package.json +10 -6
  53. package/node_modules/@narumitw/pi-btw/src/btw.ts +36 -40
  54. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +55 -10
  55. package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +390 -0
  56. package/node_modules/@narumitw/pi-btw/src/menu.ts +45 -2
  57. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
  58. package/node_modules/pi-lens/CHANGELOG.md +909 -0
  59. package/node_modules/pi-lens/README.md +11 -3
  60. package/node_modules/pi-lens/config/ruff/core.toml +42 -0
  61. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +130 -27
  62. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +126 -13
  63. package/node_modules/pi-lens/dist/clients/agent-nudge.js +67 -11
  64. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +9 -3
  65. package/node_modules/pi-lens/dist/clients/atomic-write.js +9 -3
  66. package/node_modules/pi-lens/dist/clients/bash-file-access.js +285 -8
  67. package/node_modules/pi-lens/dist/clients/biome-client.js +61 -30
  68. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
  69. package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +119 -0
  70. package/node_modules/pi-lens/dist/clients/bootstrap.js +12 -1
  71. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +12 -3
  72. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +192 -0
  73. package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
  74. package/node_modules/pi-lens/dist/clients/cascade-format.js +20 -1
  75. package/node_modules/pi-lens/dist/clients/cascade-types.js +9 -1
  76. package/node_modules/pi-lens/dist/clients/child-unref.js +54 -6
  77. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +76 -24
  78. package/node_modules/pi-lens/dist/clients/dead-code-client.js +123 -31
  79. package/node_modules/pi-lens/dist/clients/deadline-utils.js +8 -1
  80. package/node_modules/pi-lens/dist/clients/debug-handles.js +5 -0
  81. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +62 -13
  82. package/node_modules/pi-lens/dist/clients/dependency-checker.js +25 -3
  83. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +147 -33
  84. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
  85. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +52 -2
  86. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +256 -88
  87. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +7 -4
  88. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +5 -0
  89. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +234 -18
  90. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +187 -19
  91. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +6 -3
  92. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +11 -9
  93. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +398 -0
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +11 -3
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +12 -7
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +18 -0
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +4 -0
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +16 -3
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +60 -53
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -0
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +23 -0
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +331 -55
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +38 -5
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +97 -19
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +14 -0
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +20 -0
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +22 -0
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +10 -0
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +18 -6
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +73 -12
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +275 -13
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +21 -6
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +260 -27
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +734 -64
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +86 -11
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +72 -0
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +9 -0
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +9 -0
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -1
  121. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
  122. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
  123. package/node_modules/pi-lens/dist/clients/extension-log.js +22 -1
  124. package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
  125. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +294 -0
  126. package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
  127. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +3 -2
  128. package/node_modules/pi-lens/dist/clients/formatters.js +500 -115
  129. package/node_modules/pi-lens/dist/clients/generation-guard.js +216 -0
  130. package/node_modules/pi-lens/dist/clients/git-guard.js +31 -0
  131. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
  132. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +109 -9
  133. package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
  134. package/node_modules/pi-lens/dist/clients/host-ports.js +8 -0
  135. package/node_modules/pi-lens/dist/clients/installer/index.js +1114 -100
  136. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +58 -0
  137. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +715 -0
  138. package/node_modules/pi-lens/dist/clients/instance-reaper.js +643 -97
  139. package/node_modules/pi-lens/dist/clients/instance-registry.js +87 -17
  140. package/node_modules/pi-lens/dist/clients/jscpd-client.js +82 -6
  141. package/node_modules/pi-lens/dist/clients/knip-client.js +310 -10
  142. package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
  143. package/node_modules/pi-lens/dist/clients/language-profile.js +2 -0
  144. package/node_modules/pi-lens/dist/clients/latency-logger.js +440 -11
  145. package/node_modules/pi-lens/dist/clients/lazy-import.js +21 -0
  146. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -0
  147. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
  148. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +102 -7
  149. package/node_modules/pi-lens/dist/clients/lsp/client.js +1516 -159
  150. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +83 -1
  151. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
  152. package/node_modules/pi-lens/dist/clients/lsp/index.js +2274 -147
  153. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +215 -0
  154. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +146 -14
  155. package/node_modules/pi-lens/dist/clients/lsp/language.js +48 -4
  156. package/node_modules/pi-lens/dist/clients/lsp/server.js +277 -16
  157. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +22 -0
  158. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +43 -0
  159. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +79 -3
  160. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +43 -0
  161. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +422 -28
  162. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +30 -0
  163. package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +175 -0
  164. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +3 -2
  165. package/node_modules/pi-lens/dist/clients/mcp/session.js +10 -2
  166. package/node_modules/pi-lens/dist/clients/module-report.js +8 -0
  167. package/node_modules/pi-lens/dist/clients/opengrep-client.js +15 -1
  168. package/node_modules/pi-lens/dist/clients/package-manager.js +170 -14
  169. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +27 -0
  170. package/node_modules/pi-lens/dist/clients/path-utils.js +160 -0
  171. package/node_modules/pi-lens/dist/clients/pipeline.js +154 -33
  172. package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +37 -0
  173. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +17 -3
  174. package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +89 -22
  175. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +84 -14
  176. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +15 -3
  177. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +50 -2
  178. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +5 -0
  179. package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
  180. package/node_modules/pi-lens/dist/clients/project-snapshot.js +299 -0
  181. package/node_modules/pi-lens/dist/clients/quiet-window-config.js +47 -0
  182. package/node_modules/pi-lens/dist/clients/quiet-window.js +11 -25
  183. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +1 -1
  184. package/node_modules/pi-lens/dist/clients/read-guard.js +184 -10
  185. package/node_modules/pi-lens/dist/clients/resource-sampler.js +49 -17
  186. package/node_modules/pi-lens/dist/clients/reverse-deps.js +50 -11
  187. package/node_modules/pi-lens/dist/clients/review-graph/query.js +52 -4
  188. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +96 -7
  189. package/node_modules/pi-lens/dist/clients/runtime-context.js +8 -1
  190. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +308 -45
  191. package/node_modules/pi-lens/dist/clients/runtime-session.js +332 -9
  192. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
  193. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +212 -79
  194. package/node_modules/pi-lens/dist/clients/runtime-turn.js +575 -67
  195. package/node_modules/pi-lens/dist/clients/safe-spawn.js +220 -7
  196. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +161 -0
  197. package/node_modules/pi-lens/dist/clients/search-read-registration.js +34 -6
  198. package/node_modules/pi-lens/dist/clients/security-scan-client.js +157 -24
  199. package/node_modules/pi-lens/dist/clients/sg-runner.js +116 -22
  200. package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
  201. package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
  202. package/node_modules/pi-lens/dist/clients/startup-timing.js +19 -1
  203. package/node_modules/pi-lens/dist/clients/test-runner-client.js +151 -16
  204. package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
  205. package/node_modules/pi-lens/dist/clients/tool-policy.js +125 -20
  206. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +75 -1
  207. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +769 -64
  208. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +11 -0
  209. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +90 -0
  210. package/node_modules/pi-lens/dist/clients/trivy-client.js +19 -1
  211. package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
  212. package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
  213. package/node_modules/pi-lens/dist/index.js +67738 -55739
  214. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +466 -54
  215. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +132 -43
  216. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
  217. package/node_modules/pi-lens/docs/agent-guide.md +6 -1
  218. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +515 -506
  219. package/node_modules/pi-lens/docs/dispositions.md +21 -0
  220. package/node_modules/pi-lens/docs/features.md +19 -5
  221. package/node_modules/pi-lens/docs/globalconfig.md +3 -0
  222. package/node_modules/pi-lens/docs/language-coverage.md +71 -5
  223. package/node_modules/pi-lens/docs/mcp.md +2 -2
  224. package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
  225. package/node_modules/pi-lens/docs/settings.md +19 -1
  226. package/node_modules/pi-lens/docs/usage.md +1 -0
  227. package/node_modules/pi-lens/package.json +10 -6
  228. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-js-snapshot.yml +23 -0
  229. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-snapshot.yml +23 -0
  230. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/ts-void-zero-snapshot.yml +23 -0
  231. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-object-param-test.yml +16 -0
  232. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +15 -1
  233. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-compile-call-test.yml +29 -1
  234. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-dupe-class-members-test.yml +33 -0
  235. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-js-test.yml +7 -1
  236. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-test.yml +7 -1
  237. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-known-value-widening-test.yml +9 -0
  238. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml +216 -0
  239. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +2 -0
  240. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +2 -0
  241. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +2 -1
  242. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +2 -1
  243. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-return-value-in-generator-test.yml +12 -0
  244. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-runtime-typeof-test.yml +33 -0
  245. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-server-bind-wildcard-test.yml +9 -0
  246. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-shape-in-symbol-names-test.yml +13 -0
  247. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-js-test.yml +5 -1
  248. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-test.yml +5 -1
  249. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-parameters-test.yml +12 -0
  250. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-returns-test.yml +16 -0
  251. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-any-test.yml +10 -0
  252. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-unknown-test.yml +8 -0
  253. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/redundant-unsafe-function-test.yml +35 -0
  254. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/require-safety-comment-for-as-unknown-as-test.yml +177 -0
  255. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ts-void-zero-test.yml +1 -0
  256. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member-js.yml +13 -2
  257. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member.yml +13 -2
  258. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +2 -0
  259. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-object-param.yml +60 -0
  260. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +57 -12
  261. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-compile-call.yml +63 -5
  262. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-dupe-class-members.yml +52 -8
  263. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html-js.yml +27 -2
  264. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html.yml +27 -2
  265. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-known-value-widening.yml +71 -0
  266. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-non-null-assertion.yml +316 -0
  267. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +7 -0
  268. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +22 -2
  269. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +23 -2
  270. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +33 -5
  271. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +34 -8
  272. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-return-value-in-generator.yml +22 -5
  273. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-runtime-typeof.yml +121 -0
  274. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-server-bind-wildcard.yml +23 -7
  275. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-shape-in-symbol-names.yml +68 -0
  276. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +41 -2
  277. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code.yml +41 -2
  278. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +6 -1
  279. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-parameters.yml +67 -0
  280. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-returns.yml +106 -0
  281. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-any.yml +50 -0
  282. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-unknown.yml +56 -0
  283. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +2 -0
  284. package/node_modules/pi-lens/rules/ast-grep-rules/rules/redundant-unsafe-function.yml +32 -0
  285. package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml +184 -0
  286. package/node_modules/pi-lens/rules/ast-grep-rules/rules/ts-void-zero.yml +5 -0
  287. package/node_modules/pi-lens/rules/ast-grep-rules/self-scan-baseline.json +5 -0
  288. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +53 -1
  289. package/node_modules/pi-lens/scripts/download-grammars.js +25 -0
  290. package/node_modules/pi-lens/scripts/grammars.lock.json +9 -0
  291. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +2 -0
  292. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +80 -3
  293. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +41 -0
  294. package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
  295. package/node_modules/pi-mcp-adapter/CHANGELOG.md +36 -0
  296. package/node_modules/pi-mcp-adapter/README.md +47 -5
  297. package/node_modules/pi-mcp-adapter/cli.js +163 -1
  298. package/node_modules/pi-mcp-adapter/commands.ts +128 -22
  299. package/node_modules/pi-mcp-adapter/config.ts +25 -7
  300. package/node_modules/pi-mcp-adapter/direct-tools.ts +5 -4
  301. package/node_modules/pi-mcp-adapter/index.ts +219 -32
  302. package/node_modules/pi-mcp-adapter/init.ts +36 -4
  303. package/node_modules/pi-mcp-adapter/lifecycle.ts +315 -24
  304. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +39 -6
  305. package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +387 -0
  306. package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +27 -3
  307. package/node_modules/pi-mcp-adapter/mcp-code.ts +4 -0
  308. package/node_modules/pi-mcp-adapter/mcp-panel.ts +42 -13
  309. package/node_modules/pi-mcp-adapter/metadata-cache.ts +32 -21
  310. package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
  311. package/node_modules/pi-mcp-adapter/package.json +3 -1
  312. package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
  313. package/node_modules/pi-mcp-adapter/request-headers-command.ts +31 -37
  314. package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
  315. package/node_modules/pi-mcp-adapter/server-manager.ts +140 -2
  316. package/node_modules/pi-mcp-adapter/session-recovery.ts +7 -0
  317. package/node_modules/pi-mcp-adapter/tool-approval.ts +15 -2
  318. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
  319. package/node_modules/pi-mcp-adapter/types.ts +2 -0
  320. package/node_modules/pi-mcp-adapter/ui-server.ts +18 -16
  321. package/node_modules/pi-mcp-adapter/utils.ts +70 -0
  322. package/node_modules/pi-web-access/CHANGELOG.md +23 -0
  323. package/node_modules/pi-web-access/README.md +27 -9
  324. package/node_modules/pi-web-access/anysearch.ts +4 -2
  325. package/node_modules/pi-web-access/brave.ts +16 -4
  326. package/node_modules/pi-web-access/curator-page.ts +6 -3
  327. package/node_modules/pi-web-access/curator-server.ts +4 -1
  328. package/node_modules/pi-web-access/exa.ts +18 -7
  329. package/node_modules/pi-web-access/extract.ts +28 -3
  330. package/node_modules/pi-web-access/gemini-search.ts +16 -4
  331. package/node_modules/pi-web-access/index.ts +41 -57
  332. package/node_modules/pi-web-access/package.json +1 -1
  333. package/node_modules/pi-web-access/page-query.ts +4 -2
  334. package/node_modules/pi-web-access/parallel-mcp.ts +249 -0
  335. package/node_modules/pi-web-access/parallel.ts +2 -2
  336. package/node_modules/pi-web-access/query-rewrite.ts +51 -0
  337. package/node_modules/pi-web-access/serper.ts +211 -0
  338. package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
  339. package/node_modules/pi-web-access/summary-review.ts +44 -22
  340. package/node_modules/pi-web-access/tavily.ts +16 -4
  341. package/node_modules/pi-web-access/utils.ts +87 -0
  342. package/node_modules/pi-web-access/valyu.ts +199 -0
  343. package/package.json +13 -13
@@ -1,10 +1,14 @@
1
1
  import * as nodeFs from "node:fs";
2
2
  import * as path from "node:path";
3
+ import { resetBoundedTelemetry } from "./bounded-telemetry.js";
3
4
  import { createDeadline, yieldIfOverBudget } from "./cooperative-budget.js";
4
5
  import { deadCodeIssueCount } from "./dead-code-client.js";
5
6
  import { logDeadCodeScan } from "./dead-code-logger.js";
6
- import { resetDegradationLedger } from "./degradation-ledger.js";
7
+ import { incrementDegradationCount, resetDegradationLedger, } from "./degradation-ledger.js";
7
8
  import { getDiagnosticTracker } from "./diagnostic-tracker.js";
9
+ import { resetPsScriptAnalyzerAvailability } from "./dispatch/runners/psscriptanalyzer.js";
10
+ import { resetInstallRetryLatches } from "./dispatch/runners/utils/availability-policy.js";
11
+ import { resetLazyInstallAttempts } from "./dispatch/runners/utils/lazy-installer.js";
8
12
  import { resetDispatchAvailabilityState } from "./dispatch/runners/utils/runner-helpers.js";
9
13
  import { clearAllSessions as clearFileTimeSessions } from "./file-time.js";
10
14
  import { getGlobalPiLensDir, getKnipIgnorePatterns, getProjectDataDir, } from "./file-utils.js";
@@ -16,11 +20,17 @@ import { detectProjectLanguageProfile, getDefaultStartupTools, } from "./languag
16
20
  import { logLatency } from "./latency-logger.js";
17
21
  import { runLogCleanup } from "./log-cleanup.js";
18
22
  import { initLSPConfig, loadLSPConfig } from "./lsp/config.js";
23
+ import { resetWorkspaceDiagnosticsCacheSession } from "./lsp/workspace-diagnostics-session.js";
24
+ import { resetDirectLspCommandAvailability } from "./lsp/server.js";
19
25
  import { loadLspService } from "./lsp-lazy.js";
26
+ import { resetManagedToolRefreshSession } from "./installer/managed-tool-refresh-session.js";
27
+ import { resetResolvedPathCache } from "./installer/index.js";
28
+ import { _resetPackageManagerCache } from "./package-manager.js";
29
+ import { clearFormatterCache } from "./formatters.js";
20
30
  import { isAtOrAboveHomeDir } from "./path-utils.js";
21
31
  import { isPrintMode } from "./print-mode.js";
22
32
  import { readLatestProjectSequence, readLatestProjectSequenceAsync, } from "./project-changes.js";
23
- import { getProjectSnapshotPath, hydrateRuntimeFromProjectSnapshot, isProjectSnapshotFresh, isProjectSnapshotMetaStale, loadProjectSnapshot, PROJECT_SNAPSHOT_VERSION, readProjectSnapshotMeta, saveRuntimeProjectSnapshot, } from "./project-snapshot.js";
33
+ import { getProjectSnapshotPath, getProjectSnapshotLegacyPath, hydrateRuntimeFromProjectSnapshot, hydrateRuntimeFromProjectSnapshotIfIdle, isProjectSnapshotFresh, isProjectSnapshotMetaStale, loadProjectSnapshot, loadProjectSnapshotExportsAndRules, PROJECT_SNAPSHOT_VERSION, readProjectSnapshotMeta, saveRuntimeProjectSnapshot, } from "./project-snapshot.js";
24
34
  import { clearTsconfigPathsCache } from "./review-graph/tsconfig-paths.js";
25
35
  import { scanProjectRules } from "./rules-scanner.js";
26
36
  import { resetSafeSpawnWindowsCommandCache } from "./safe-spawn.js";
@@ -33,6 +43,27 @@ import { isWarmAttached } from "./warm-attach.js";
33
43
  import { setSessionLanguages } from "./widget-state.js";
34
44
  import { logWordIndex } from "./word-index-logger.js";
35
45
  import { resetWorkspaceTopology } from "./workspace-topology.js";
46
+ import { resetZizmorTokenAvailability } from "./zizmor-config.js";
47
+ const HOST_STALL_THRESHOLD_MS = 30_000;
48
+ function logHostReadyDelay(deps, cwd) {
49
+ if (!deps.emitHostReadyDelay ||
50
+ deps.sessionStartMonotonicAt === undefined ||
51
+ deps.extensionLoadedAt === undefined) {
52
+ return;
53
+ }
54
+ const durationMs = Math.max(0, deps.sessionStartMonotonicAt - deps.extensionLoadedAt);
55
+ logLatency({
56
+ type: "phase",
57
+ filePath: cwd,
58
+ phase: "host_ready_delay",
59
+ durationMs,
60
+ metadata: {
61
+ hostStallSuspected: durationMs > HOST_STALL_THRESHOLD_MS,
62
+ sessionStart: "first-process-session",
63
+ reason: deps.sessionReason,
64
+ },
65
+ });
66
+ }
36
67
  function resolveSnapshotRoot(cwd) {
37
68
  const resolvedCwd = path.resolve(cwd);
38
69
  const nearest = findNearestProjectRoot(resolvedCwd);
@@ -79,6 +110,91 @@ function snapshotSequenceBase(root) {
79
110
  sinceSeq: meta.seq,
80
111
  };
81
112
  }
113
+ /**
114
+ * #1785: one bounded ledger record per timed-out sequence read, so a real
115
+ * occurrence is diagnosable from the ledger alone rather than only from a
116
+ * `dbg` line that most hosts never surface. Carries the project root and the
117
+ * on-disk snapshot's age/size (when one exists) — the identity AC1 asks for:
118
+ * which project, how stale/large the snapshot that got skipped was.
119
+ */
120
+ function recordSnapshotSequenceTimeout(args) {
121
+ let reason = "sequence read timed out; no snapshot on disk";
122
+ try {
123
+ const stat = nodeFs.statSync(args.snapshotPath);
124
+ reason = `sequence read timed out; snapshot age=${Math.round(Date.now() - stat.mtimeMs)}ms size=${stat.size}b`;
125
+ }
126
+ catch {
127
+ // No snapshot on disk yet — the reason above already covers it.
128
+ }
129
+ incrementDegradationCount({
130
+ kind: "snapshot-sequence-read-timeout",
131
+ subject: args.snapshotRoot,
132
+ reason,
133
+ });
134
+ }
135
+ /**
136
+ * #1785: the synchronous freshness check made a conservative call with the
137
+ * `UNKNOWN_PROJECT_SEQ` sentinel (never hydrate when the real sequence is
138
+ * unknown). Once the deferred read resolves — a deterministic completion
139
+ * signal, not a sleep — this re-checks freshness against the now-known
140
+ * sequence and hydrates late when the snapshot really was current, instead of
141
+ * leaving the runtime without `cachedExports`/`projectRulesScan` for the rest
142
+ * of the session.
143
+ *
144
+ * #1785 review round F5 (design (a), replacing rounds 1-3's synchronous
145
+ * capture entirely): quick mode's own cold-start warmup ALREADY loads the
146
+ * on-disk snapshot for its own purposes — `cachedSnapshot` at the top of the
147
+ * warmup body, used to reuse a still-fresh `startupScan` verdict — strictly
148
+ * BEFORE the warmup's own possible save (`saveRuntimeProjectSnapshot`, only
149
+ * reached when that verdict was NOT fresh). Reusing THAT already-loaded
150
+ * value costs nothing new: the read was always going to happen regardless of
151
+ * this fix, and it is guaranteed to predate any overwrite the SAME warmup
152
+ * invocation might go on to make — a read-before-write invariant of the
153
+ * warmup's own code, not something this function has to defend against with
154
+ * a race window of its own. `getWarmupOwnSnapshotRead` is a closure over a
155
+ * per-`handleSessionStart`-call LOCAL variable (never module-scope — #1785
156
+ * F6 is exactly the class of bug a module-scope holder here would
157
+ * reintroduce) that the warmup publishes into once its own read completes.
158
+ *
159
+ * When the getter still returns `undefined` — the deferred read resolved
160
+ * before the warmup got that far (or no warmup was ever armed by this call:
161
+ * a later quick-mode call in the same process, print mode, full mode) —
162
+ * there is nothing published yet, so this falls back to a live re-load via
163
+ * `loadProjectSnapshotExportsAndRules`. That fallback is exactly as safe as
164
+ * the primary path: if the warmup hasn't reached its own read yet, it
165
+ * certainly hasn't saved yet either (same invariant), so disk still holds
166
+ * whatever was there before any warmup activity.
167
+ *
168
+ * Both the published value and the fallback re-load are the narrow,
169
+ * postings-free `ProjectSnapshotExportsAndRules` shape — never the full
170
+ * `loadProjectSnapshot`. This path only ever hydrates
171
+ * `cachedExports`/`projectRulesScan`; it can NOT hydrate `wordIndex` even
172
+ * when the underlying snapshot would otherwise have one, because the narrow
173
+ * type never carries it. That is intentional, not a regression: F2's hazard
174
+ * was this exact path nulling a `wordIndex` that quick mode's warmup had, in
175
+ * the meantime, built for real — the warmup remains the sole source of a
176
+ * late-arriving `wordIndex` for the interactive path.
177
+ */
178
+ function retroactivelyHydrateAfterDeferredSequence(args) {
179
+ return (latestSeq) => {
180
+ const published = args.getWarmupOwnSnapshotRead();
181
+ const snapshot = published !== undefined
182
+ ? published
183
+ : loadProjectSnapshotExportsAndRules(args.snapshotRoot);
184
+ if (!snapshot ||
185
+ snapshot.version !== PROJECT_SNAPSHOT_VERSION ||
186
+ snapshot.seq !== latestSeq.projectSeq) {
187
+ return;
188
+ }
189
+ const hydrated = hydrateRuntimeFromProjectSnapshotIfIdle(args.runtime, snapshot);
190
+ if (hydrated) {
191
+ args.dbg(`session_start: deferred sequence read confirmed snapshot freshness — hydrating cachedExports/projectRulesScan late (seq=${snapshot.seq})`);
192
+ }
193
+ else {
194
+ args.dbg(`session_start: deferred sequence read confirmed snapshot freshness (seq=${snapshot.seq}), but the runtime already has live state (warmup or another task got there first) — skipping late hydration to avoid clobbering it`);
195
+ }
196
+ };
197
+ }
82
198
  function loadSnapshotBodyUnlessStale(args) {
83
199
  const meta = readProjectSnapshotMeta(args.root);
84
200
  if (meta && isProjectSnapshotMetaStale(meta, args.currentProjectSeq)) {
@@ -90,12 +206,17 @@ function loadSnapshotBodyUnlessStale(args) {
90
206
  skippedStale: false,
91
207
  };
92
208
  }
93
- function describeSnapshotMiss(snapshot, currentProjectSeq) {
209
+ function describeSnapshotMiss(snapshot, currentProjectSeq, args) {
210
+ if (args.skippedStale)
211
+ return "stale-meta-gate";
94
212
  if (!snapshot)
95
- return "missing";
213
+ return args.bodyPresent ? "invalid-body" : "missing";
96
214
  if (snapshot.seq !== currentProjectSeq) {
97
215
  return `stale(seq=${snapshot.seq}, current=${currentProjectSeq})`;
98
216
  }
217
+ // Defensive-only arm: parseSnapshot rejects incompatible versions, and a
218
+ // same-sequence parsed snapshot is fresh. Keep this classification explicit
219
+ // so a future loader change cannot collapse it into a generic miss.
99
220
  return "incompatible";
100
221
  }
101
222
  function logProjectSnapshotProbe(args) {
@@ -104,7 +225,7 @@ function logProjectSnapshotProbe(args) {
104
225
  args.dbg(`project_snapshot: loaded seq=${args.snapshot.seq} exports=${args.snapshot.cachedExports.length} files=${Object.keys(args.snapshot.files ?? {}).length} reverseDeps=${Object.keys(args.snapshot.reverseDeps ?? {}).length} startupScan=${Boolean(args.snapshot.startupScan)} languageProfile=${Boolean(args.snapshot.languageProfile)}`);
105
226
  }
106
227
  else {
107
- args.dbg(`project_snapshot: miss reason=${describeSnapshotMiss(args.snapshot, args.currentProjectSeq)}`);
228
+ args.dbg(`project_snapshot: miss reason=${args.missReason}`);
108
229
  }
109
230
  }
110
231
  function resolveStartupMode() {
@@ -171,7 +292,7 @@ const UNKNOWN_PROJECT_SEQ = -1;
171
292
  * logs its own `session_start_sequence_read_deferred_reseed` phase.
172
293
  */
173
294
  async function readSequenceWithBudget(args) {
174
- const { snapshotRoot, base, cwd, runtime, sessionGeneration, dbg } = args;
295
+ const { snapshotRoot, base, cwd, runtime, sessionGeneration, dbg, onDeferredSequenceResolved, } = args;
175
296
  const readPromise = readLatestProjectSequenceAsync(snapshotRoot, base);
176
297
  let timeoutHandle;
177
298
  const timeoutPromise = new Promise((resolve) => {
@@ -224,6 +345,7 @@ async function readSequenceWithBudget(args) {
224
345
  metadata: { entries: latestSeq.fileSeqByPath.size, deferred: true },
225
346
  });
226
347
  dbg(`session_start: deferred sequence read completed — reseeded projectSeq=${latestSeq.projectSeq} fileSeqEntries=${latestSeq.fileSeqByPath.size}`);
348
+ onDeferredSequenceResolved?.(latestSeq);
227
349
  })
228
350
  .catch((err) => {
229
351
  dbg(`session_start: deferred sequence read failed: ${err}`);
@@ -375,6 +497,47 @@ function firePreinstallDefaults(ensureTool, dbg, startupDefaults) {
375
497
  });
376
498
  }
377
499
  }
500
+ /**
501
+ * Default delay before the managed-tool version refresh runs (#1730). Long
502
+ * enough that `session_start`, the startup scans, and the tool preinstalls have
503
+ * all settled — the refresh may spawn one `npm update`, and that must never
504
+ * compete with the work the user is waiting on.
505
+ */
506
+ const MANAGED_TOOL_REFRESH_DELAY_MS = 30_000;
507
+ /**
508
+ * Schedule the periodic managed-tool refresh (#1730) on an unref'd background
509
+ * timer.
510
+ *
511
+ * `session_start`'s own cost here is a single `setTimeout` registration: the
512
+ * refresh module is not even imported until the timer fires. The timer is
513
+ * unref'd so a one-shot process exits without waiting for it, matching the
514
+ * warmup timer above. Whether a refresh actually runs is decided inside
515
+ * `runManagedToolRefresh` against a PERSISTED per-tool stamp, so a launch loop
516
+ * cannot escalate the weekly cadence.
517
+ */
518
+ function scheduleManagedToolRefresh(dbg) {
519
+ const delayMs = Number(process.env.PI_LENS_TOOL_REFRESH_DELAY_MS ?? MANAGED_TOOL_REFRESH_DELAY_MS);
520
+ const timer = setTimeout(() => {
521
+ void (async () => {
522
+ try {
523
+ const refresh = await import("./installer/managed-tool-refresh.js");
524
+ const outcome = await refresh.runManagedToolRefresh();
525
+ if (outcome.skipped) {
526
+ dbg(`session_start tool-refresh: skipped (${outcome.skipped})`);
527
+ return;
528
+ }
529
+ for (const result of outcome.refreshed) {
530
+ dbg(`session_start tool-refresh: ${result.toolId} ${result.ok ? "ok" : "failed"}` +
531
+ `${result.changed ? ` ${result.previousVersion ?? "unknown"} → ${result.currentVersion}` : " (unchanged)"}`);
532
+ }
533
+ }
534
+ catch (err) {
535
+ dbg(`session_start tool-refresh: error ${err}`);
536
+ }
537
+ })();
538
+ }, Number.isFinite(delayMs) ? delayMs : MANAGED_TOOL_REFRESH_DELAY_MS);
539
+ timer.unref?.();
540
+ }
378
541
  async function probePrettierInstall(ensureTool, dbg, analysisRoot) {
379
542
  const pkgPath = path.join(analysisRoot, "package.json");
380
543
  try {
@@ -715,7 +878,7 @@ function scheduleStartupScans(deps, runtime, sessionGeneration, analysisRoot, sn
715
878
  // KnipClient skips before probing/installing when analysisRoot is not a real
716
879
  // JS/Knip project. This avoids running knip from Unity/C#/generic repos.
717
880
  const startMs = Date.now();
718
- const knipResult = await knipClient.analyze(analysisRoot, getKnipIgnorePatterns());
881
+ const knipResult = await knipClient.analyze(analysisRoot, getKnipIgnorePatterns(), { projectSeq: runtime.projectSeq });
719
882
  if (!runtime.isCurrentSession(sessionGeneration))
720
883
  return;
721
884
  if (knipResult.success) {
@@ -1121,6 +1284,12 @@ export const SESSION_START_GUIDANCE = [
1121
1284
  ];
1122
1285
  export async function handleSessionStart(deps) {
1123
1286
  resetDegradationLedger();
1287
+ // #1743: the bounded-telemetry per-turn counters. The rising-edge state is
1288
+ // NOT here — it is the ledger's own tally, reset on the line above. These
1289
+ // counters are keyed by turn index, and a new session restarts turn
1290
+ // numbering at 0, so without this a stale count could survive a session
1291
+ // boundary that happened to land on the same index.
1292
+ resetBoundedTelemetry();
1124
1293
  const handlerEnteredAt = Date.now();
1125
1294
  const sessionStartMs = deps.sessionStartFiredAt ?? handlerEnteredAt;
1126
1295
  const cwdForTelemetry = deps.ctxCwd ?? process.cwd();
@@ -1175,6 +1344,11 @@ export async function handleSessionStart(deps) {
1175
1344
  // (an explicit env var still takes highest precedence).
1176
1345
  // Tunable: PI_LENS_WARMUP_DELAY_MS adjusts the warmup delay.
1177
1346
  let startupMode = resolveStartupMode();
1347
+ // SAFETY: these two flags are process-lifetime state pi-lens stashes on
1348
+ // `globalThis` so a second extension instance in the same process sees the
1349
+ // first one's warmup. There is no ambient declaration for them, and adding
1350
+ // one would let any module write them. Both are declared OPTIONAL here, so
1351
+ // the reads below are `undefined`-safe on a process where nothing set them.
1178
1352
  const processGlobals = globalThis;
1179
1353
  const isFirstSessionOfProcess = !processGlobals.__piLensFirstSessionDone;
1180
1354
  if (isFirstSessionOfProcess &&
@@ -1185,6 +1359,20 @@ export async function handleSessionStart(deps) {
1185
1359
  startupMode = deps.startupModeOverride ?? "quick";
1186
1360
  }
1187
1361
  processGlobals.__piLensFirstSessionDone = true;
1362
+ // #1785 F5 (round 4, design (a)): the warmup timer body below ALREADY
1363
+ // loads the on-disk snapshot for its own purposes (`cachedSnapshot`,
1364
+ // reused for the `startupScan` verdict cache) strictly BEFORE any save it
1365
+ // might go on to make. This LOCAL variable — per-`handleSessionStart`-call,
1366
+ // deliberately NOT module-scope (see #1785 F6) — lets the warmup publish
1367
+ // that already-loaded read (narrowed to exports+rules, never the full
1368
+ // object with `wordIndex`) for `retroactivelyHydrateAfterDeferredSequence`
1369
+ // to reuse at zero additional cost, instead of this call paying for its
1370
+ // own separate synchronous capture (rounds 1-3's approach, reverted here:
1371
+ // see that function's doc comment for the full history). `undefined`
1372
+ // means the warmup hasn't reached its own read yet (or was never armed by
1373
+ // this call at all) — the quick-mode block's retroactive-hydration
1374
+ // callback then falls back to a live re-load instead.
1375
+ let warmupOwnSnapshotRead;
1188
1376
  // #1154: quick mode is entered on BOTH `pi -p`/`--print` (a one-shot that
1189
1377
  // exits right after this turn) and an interactive process's first
1190
1378
  // session_start (forced quick to protect keystroke latency, then warms
@@ -1232,6 +1420,23 @@ export async function handleSessionStart(deps) {
1232
1420
  // reuse it instead of re-walking a possibly huge tree from
1233
1421
  // scratch on every single startup.
1234
1422
  const cachedSnapshot = loadProjectSnapshot(warmupSnapshotRoot);
1423
+ // #1785 F5 (round 4): publish this ALREADY-loaded read — narrowed
1424
+ // to exports+rules, never a reference to `cachedSnapshot` itself
1425
+ // (which carries `wordIndex`/`files`/`symbols`/`reverseDeps`) — for
1426
+ // `retroactivelyHydrateAfterDeferredSequence` to reuse. This read
1427
+ // strictly precedes the warmup's own possible save a few lines
1428
+ // below, so it is guaranteed to reflect disk as it stood before
1429
+ // THIS warmup could have touched it. Zero marginal cost: this read
1430
+ // already happens unconditionally for the `startupScan` verdict
1431
+ // cache below, with or without this fix.
1432
+ warmupOwnSnapshotRead = cachedSnapshot
1433
+ ? {
1434
+ version: cachedSnapshot.version,
1435
+ seq: cachedSnapshot.seq,
1436
+ cachedExports: cachedSnapshot.cachedExports,
1437
+ projectRulesScan: cachedSnapshot.projectRulesScan,
1438
+ }
1439
+ : null;
1235
1440
  const cachedVerdict = cachedSnapshot?.startupScan;
1236
1441
  let scan;
1237
1442
  if (cachedVerdict &&
@@ -1381,7 +1586,7 @@ export async function handleSessionStart(deps) {
1381
1586
  }
1382
1587
  const allowBootstrapTasks = startupMode === "full";
1383
1588
  const quickMode = startupMode === "quick";
1384
- const { ctxCwd, getFlag, notify, dbg, log, runtime, metricsClient, cacheManager, testRunnerClient, goClient, rustClient, ensureTool, cleanStaleTsBuildInfo, resetDispatchBaselines, resetLSPService, } = deps;
1589
+ const { ctxCwd, getFlag, notify, dbg, log, runtime, metricsClient, knipClient, cacheManager, testRunnerClient, goClient, rustClient, ensureTool, cleanStaleTsBuildInfo, resetDispatchBaselines, resetLSPService, } = deps;
1385
1590
  // Lightweight phase timer — resets after each call so each log line shows
1386
1591
  // the cost of that phase alone, not cumulative time from session start.
1387
1592
  let _phaseT = Date.now();
@@ -1415,9 +1620,66 @@ export async function handleSessionStart(deps) {
1415
1620
  // the tool for the rest of the process lifetime. Clear it here, same
1416
1621
  // boundary as the other per-session caches on this line.
1417
1622
  resetDispatchAvailabilityState();
1623
+ // #1895: formatter PATH verdicts are session-scoped, but they live in
1624
+ // formatters.ts and are not covered by the dispatch generation. Re-arm them
1625
+ // here so a formatter installed or removed between sessions is observed by
1626
+ // the next session. `clearFormatterCache` drops the per-cwd selection cache
1627
+ // as well as the which latches, which is what a real re-probe needs: the
1628
+ // selection cache answers a same-cwd lookup before any probe runs, so
1629
+ // clearing the latches alone would leave the stale verdict standing in the
1630
+ // one directory the user is working in.
1631
+ clearFormatterCache();
1632
+ // #1535: same #1266 pattern, one caller earlier — the `gh auth token` latch
1633
+ // zizmor's spawn reads is process-lived storage whose durability contract is
1634
+ // per SESSION, not per process. Without this, a user who runs `gh auth
1635
+ // login` and starts a fresh session still reads the previous session's
1636
+ // stale "no token" verdict until the cooldown (if any) happens to expire.
1637
+ resetZizmorTokenAvailability();
1638
+ // psscriptanalyzer's three latches (interpreter, module, -File exec) are
1639
+ // module-local, so the generation counter above does not reach them
1640
+ // (#1490, #1540).
1641
+ resetPsScriptAnalyzerAvailability();
1642
+ // #1497: the install-class retry ceiling is terminal for a SESSION, but the
1643
+ // latches holding it live on process-lived client instances (bootstrap builds
1644
+ // them once). Same #1266/#1490/#1535 shape — without this line "terminal for
1645
+ // the session" is terminal for the process, and a repaired network never
1646
+ // re-earns its `go install`.
1647
+ resetInstallRetryLatches();
1648
+ // #1537: the lazy-install seam's hold (`gem install rubocop`, `rustup
1649
+ // component add`) is durable for a SESSION. Its map is module-local, so the
1650
+ // generation counter above does not reach it — same #1490/#1497 shape. It
1651
+ // belongs on THIS line and not on the turn_end path: the first cut cleared it
1652
+ // from `clearFormatterRuntimeState()`, which runs every turn, so a failing
1653
+ // install re-spawned every turn instead of once per session.
1654
+ resetLazyInstallAttempts();
1655
+ // #1897: direct-LSP negative availability and bare installer paths are
1656
+ // session facts. A command or PATH entry can appear between sessions.
1657
+ resetDirectLspCommandAvailability();
1658
+ resetResolvedPathCache();
1659
+ // #1653: pnpm/yarn/bun/npm's availability latches (package-manager.ts) are
1660
+ // module-local, same #1490/#1535 shape as the two lines above — the
1661
+ // generation counter above does not reach them. Without this line, a
1662
+ // pnpm/yarn/bun install done mid-day stayed invisible: a genuine "missing"
1663
+ // verdict from one session latched into the next until a process restart.
1664
+ _resetPackageManagerCache();
1665
+ // #1730: the managed-tool refresh budget is a per-SESSION allowance (at most
1666
+ // one `npm update` per session). Left process-lived, one long-running pi
1667
+ // would refresh a single tool at launch and never look at the other 21
1668
+ // again — the same latch shape as the two lines above. The weekly cadence
1669
+ // itself is NOT reset here: it lives in the persisted per-tool stamp, so
1670
+ // re-arming the budget only restores the session's right to ask.
1671
+ resetManagedToolRefreshSession();
1418
1672
  // #1123 item 3: a fresh session can re-report smells that a prior session
1419
1673
  // already surfaced once (see `checkSmellsAndNoteOnce`'s once-per-session gate).
1420
1674
  resetSmellsSessionState();
1675
+ // #1782: re-arm the workspace-diagnostics cache session clock. Entries
1676
+ // written before this instant assert findings from a session that is over,
1677
+ // so they must revalidate before they can be served as current again.
1678
+ resetWorkspaceDiagnosticsCacheSession(sessionStartMs);
1679
+ // Some embedders inject a capability-shaped Knip client rather than the
1680
+ // concrete KnipClient. Session reset is an optional lifecycle capability;
1681
+ // its absence must not make session_start fail.
1682
+ knipClient.resetSessionState?.();
1421
1683
  runtime.resetForSession(sessionStartMs);
1422
1684
  logLatency({
1423
1685
  type: "phase",
@@ -1471,11 +1733,21 @@ export async function handleSessionStart(deps) {
1471
1733
  // project data roots and machine-global registry root once per session start;
1472
1734
  // this is fire-and-forget and bounded so it never delays startup.
1473
1735
  const projectDataDir = getProjectDataDir(cwd);
1736
+ // #1609 review F1: sweepOwnStagingFiles does not recurse, so the installer's
1737
+ // bin/ and tools/ subdirectories (clients/installer/index.ts's
1738
+ // GITHUB_BIN_DIR / TOOLS_DIR, now atomic-write.js writers too) need their
1739
+ // own entries — otherwise an orphaned staging file from a kill mid-install
1740
+ // (this PR's own motivating scenario) never gets reaped, and unique
1741
+ // pid-thread-seq staging names mean repeated kills ACCUMULATE full-size
1742
+ // orphan binaries instead of being cleaned up.
1743
+ const globalDir = getGlobalPiLensDir();
1474
1744
  void sweepAtomicWriteStages([
1475
1745
  projectDataDir,
1476
1746
  path.join(projectDataDir, "cache"),
1477
1747
  path.join(projectDataDir, "sessions"),
1478
- getGlobalPiLensDir(),
1748
+ globalDir,
1749
+ path.join(globalDir, "bin"),
1750
+ path.join(globalDir, "tools"),
1479
1751
  ]).catch(() => {
1480
1752
  // best-effort lifecycle cleanup — never fail session_start
1481
1753
  });
@@ -1483,6 +1755,12 @@ export async function handleSessionStart(deps) {
1483
1755
  runtime.projectRoot = cwd;
1484
1756
  const sequenceReadStartedAt = Date.now();
1485
1757
  const snapshotRoot = resolveSnapshotRoot(cwd);
1758
+ // #1785 F5 (round 4): the getter closes over `warmupOwnSnapshotRead`
1759
+ // directly (a `let` in this same `handleSessionStart` invocation's
1760
+ // scope), so it reads whatever value is current AT DEFERRED-RESOLVE
1761
+ // TIME — not whatever it was at this wiring instant. See
1762
+ // `retroactivelyHydrateAfterDeferredSequence`'s doc comment for the
1763
+ // full design.
1486
1764
  const { latestSeq, timedOut } = await readSequenceWithBudget({
1487
1765
  snapshotRoot,
1488
1766
  base: snapshotSequenceBase(snapshotRoot),
@@ -1490,6 +1768,12 @@ export async function handleSessionStart(deps) {
1490
1768
  runtime,
1491
1769
  sessionGeneration: runtime.sessionGeneration,
1492
1770
  dbg,
1771
+ onDeferredSequenceResolved: retroactivelyHydrateAfterDeferredSequence({
1772
+ getWarmupOwnSnapshotRead: () => warmupOwnSnapshotRead,
1773
+ snapshotRoot,
1774
+ runtime,
1775
+ dbg,
1776
+ }),
1493
1777
  });
1494
1778
  logLatency({
1495
1779
  type: "phase",
@@ -1499,6 +1783,12 @@ export async function handleSessionStart(deps) {
1499
1783
  durationMs: Date.now() - sequenceReadStartedAt,
1500
1784
  metadata: { entries: latestSeq.fileSeqByPath.size, timedOut },
1501
1785
  });
1786
+ if (timedOut) {
1787
+ recordSnapshotSequenceTimeout({
1788
+ snapshotRoot,
1789
+ snapshotPath: getProjectSnapshotPath(snapshotRoot),
1790
+ });
1791
+ }
1502
1792
  runtime.seedProjectSequence?.(latestSeq.projectSeq, latestSeq.fileSeqByPath);
1503
1793
  const effectiveSeq = runtime.projectSeq ?? latestSeq.projectSeq;
1504
1794
  dbg(`session_start sequence: projectSeq=${effectiveSeq} fileSeqEntries=${latestSeq.fileSeqByPath.size}`);
@@ -1522,6 +1812,8 @@ export async function handleSessionStart(deps) {
1522
1812
  catch {
1523
1813
  // Missing snapshots are the normal cold-start case.
1524
1814
  }
1815
+ const snapshotBodyPresent = nodeFs.existsSync(snapshotPath) ||
1816
+ nodeFs.existsSync(getProjectSnapshotLegacyPath(snapshotRoot));
1525
1817
  const snapshotGate = loadSnapshotBodyUnlessStale({
1526
1818
  root: snapshotRoot,
1527
1819
  currentProjectSeq: freshnessSeq,
@@ -1529,6 +1821,10 @@ export async function handleSessionStart(deps) {
1529
1821
  });
1530
1822
  const snapshot = snapshotGate.snapshot;
1531
1823
  const snapshotFresh = isProjectSnapshotFresh(snapshot, freshnessSeq);
1824
+ const snapshotMissReason = describeSnapshotMiss(snapshot, freshnessSeq, {
1825
+ skippedStale: snapshotGate.skippedStale,
1826
+ bodyPresent: snapshotBodyPresent,
1827
+ });
1532
1828
  logLatency({
1533
1829
  type: "phase",
1534
1830
  phase: "session_start_snapshot_load",
@@ -1539,6 +1835,7 @@ export async function handleSessionStart(deps) {
1539
1835
  bytes: snapshotBytes,
1540
1836
  fresh: snapshotFresh,
1541
1837
  seq: snapshot?.seq ?? null,
1838
+ reason: snapshotFresh ? undefined : snapshotMissReason,
1542
1839
  ...(snapshotGate.skippedStale ? { skippedStale: true } : {}),
1543
1840
  ...(timedOut ? { sequenceUnknown: true } : {}),
1544
1841
  },
@@ -1548,6 +1845,7 @@ export async function handleSessionStart(deps) {
1548
1845
  root: snapshotRoot,
1549
1846
  currentProjectSeq: freshnessSeq,
1550
1847
  snapshot,
1848
+ missReason: snapshotMissReason,
1551
1849
  });
1552
1850
  if (snapshotFresh) {
1553
1851
  hydrateRuntimeFromProjectSnapshot(runtime, snapshot);
@@ -1569,6 +1867,7 @@ export async function handleSessionStart(deps) {
1569
1867
  durationMs: totalDurationMs,
1570
1868
  metadata: { mode: startupMode, reason: deps.sessionReason },
1571
1869
  });
1870
+ logHostReadyDelay(deps, cwd);
1572
1871
  emitSmellsSessionStartLine(dbg, sessionStartMs);
1573
1872
  return;
1574
1873
  }
@@ -1605,6 +1904,20 @@ export async function handleSessionStart(deps) {
1605
1904
  durationMs: Date.now() - sequenceReadStartedAt,
1606
1905
  metadata: { entries: latestSeq.fileSeqByPath.size, timedOut },
1607
1906
  });
1907
+ if (timedOut) {
1908
+ // #1785: instrumentation only here, deliberately no
1909
+ // `onDeferredSequenceResolved` — unlike quick mode's cold path (which
1910
+ // does nothing when the snapshot isn't trusted), full mode's cold path
1911
+ // actively kicks off a real rescan below to rebuild this same state.
1912
+ // Retroactively hydrating from the on-disk snapshot once the deferred
1913
+ // read lands could overwrite that fresher, actively-computed state with
1914
+ // the stale disk copy — a regression, not a fix. See the PR body for the
1915
+ // full reasoning.
1916
+ recordSnapshotSequenceTimeout({
1917
+ snapshotRoot,
1918
+ snapshotPath: getProjectSnapshotPath(snapshotRoot),
1919
+ });
1920
+ }
1608
1921
  runtime.seedProjectSequence?.(latestSeq.projectSeq, latestSeq.fileSeqByPath);
1609
1922
  const effectiveSeq = runtime.projectSeq ?? latestSeq.projectSeq;
1610
1923
  dbg(`session_start sequence: projectSeq=${effectiveSeq} fileSeqEntries=${latestSeq.fileSeqByPath.size}`);
@@ -1624,6 +1937,8 @@ export async function handleSessionStart(deps) {
1624
1937
  catch {
1625
1938
  // Missing snapshots are the normal cold-start case.
1626
1939
  }
1940
+ const snapshotBodyPresent = nodeFs.existsSync(snapshotPath) ||
1941
+ nodeFs.existsSync(getProjectSnapshotLegacyPath(snapshotRoot));
1627
1942
  const snapshotGate = loadSnapshotBodyUnlessStale({
1628
1943
  root: snapshotRoot,
1629
1944
  currentProjectSeq: freshnessSeq,
@@ -1631,6 +1946,10 @@ export async function handleSessionStart(deps) {
1631
1946
  });
1632
1947
  const snapshot = snapshotGate.snapshot;
1633
1948
  const snapshotFresh = isProjectSnapshotFresh(snapshot, freshnessSeq);
1949
+ const snapshotMissReason = describeSnapshotMiss(snapshot, freshnessSeq, {
1950
+ skippedStale: snapshotGate.skippedStale,
1951
+ bodyPresent: snapshotBodyPresent,
1952
+ });
1634
1953
  logLatency({
1635
1954
  type: "phase",
1636
1955
  phase: "session_start_snapshot_load",
@@ -1641,6 +1960,7 @@ export async function handleSessionStart(deps) {
1641
1960
  bytes: snapshotBytes,
1642
1961
  fresh: snapshotFresh,
1643
1962
  seq: snapshot?.seq ?? null,
1963
+ reason: snapshotFresh ? undefined : snapshotMissReason,
1644
1964
  ...(snapshotGate.skippedStale ? { skippedStale: true } : {}),
1645
1965
  ...(timedOut ? { sequenceUnknown: true } : {}),
1646
1966
  },
@@ -1650,6 +1970,7 @@ export async function handleSessionStart(deps) {
1650
1970
  root: snapshotRoot,
1651
1971
  currentProjectSeq: freshnessSeq,
1652
1972
  snapshot,
1973
+ missReason: snapshotMissReason,
1653
1974
  });
1654
1975
  const freshSnapshot = snapshotFresh ? snapshot : null;
1655
1976
  if (freshSnapshot) {
@@ -1777,6 +2098,7 @@ export async function handleSessionStart(deps) {
1777
2098
  const jstsHeavyScansWillRun = startupScansWillRun && canRunStartupHeavyScans(languageProfile, "jsts");
1778
2099
  if (allowBootstrapTasks) {
1779
2100
  scheduleDeferredToolProbes(deps, languageProfile, startupDefaults, jstsHeavyScansWillRun, dbg);
2101
+ scheduleManagedToolRefresh(dbg);
1780
2102
  }
1781
2103
  if (allowBootstrapTasks) {
1782
2104
  // Fire-and-forget like other tool probes
@@ -1889,6 +2211,7 @@ export async function handleSessionStart(deps) {
1889
2211
  durationMs: totalDurationMs,
1890
2212
  metadata: { mode: startupMode, reason: deps.sessionReason },
1891
2213
  });
2214
+ logHostReadyDelay(deps, cwd);
1892
2215
  emitSmellsSessionStartLine(dbg, sessionStartMs);
1893
2216
  }
1894
2217
  /**