@herbertgao/pi-extensions 2026.8.4 → 2026.8.6

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 (360) hide show
  1. package/README.md +5 -5
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +11 -3
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +11 -3
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +24 -0
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +91 -1
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -3
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +74 -5
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +7 -6
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +53 -14
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
  14. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  15. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +18 -0
  16. package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
  17. package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
  18. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
  19. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
  20. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +20 -4
  21. package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
  22. package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
  23. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
  24. package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +15 -6
  25. package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
  26. package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
  27. package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +9 -5
  28. package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +2 -0
  29. package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +20 -0
  30. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +6 -0
  31. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
  32. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  33. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
  34. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
  35. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
  36. package/node_modules/@narumitw/pi-btw/README.md +32 -24
  37. package/node_modules/@narumitw/pi-btw/package.json +6 -6
  38. package/node_modules/@narumitw/pi-btw/src/btw.ts +4 -2
  39. package/node_modules/@narumitw/pi-btw/src/menu.ts +34 -13
  40. package/node_modules/@narumitw/pi-btw/src/settings.ts +22 -2
  41. package/node_modules/pi-lens/CHANGELOG.md +2535 -954
  42. package/node_modules/pi-lens/README.md +13 -0
  43. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
  44. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +314 -0
  45. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
  46. package/node_modules/pi-lens/dist/clients/agent-nudge.js +14 -7
  47. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
  48. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
  49. package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
  50. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
  51. package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
  52. package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
  53. package/node_modules/pi-lens/dist/clients/biome-client.js +136 -24
  54. package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
  55. package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
  56. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
  57. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +62 -6
  58. package/node_modules/pi-lens/dist/clients/bus-publish.js +19 -4
  59. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
  60. package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
  61. package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
  62. package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
  63. package/node_modules/pi-lens/dist/clients/cascade-format.js +57 -2
  64. package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
  65. package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
  66. package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
  67. package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
  68. package/node_modules/pi-lens/dist/clients/console-guard-install.js +26 -0
  69. package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
  70. package/node_modules/pi-lens/dist/clients/dead-code-client.js +137 -31
  71. package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
  72. package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
  73. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
  74. package/node_modules/pi-lens/dist/clients/dependency-checker.js +361 -77
  75. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +65 -13
  76. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +18 -4
  77. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +176 -29
  78. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
  79. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
  80. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
  81. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
  82. package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
  83. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1172 -683
  84. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
  85. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
  86. package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
  87. package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
  88. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
  89. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
  90. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
  91. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
  92. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +154 -0
  93. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +47 -6
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +163 -0
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +226 -0
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +69 -0
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +473 -42
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +97 -0
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
  114. package/node_modules/pi-lens/dist/clients/disposition-publish.js +18 -4
  115. package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
  116. package/node_modules/pi-lens/dist/clients/eval-timestamp.js +17 -0
  117. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
  118. package/node_modules/pi-lens/dist/clients/extension-log.js +432 -0
  119. package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
  120. package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
  121. package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
  122. package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
  123. package/node_modules/pi-lens/dist/clients/fix-worklog.js +5 -1
  124. package/node_modules/pi-lens/dist/clients/format-events-publish.js +51 -7
  125. package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
  126. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
  127. package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
  128. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
  129. package/node_modules/pi-lens/dist/clients/git-guard.js +678 -11
  130. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
  131. package/node_modules/pi-lens/dist/clients/go-client.js +23 -40
  132. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +124 -7
  133. package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
  134. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
  135. package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
  136. package/node_modules/pi-lens/dist/clients/installer/index.js +395 -100
  137. package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
  138. package/node_modules/pi-lens/dist/clients/jscpd-client.js +27 -55
  139. package/node_modules/pi-lens/dist/clients/knip-client.js +58 -42
  140. package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
  141. package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
  142. package/node_modules/pi-lens/dist/clients/latency-logger.js +72 -1
  143. package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
  144. package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
  145. package/node_modules/pi-lens/dist/clients/lens-events.js +63 -9
  146. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +16 -0
  147. package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
  148. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +73 -0
  149. package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
  150. package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +30 -4
  151. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +59 -14
  152. package/node_modules/pi-lens/dist/clients/lsp/client.js +662 -56
  153. package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
  154. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +115 -0
  155. package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
  156. package/node_modules/pi-lens/dist/clients/lsp/index.js +2025 -800
  157. package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
  158. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
  159. package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
  160. package/node_modules/pi-lens/dist/clients/lsp/server.js +437 -86
  161. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +96 -0
  162. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +21 -5
  163. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +18 -3
  164. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
  165. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
  166. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
  167. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +127 -32
  168. package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
  169. package/node_modules/pi-lens/dist/clients/mcp/session.js +235 -14
  170. package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
  171. package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
  172. package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
  173. package/node_modules/pi-lens/dist/clients/model-provider.js +53 -0
  174. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
  175. package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
  176. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
  177. package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
  178. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
  179. package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
  180. package/node_modules/pi-lens/dist/clients/pipeline.js +76 -15
  181. package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
  182. package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
  183. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
  184. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +1 -1
  185. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
  186. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +23 -2
  187. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
  188. package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
  189. package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
  190. package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
  191. package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
  192. package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
  193. package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
  194. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
  195. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
  196. package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
  197. package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
  198. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
  199. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
  200. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
  201. package/node_modules/pi-lens/dist/clients/review-graph/query.js +24 -0
  202. package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
  203. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
  204. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
  205. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
  206. package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
  207. package/node_modules/pi-lens/dist/clients/run-duration.js +55 -0
  208. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +257 -77
  209. package/node_modules/pi-lens/dist/clients/runtime-context.js +129 -12
  210. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +242 -26
  211. package/node_modules/pi-lens/dist/clients/runtime-session.js +428 -117
  212. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
  213. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +342 -33
  214. package/node_modules/pi-lens/dist/clients/runtime-turn.js +619 -93
  215. package/node_modules/pi-lens/dist/clients/rust-client.js +23 -38
  216. package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
  217. package/node_modules/pi-lens/dist/clients/security-scan-client.js +90 -6
  218. package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
  219. package/node_modules/pi-lens/dist/clients/sg-runner.js +424 -196
  220. package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
  221. package/node_modules/pi-lens/dist/clients/smells-rollup.js +231 -0
  222. package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
  223. package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
  224. package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
  225. package/node_modules/pi-lens/dist/clients/startup-timing.js +7 -1
  226. package/node_modules/pi-lens/dist/clients/test-runner-client.js +469 -32
  227. package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
  228. package/node_modules/pi-lens/dist/clients/tool-policy.js +390 -39
  229. package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
  230. package/node_modules/pi-lens/dist/clients/tool-set-policy.js +76 -0
  231. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
  232. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
  233. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
  234. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
  235. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
  236. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
  237. package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
  238. package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
  239. package/node_modules/pi-lens/dist/clients/warm-attach.js +50 -13
  240. package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
  241. package/node_modules/pi-lens/dist/clients/word-index.js +680 -81
  242. package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
  243. package/node_modules/pi-lens/dist/index.js +51785 -36118
  244. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
  245. package/node_modules/pi-lens/dist/mcp/server.js +219 -46
  246. package/node_modules/pi-lens/dist/tools/activate-tools.js +17 -5
  247. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +9 -4
  248. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
  249. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +5 -2
  250. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +203 -38
  251. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +210 -42
  252. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
  253. package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
  254. package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -1
  255. package/node_modules/pi-lens/docs/agent-guide.md +40 -15
  256. package/node_modules/pi-lens/docs/agent-tools.md +21 -10
  257. package/node_modules/pi-lens/docs/analysisall.md +192 -0
  258. package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
  259. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +14 -3
  260. package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
  261. package/node_modules/pi-lens/docs/environment-variables.md +44 -0
  262. package/node_modules/pi-lens/docs/fable.md +27 -0
  263. package/node_modules/pi-lens/docs/features.md +45 -3
  264. package/node_modules/pi-lens/docs/globalconfig.md +56 -1
  265. package/node_modules/pi-lens/docs/language-coverage.md +4 -3
  266. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
  267. package/node_modules/pi-lens/docs/mcp.md +37 -4
  268. package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
  269. package/node_modules/pi-lens/docs/settings.md +18 -1
  270. package/node_modules/pi-lens/docs/tools.md +4 -1
  271. package/node_modules/pi-lens/docs/usage.md +41 -5
  272. package/node_modules/pi-lens/docs/word-index.md +35 -0
  273. package/node_modules/pi-lens/package.json +10 -10
  274. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
  275. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
  276. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +8 -0
  277. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-js-test.yml +9 -0
  278. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-test.yml +9 -0
  279. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
  280. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
  281. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +7 -0
  282. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +7 -0
  283. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +8 -0
  284. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +8 -0
  285. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-laundering-test.yml +11 -0
  286. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
  287. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
  288. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
  289. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +21 -0
  290. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread-js.yml +21 -0
  291. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread.yml +29 -0
  292. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
  293. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
  294. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +9 -0
  295. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +9 -0
  296. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +13 -0
  297. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +16 -0
  298. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +27 -0
  299. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
  300. package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
  301. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
  302. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +134 -2
  303. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +10 -11
  304. package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +22 -22
  305. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +8 -114
  306. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +129 -0
  307. package/node_modules/pi-lens/skills/pi-lens-write-tree-sitter-rule/SKILL.md +3 -1
  308. package/node_modules/pi-mcp-adapter/CHANGELOG.md +38 -0
  309. package/node_modules/pi-mcp-adapter/README.md +38 -4
  310. package/node_modules/pi-mcp-adapter/agent-dir.ts +12 -4
  311. package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
  312. package/node_modules/pi-mcp-adapter/cli.js +25 -4
  313. package/node_modules/pi-mcp-adapter/commands.ts +15 -7
  314. package/node_modules/pi-mcp-adapter/config.ts +4 -4
  315. package/node_modules/pi-mcp-adapter/direct-tools.ts +58 -8
  316. package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
  317. package/node_modules/pi-mcp-adapter/index.ts +8 -3
  318. package/node_modules/pi-mcp-adapter/init.ts +29 -5
  319. package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
  320. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
  321. package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
  322. package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
  323. package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
  324. package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +2 -1
  325. package/node_modules/pi-mcp-adapter/metadata-cache.ts +37 -4
  326. package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
  327. package/node_modules/pi-mcp-adapter/package.json +4 -3
  328. package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
  329. package/node_modules/pi-mcp-adapter/request-headers-command.ts +336 -0
  330. package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
  331. package/node_modules/pi-mcp-adapter/server-manager.ts +41 -7
  332. package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
  333. package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
  334. package/node_modules/pi-mcp-adapter/tool-metadata.ts +62 -4
  335. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
  336. package/node_modules/pi-mcp-adapter/types.ts +176 -27
  337. package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
  338. package/node_modules/pi-web-access/CHANGELOG.md +14 -0
  339. package/node_modules/pi-web-access/README.md +18 -12
  340. package/node_modules/pi-web-access/auth-fetch.ts +148 -0
  341. package/node_modules/pi-web-access/chrome-cookies.ts +110 -23
  342. package/node_modules/pi-web-access/curator-page.ts +5 -3
  343. package/node_modules/pi-web-access/curator-server.ts +2 -1
  344. package/node_modules/pi-web-access/extract.ts +106 -34
  345. package/node_modules/pi-web-access/fetch-params.ts +17 -3
  346. package/node_modules/pi-web-access/firecrawl.ts +172 -12
  347. package/node_modules/pi-web-access/gemini-search.ts +18 -4
  348. package/node_modules/pi-web-access/index.ts +120 -48
  349. package/node_modules/pi-web-access/package.json +2 -2
  350. package/node_modules/pi-web-access/summary-review.ts +11 -5
  351. package/node_modules/pi-web-access/youtube-extract.ts +2 -2
  352. package/package.json +12 -13
  353. package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
  354. package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
  355. package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
  356. package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
  357. package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
  358. package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
  359. package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
  360. package/node_modules/pi-lens/dist/clients/types.js +0 -11
@@ -265,11 +265,19 @@ function buildProjectIgnoreMatcher(resolvedRoot, patterns) {
265
265
  const patternsForDir = (dir) => {
266
266
  if (dir === resolvedRoot)
267
267
  return patterns;
268
- const gitignoreMtime = gitignoreMtimeMs(dir);
269
- const pilensMtime = findPiLensConfigInDir(dir)?.mtimeMs ?? -1;
268
+ const gitignoreSig = gitignoreSignature(dir);
269
+ // #1105: gate on size too. `findPiLensConfigInDir` returns `size` alongside
270
+ // `mtimeMs` (both from one stat), and `gitignoreSignature` reads both for
271
+ // the nested `.gitignore`, so an mtime-preserving, length-changing edit to
272
+ // EITHER nested source can no longer replay stale patterns for this subtree.
273
+ const pilensInfo = findPiLensConfigInDir(dir);
274
+ const pilensMtime = pilensInfo?.mtimeMs ?? -1;
275
+ const pilensSize = pilensInfo?.size ?? -1;
270
276
  const cached = nestedCache.get(dir);
271
- if (cached?.gitignoreMtimeMs === gitignoreMtime &&
272
- cached?.pilensMtimeMs === pilensMtime) {
277
+ if (cached?.gitignoreMtimeMs === gitignoreSig.mtimeMs &&
278
+ cached?.gitignoreSize === gitignoreSig.size &&
279
+ cached?.pilensMtimeMs === pilensMtime &&
280
+ cached?.pilensSize === pilensSize) {
273
281
  return cached.patterns;
274
282
  }
275
283
  const nestedConfig = loadPiLensConfigInDir(dir);
@@ -278,15 +286,17 @@ function buildProjectIgnoreMatcher(resolvedRoot, patterns) {
278
286
  ...parseGitignoreContent(nestedConfig.ignore.join("\n"), "pilens"),
279
287
  ];
280
288
  nestedCache.set(dir, {
281
- gitignoreMtimeMs: gitignoreMtime,
289
+ gitignoreMtimeMs: gitignoreSig.mtimeMs,
290
+ gitignoreSize: gitignoreSig.size,
282
291
  pilensMtimeMs: pilensMtime,
292
+ pilensSize: pilensSize,
283
293
  patterns: nextPatterns,
284
294
  });
285
295
  return nextPatterns;
286
296
  };
287
297
  // Per-matcher path → pattern-verdict memo. The matcher itself is cached by
288
- // `getProjectIgnoreMatcher` keyed on `.gitignore` mtime, so this Map's
289
- // lifetime is bounded to a single set of ignore rules — when any
298
+ // `getProjectIgnoreMatcher` keyed on `.gitignore` size+mtime (#1105), so this
299
+ // Map's lifetime is bounded to a single set of ignore rules — when any
290
300
  // `.gitignore` changes, the matcher is rebuilt and the memo is dropped
291
301
  // with it. Without this memo, every background scan (comment scan, knip,
292
302
  // jscpd, call-graph, source-filter, pipeline) recomputes O(ancestorDirs ×
@@ -402,26 +412,20 @@ export function createProjectIgnoreMatcher(rootDir, extraPatterns = [], globalPa
402
412
  return buildProjectIgnoreMatcher(resolvedRoot, patterns);
403
413
  }
404
414
  const projectIgnoreMatcherCache = new Map();
405
- /**
406
- * mtime of the global `~/.pi-lens/config.json` (or the PI_LENS_CONFIG_PATH
407
- * override). Part of the ignore-matcher cache key so editing global ignore
408
- * patterns takes effect without a restart (#252). -1 when absent.
409
- */
410
- function globalConfigMtimeMs() {
415
+ function fileFreshnessSignature(filePath) {
411
416
  try {
412
- return fs.statSync(getPiLensGlobalConfigPath()).mtimeMs;
417
+ const stat = fs.statSync(filePath);
418
+ return { mtimeMs: stat.mtimeMs, size: stat.size };
413
419
  }
414
420
  catch {
415
- return -1;
421
+ return { mtimeMs: -1, size: -1 };
416
422
  }
417
423
  }
418
- function gitignoreMtimeMs(rootDir) {
419
- try {
420
- return fs.statSync(path.join(rootDir, ".gitignore")).mtimeMs;
421
- }
422
- catch {
423
- return -1;
424
- }
424
+ function globalConfigSignature() {
425
+ return fileFreshnessSignature(getPiLensGlobalConfigPath());
426
+ }
427
+ function gitignoreSignature(rootDir) {
428
+ return fileFreshnessSignature(path.join(rootDir, ".gitignore"));
425
429
  }
426
430
  /**
427
431
  * The project config file found by the same upward walk as the loader. Cache
@@ -432,32 +436,39 @@ function gitignoreMtimeMs(rootDir) {
432
436
  function lensConfigInfo(rootDir) {
433
437
  const info = findPiLensProjectConfig(rootDir);
434
438
  return info
435
- ? { info, path: info.path, mtimeMs: info.mtimeMs }
436
- : { info, path: undefined, mtimeMs: -1 };
439
+ ? { info, path: info.path, mtimeMs: info.mtimeMs, size: info.size }
440
+ : { info, path: undefined, mtimeMs: -1, size: -1 };
437
441
  }
438
442
  export function getProjectIgnoreMatcher(rootDir) {
439
443
  const resolvedRoot = resolveGitIgnoreRoot(rootDir);
440
- const gitignoreMtime = gitignoreMtimeMs(resolvedRoot);
444
+ const gitignoreSig = gitignoreSignature(resolvedRoot);
441
445
  const lensConfig = lensConfigInfo(resolvedRoot);
442
- const globalMtime = globalConfigMtimeMs();
446
+ const globalSig = globalConfigSignature();
443
447
  const cached = projectIgnoreMatcherCache.get(resolvedRoot);
444
- if (cached?.gitignoreMtimeMs === gitignoreMtime &&
448
+ if (cached?.gitignoreMtimeMs === gitignoreSig.mtimeMs &&
449
+ cached?.gitignoreSize === gitignoreSig.size &&
445
450
  cached?.lensConfigPath === lensConfig.path &&
446
451
  cached?.lensConfigMtimeMs === lensConfig.mtimeMs &&
447
- cached?.globalConfigMtimeMs === globalMtime) {
452
+ cached?.lensConfigSize === lensConfig.size &&
453
+ cached?.globalConfigMtimeMs === globalSig.mtimeMs &&
454
+ cached?.globalConfigSize === globalSig.size) {
448
455
  return cached.matcher;
449
456
  }
450
457
  // Load both configs fresh on cache miss. On a cache HIT (the common case)
451
- // none of this runs — the only per-call cost is the mtime stats above. The
452
- // project loader is itself mtime-cached; the global loader re-parses, but
453
- // only here on miss (when some tracked mtime changed).
458
+ // none of this runs — the only per-call cost is the size:mtimeMs stats above
459
+ // (size is free from the same stat). The project loader is itself
460
+ // size:mtimeMs-cached; the global loader re-parses, but only here on miss
461
+ // (when some tracked signature changed).
454
462
  const projectConfig = loadPiLensProjectConfig(resolvedRoot, lensConfig.info);
455
463
  const matcher = createProjectIgnoreMatcher(resolvedRoot, projectConfig.ignore, getGlobalIgnorePatterns());
456
464
  projectIgnoreMatcherCache.set(resolvedRoot, {
457
- gitignoreMtimeMs: gitignoreMtime,
465
+ gitignoreMtimeMs: gitignoreSig.mtimeMs,
466
+ gitignoreSize: gitignoreSig.size,
458
467
  lensConfigPath: lensConfig.path,
459
468
  lensConfigMtimeMs: lensConfig.mtimeMs,
460
- globalConfigMtimeMs: globalMtime,
469
+ lensConfigSize: lensConfig.size,
470
+ globalConfigMtimeMs: globalSig.mtimeMs,
471
+ globalConfigSize: globalSig.size,
461
472
  matcher,
462
473
  });
463
474
  return matcher;
@@ -465,10 +476,21 @@ export function getProjectIgnoreMatcher(rootDir) {
465
476
  export function isPathIgnoredByProject(filePath, rootDir, isDirectory = false) {
466
477
  return getProjectIgnoreMatcher(rootDir).isIgnored(filePath, isDirectory);
467
478
  }
479
+ const projectIgnoreGlobsCache = new Map();
468
480
  export function getProjectIgnoreGlobs(rootDir) {
469
- return readGitignorePatterns(rootDir)
481
+ const resolvedRoot = path.resolve(rootDir);
482
+ const signature = gitignoreSignature(resolvedRoot);
483
+ const cached = projectIgnoreGlobsCache.get(resolvedRoot);
484
+ if (cached &&
485
+ cached.mtimeMs === signature.mtimeMs &&
486
+ cached.size === signature.size) {
487
+ return cached.globs;
488
+ }
489
+ const globs = readGitignorePatterns(resolvedRoot)
470
490
  .filter((pattern) => !pattern.negated)
471
491
  .flatMap((pattern) => expandGitignorePattern(pattern));
492
+ projectIgnoreGlobsCache.set(resolvedRoot, { ...signature, globs });
493
+ return globs;
472
494
  }
473
495
  /**
474
496
  * Read simple directory-name entries from a root .gitignore.
@@ -18,13 +18,15 @@ export function getWorklogPath(cwd) {
18
18
  * diagnostics that were already fixed by the tool, `false` for
19
19
  * diagnostics that are fixable but require agent action.
20
20
  */
21
- export function appendToWorklog(cwd, diagnostics, autoFixed) {
21
+ export function appendToWorklog(cwd, diagnostics, autoFixed, identity) {
22
22
  if (diagnostics.length === 0)
23
23
  return;
24
24
  const worklogPath = getWorklogPath(cwd);
25
25
  try {
26
26
  fs.mkdirSync(path.dirname(worklogPath), { recursive: true });
27
27
  const timestamp = new Date().toISOString();
28
+ const model = identity?.model?.trim() || undefined;
29
+ const provider = identity?.provider?.trim() || undefined;
28
30
  const lines = diagnostics
29
31
  .map((d) => {
30
32
  const entry = {
@@ -38,6 +40,8 @@ export function appendToWorklog(cwd, diagnostics, autoFixed) {
38
40
  fixable: d.fixable ?? false,
39
41
  fixSuggestion: d.fixSuggestion,
40
42
  autoFixed,
43
+ model,
44
+ provider,
41
45
  };
42
46
  return JSON.stringify(entry);
43
47
  })
@@ -59,7 +59,15 @@
59
59
  * New optional fields may be added under the same `v: 1` for any of the three
60
60
  * events; a breaking change to an existing field's meaning must bump that
61
61
  * event's `v` independently (each event versions separately since they're
62
- * unrelated payloads).
62
+ * unrelated payloads). `FormatQueuedPayload.kinds` (S3d, #1432 review) is now
63
+ * an always-present required field at `publishFormatQueued`'s call boundary —
64
+ * both in-repo callers already passed it, so the `?? ["format"]` fallback
65
+ * was fabricating data no caller asked for. This is NOT a `v` bump: `kinds`
66
+ * was already part of the v1 payload shape and every wire-format consumer
67
+ * still reads the same field; a v1 emitter built against an older copy of
68
+ * this module that omits `kinds` at the call site now fails to compile
69
+ * rather than silently emitting a guessed value, and any reader written
70
+ * against v1 that still treats `kinds` as possibly-absent remains correct.
63
71
  *
64
72
  * Fire-and-forget: publishing must never affect the write path's or
65
73
  * `agent_end`'s success or latency. Any failure (bus unavailable, emit
@@ -70,13 +78,14 @@
70
78
  import { logBusEvent } from "./bus-events-logger.js";
71
79
  import { isBusPublishEnabled } from "./bus-publish.js";
72
80
  import { normalizeFilePath } from "./path-utils.js";
81
+ import { createLiveBusEmitter, recordStaleBusFailure, resolveLiveBusEmitter, } from "./live-bus-emitter.js";
73
82
  export const BUS_FORMAT_QUEUED_EVENT = "pilens:format:queued";
74
83
  export const BUS_FORMAT_QUEUED_VERSION = 1;
75
84
  export const BUS_FORMAT_START_EVENT = "pilens:format:start";
76
85
  export const BUS_FORMAT_START_VERSION = 1;
77
86
  export const BUS_AUTOFIX_START_EVENT = "pilens:autofix:start";
78
87
  export const BUS_AUTOFIX_START_VERSION = 1;
79
- let busEmit;
88
+ const liveEmitter = createLiveBusEmitter();
80
89
  let hasLoggedQueuedFailure = false;
81
90
  let hasLoggedQueuedUnwired = false;
82
91
  let hasLoggedQueuedDisabled = false;
@@ -93,11 +102,14 @@ let hasLoggedAutofixStartDisabled = false;
93
102
  * identical `pi.events.emit` binding, wired separately per producer.
94
103
  */
95
104
  export function wireFormatEventsBusEmitter(emitFn) {
96
- busEmit = emitFn;
105
+ liveEmitter.wire(emitFn);
106
+ }
107
+ export function wireFormatEventsBusEmitterGetter(getter) {
108
+ liveEmitter.wireGetter(getter);
97
109
  }
98
110
  /** Test-only: reset module state between test files. */
99
111
  export function _resetFormatEventsPublishForTests() {
100
- busEmit = undefined;
112
+ liveEmitter.reset();
101
113
  hasLoggedQueuedFailure = false;
102
114
  hasLoggedQueuedUnwired = false;
103
115
  hasLoggedQueuedDisabled = false;
@@ -127,7 +139,13 @@ export function publishFormatQueued(args) {
127
139
  }
128
140
  return;
129
141
  }
130
- if (!busEmit) {
142
+ const resolution = resolveLiveBusEmitter(liveEmitter, () => ({
143
+ event: BUS_FORMAT_QUEUED_EVENT,
144
+ cwd: normalizeFilePath(args.cwd),
145
+ }));
146
+ if (resolution.outcome === "stale-session")
147
+ return;
148
+ if (resolution.outcome === "unwired") {
131
149
  if (!hasLoggedQueuedUnwired) {
132
150
  hasLoggedQueuedUnwired = true;
133
151
  logBusEvent({
@@ -138,6 +156,7 @@ export function publishFormatQueued(args) {
138
156
  }
139
157
  return;
140
158
  }
159
+ const busEmit = resolution.emit;
141
160
  try {
142
161
  const payload = {
143
162
  v: BUS_FORMAT_QUEUED_VERSION,
@@ -145,8 +164,10 @@ export function publishFormatQueued(args) {
145
164
  filePath: normalizeFilePath(args.filePath),
146
165
  cwd: normalizeFilePath(args.cwd),
147
166
  tool: args.tool,
167
+ kinds: args.kinds,
148
168
  };
149
169
  busEmit(BUS_FORMAT_QUEUED_EVENT, payload);
170
+ hasLoggedQueuedFailure = false;
150
171
  logBusEvent({
151
172
  event: BUS_FORMAT_QUEUED_EVENT,
152
173
  outcome: "emitted",
@@ -160,9 +181,11 @@ export function publishFormatQueued(args) {
160
181
  outcome: "emit_failed",
161
182
  cwd: normalizeFilePath(args.cwd),
162
183
  error: String(err),
184
+ ctxSource: resolution.ctxSource,
163
185
  });
164
186
  if (!hasLoggedQueuedFailure) {
165
187
  hasLoggedQueuedFailure = true;
188
+ recordStaleBusFailure(BUS_FORMAT_QUEUED_EVENT, err);
166
189
  args.dbg?.(`format-events-publish: pilens:format:queued emit failed (further failures suppressed): ${err}`);
167
190
  }
168
191
  }
@@ -189,7 +212,13 @@ export function publishFormatStart(args) {
189
212
  }
190
213
  return;
191
214
  }
192
- if (!busEmit) {
215
+ const resolution = resolveLiveBusEmitter(liveEmitter, () => ({
216
+ event: BUS_FORMAT_START_EVENT,
217
+ cwd: normalizeFilePath(args.cwd),
218
+ }));
219
+ if (resolution.outcome === "stale-session")
220
+ return;
221
+ if (resolution.outcome === "unwired") {
193
222
  if (!hasLoggedStartUnwired) {
194
223
  hasLoggedStartUnwired = true;
195
224
  logBusEvent({
@@ -200,6 +229,7 @@ export function publishFormatStart(args) {
200
229
  }
201
230
  return;
202
231
  }
232
+ const busEmit = resolution.emit;
203
233
  try {
204
234
  const paths = args.paths.map((p) => normalizeFilePath(p));
205
235
  const payload = {
@@ -208,8 +238,10 @@ export function publishFormatStart(args) {
208
238
  cwd: normalizeFilePath(args.cwd),
209
239
  paths,
210
240
  fileCount: paths.length,
241
+ kinds: args.kinds ?? ["format"],
211
242
  };
212
243
  busEmit(BUS_FORMAT_START_EVENT, payload);
244
+ hasLoggedStartFailure = false;
213
245
  logBusEvent({
214
246
  event: BUS_FORMAT_START_EVENT,
215
247
  outcome: "emitted",
@@ -223,9 +255,11 @@ export function publishFormatStart(args) {
223
255
  outcome: "emit_failed",
224
256
  cwd: normalizeFilePath(args.cwd),
225
257
  error: String(err),
258
+ ctxSource: resolution.ctxSource,
226
259
  });
227
260
  if (!hasLoggedStartFailure) {
228
261
  hasLoggedStartFailure = true;
262
+ recordStaleBusFailure(BUS_FORMAT_START_EVENT, err);
229
263
  args.dbg?.(`format-events-publish: pilens:format:start emit failed (further failures suppressed): ${err}`);
230
264
  }
231
265
  }
@@ -255,7 +289,13 @@ export function publishAutofixStart(args) {
255
289
  }
256
290
  return;
257
291
  }
258
- if (!busEmit) {
292
+ const resolution = resolveLiveBusEmitter(liveEmitter, () => ({
293
+ event: BUS_AUTOFIX_START_EVENT,
294
+ cwd: normalizeFilePath(args.cwd),
295
+ }));
296
+ if (resolution.outcome === "stale-session")
297
+ return;
298
+ if (resolution.outcome === "unwired") {
259
299
  if (!hasLoggedAutofixStartUnwired) {
260
300
  hasLoggedAutofixStartUnwired = true;
261
301
  logBusEvent({
@@ -266,6 +306,7 @@ export function publishAutofixStart(args) {
266
306
  }
267
307
  return;
268
308
  }
309
+ const busEmit = resolution.emit;
269
310
  try {
270
311
  const paths = args.paths.map((p) => normalizeFilePath(p));
271
312
  const payload = {
@@ -277,6 +318,7 @@ export function publishAutofixStart(args) {
277
318
  eligibleCount: args.eligibleCount,
278
319
  };
279
320
  busEmit(BUS_AUTOFIX_START_EVENT, payload);
321
+ hasLoggedAutofixStartFailure = false;
280
322
  logBusEvent({
281
323
  event: BUS_AUTOFIX_START_EVENT,
282
324
  outcome: "emitted",
@@ -290,9 +332,11 @@ export function publishAutofixStart(args) {
290
332
  outcome: "emit_failed",
291
333
  cwd: normalizeFilePath(args.cwd),
292
334
  error: String(err),
335
+ ctxSource: resolution.ctxSource,
293
336
  });
294
337
  if (!hasLoggedAutofixStartFailure) {
295
338
  hasLoggedAutofixStartFailure = true;
339
+ recordStaleBusFailure(BUS_AUTOFIX_START_EVENT, err);
296
340
  args.dbg?.(`format-events-publish: pilens:autofix:start emit failed (further failures suppressed): ${err}`);
297
341
  }
298
342
  }
@@ -10,10 +10,11 @@
10
10
  * - FileTime integration for safety
11
11
  * - Explicit config wins; otherwise smart defaults apply
12
12
  */
13
+ import { logExtension } from "./extension-log.js";
13
14
  import * as path from "node:path";
14
15
  import { recordFormatter } from "./widget-state.js";
15
16
  import { FileTime } from "./file-time.js";
16
- import { clearFormatterRuntimeState, formatFile, getFormattersForFile, } from "./formatters.js";
17
+ import { loadFormatters } from "./formatters-lazy.js";
17
18
  // --- Configuration ---
18
19
  /** Reserved for future batching; formatting currently runs one selected formatter per file. */
19
20
  const DEFAULT_FORMATTER_CONCURRENCY = 1;
@@ -42,7 +43,12 @@ export class FormatService {
42
43
  }
43
44
  // Check if file was modified externally (safety check)
44
45
  if (this.fileTime.hasChanged(absolutePath)) {
45
- console.warn(`[format] File ${absolutePath} modified externally, skipping format`);
46
+ logExtension({
47
+ subsystem: "format",
48
+ level: "warn",
49
+ message: `File ${absolutePath} modified externally, skipping format`,
50
+ metadata: { filePath: absolutePath },
51
+ });
46
52
  return {
47
53
  filePath: absolutePath,
48
54
  formatters: [],
@@ -53,7 +59,7 @@ export class FormatService {
53
59
  // Get formatters for this file
54
60
  const formatters = options.formatters
55
61
  ? await this.getFormattersByName(options.formatters)
56
- : await getFormattersForFile(absolutePath, cwd);
62
+ : await (await loadFormatters()).getFormattersForFile(absolutePath, cwd);
57
63
  if (formatters.length === 0) {
58
64
  return {
59
65
  filePath: absolutePath,
@@ -90,13 +96,19 @@ export class FormatService {
90
96
  async runFormattersWithConcurrency(filePath, formatters, _concurrency = DEFAULT_FORMATTER_CONCURRENCY) {
91
97
  const results = [];
92
98
  for (const formatter of formatters) {
99
+ // #1097: keep the timer handle so it can be cleared once the race
100
+ // settles. An uncleared, REF'D 30s setTimeout that outlives a fast
101
+ // `formatFile` win would keep a one-shot `pi --print` process alive for
102
+ // up to 30s after completion (same uncleared-race-timeout class as the
103
+ // LSP client-wait leak fixed in clients/lsp/index.ts).
104
+ let formatTimer;
93
105
  try {
94
106
  const timeoutMs = 30000;
95
107
  const timeoutPromise = new Promise((_, reject) => {
96
- setTimeout(() => reject(new Error(`Formatter ${formatter.name} timed out after ${timeoutMs}ms`)), timeoutMs);
108
+ formatTimer = setTimeout(() => reject(new Error(`Formatter ${formatter.name} timed out after ${timeoutMs}ms`)), timeoutMs);
97
109
  });
98
110
  const result = await Promise.race([
99
- formatFile(filePath, formatter),
111
+ loadFormatters().then(({ formatFile }) => formatFile(filePath, formatter)),
100
112
  timeoutPromise,
101
113
  ]);
102
114
  results.push(result);
@@ -108,6 +120,10 @@ export class FormatService {
108
120
  error: error instanceof Error ? error.message : String(error),
109
121
  });
110
122
  }
123
+ finally {
124
+ if (formatTimer)
125
+ clearTimeout(formatTimer);
126
+ }
111
127
  }
112
128
  return results;
113
129
  }
@@ -115,7 +131,7 @@ export class FormatService {
115
131
  * Get formatters by name (for explicit formatter selection)
116
132
  */
117
133
  async getFormattersByName(names) {
118
- const { listAllFormatters, ...formatters } = await import("./formatters.js");
134
+ const { listAllFormatters, ...formatters } = await loadFormatters();
119
135
  const allNames = listAllFormatters();
120
136
  return names
121
137
  .filter((name) => allNames.includes(name))
@@ -151,7 +167,7 @@ export class FormatService {
151
167
  * Clear detection cache
152
168
  */
153
169
  clearCache() {
154
- clearFormatterRuntimeState();
170
+ void loadFormatters().then(({ clearFormatterRuntimeState }) => clearFormatterRuntimeState());
155
171
  }
156
172
  }
157
173
  // --- Singleton Instance ---
@@ -169,7 +185,7 @@ export function getFormatService(sessionID, enabled = true) {
169
185
  return globalFormatService;
170
186
  }
171
187
  export function resetFormatService() {
172
- clearFormatterRuntimeState();
188
+ void loadFormatters().then(({ clearFormatterRuntimeState }) => clearFormatterRuntimeState());
173
189
  globalFormatService = null;
174
190
  currentSessionID = null;
175
191
  }
@@ -0,0 +1,8 @@
1
+ /** Shared lazy formatter catalog seam (#1394). */
2
+ let formatterPromise;
3
+ export function warmFormatters() {
4
+ return (formatterPromise ??= import("./formatters.js"));
5
+ }
6
+ export function loadFormatters() {
7
+ return warmFormatters();
8
+ }