@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
@@ -0,0 +1,432 @@
1
+ /**
2
+ * Terminal-safe diagnostic sink for the in-pi extension path (#1333).
3
+ *
4
+ * pi owns the terminal: it runs the TTY in raw mode and repaints with
5
+ * cursor-addressed diffs, so ANY byte an extension writes to stdout/stderr
6
+ * lands mid-frame and desyncs pi's model of the screen — the layout stays
7
+ * broken until a full repaint. `clients/`, `tools/`, `index.ts` and `i18n.ts`
8
+ * are all reachable from the extension entry, so none of them may call
9
+ * `console.*` or `process.std*.write`. (`mcp/`, `scripts/` and `bin/` DO own
10
+ * their stdout contract and keep their writes.)
11
+ *
12
+ * This module is the general-purpose replacement sink: one `createNdjsonLogger`
13
+ * instance over `<global pi-lens dir>/extension.log`, per the single-writer
14
+ * invariant in AGENTS.md. Subsystems that already own a log (tree-sitter,
15
+ * review-graph, cascade, latency, sessionstart) route to THAT log instead —
16
+ * this file is for the areas that had no sink at all.
17
+ *
18
+ * Three-channels rule (#482/#484/#485): everything written here is
19
+ * LOG-audience. A genuinely user-facing degradation must ALSO reach the human
20
+ * through the host's own render path (`ctx.ui.notify` / a display-only session
21
+ * entry) — never a raw write.
22
+ */
23
+ import { AsyncLocalStorage } from "node:async_hooks";
24
+ import * as path from "node:path";
25
+ import { isTestMode } from "./env-utils.js";
26
+ import { getGlobalPiLensDir } from "./file-utils.js";
27
+ import { getMaxLogSizeMB } from "./log-cleanup.js";
28
+ import { createNdjsonLogger } from "./ndjson-logger.js";
29
+ export const EXTENSION_LOG_FILE = path.join(getGlobalPiLensDir(), "extension.log");
30
+ const writer = createNdjsonLogger({
31
+ filePath: EXTENSION_LOG_FILE,
32
+ maxBytes: getMaxLogSizeMB() * 1024 * 1024,
33
+ });
34
+ export function logExtension(entry) {
35
+ if (isTestMode())
36
+ return;
37
+ writer.log({
38
+ ts: new Date().toISOString(),
39
+ pid: process.pid,
40
+ level: entry.level ?? "error",
41
+ subsystem: entry.subsystem,
42
+ message: entry.message,
43
+ ...(entry.metadata ? { metadata: entry.metadata } : {}),
44
+ });
45
+ }
46
+ export function createSubsystemLogger(subsystem, defaultLevel = "debug") {
47
+ const at = (level) => (message, metadata) => {
48
+ logExtension({ subsystem, message, level, metadata });
49
+ };
50
+ const logger = at(defaultLevel);
51
+ logger.error = at("error");
52
+ logger.warn = at("warn");
53
+ logger.debug = at("debug");
54
+ return logger;
55
+ }
56
+ /** No-op with the `SubsystemLogger` shape, for the verbose-off branch. */
57
+ export function noopSubsystemLogger() {
58
+ const noop = (() => { });
59
+ noop.error = () => { };
60
+ noop.warn = () => { };
61
+ noop.debug = () => { };
62
+ return noop;
63
+ }
64
+ export function getExtensionLogPath() {
65
+ return EXTENSION_LOG_FILE;
66
+ }
67
+ /** Resolve once all enqueued extension-log writes are on disk (tests/shutdown). */
68
+ export function flushExtensionLog() {
69
+ return writer.flush();
70
+ }
71
+ /** Teardown-only: force queued entries to disk before the process exits. */
72
+ export function flushExtensionLogSync() {
73
+ writer.flushSync();
74
+ }
75
+ // --- Defense in depth: the console reroute -----------------------------------
76
+ const CONSOLE_METHODS = [
77
+ "log",
78
+ "info",
79
+ "warn",
80
+ "error",
81
+ "debug",
82
+ "trace",
83
+ "dir",
84
+ ];
85
+ let consoleGuardInstalled = false;
86
+ /** The console methods captured before the patch, for an exact restore. */
87
+ const originalConsoleMethods = new Map();
88
+ /** The replacements this module installed, so uninstall never clobbers a later patch. */
89
+ const installedConsoleMethods = new Map();
90
+ /**
91
+ * The async capture window (#1434).
92
+ *
93
+ * The guard must catch pi-lens's own writes without swallowing the host's. pi's
94
+ * one-shot CLI commands print through `console.log`, so a permanent global
95
+ * reroute makes `pi list` print nothing in any project whose cwd loads the
96
+ * extension first. The store answers "is pi-lens executing right now?" and
97
+ * `AsyncLocalStorage` carries that answer into every promise, timer and
98
+ * callback created inside the window — so an async handler still captures after
99
+ * an `await`, while host code outside the window keeps its real sink.
100
+ *
101
+ * Built LAZILY (S1b, #1434 review): an active `AsyncLocalStorage` enables an
102
+ * async_hooks init hook for every promise in the process on Node 22 — the same
103
+ * hazard `tree-sitter-client.ts`'s `parseCacheMeasurement.disable()` comment
104
+ * documents — so constructing one at module scope taxes every `await` in the
105
+ * host even when the kill switch (`PI_LENS_CONSOLE_GUARD=0`) or test mode means
106
+ * the guard never installs and nothing ever reads the store. Construction is
107
+ * deferred to the first `runInConsoleCaptureWindow` call, and only happens once
108
+ * `installConsoleGuard()` has actually installed (never under the kill switch
109
+ * or test mode, since `consoleGuardInstalled` stays false in both).
110
+ */
111
+ let consoleCaptureStorage;
112
+ function getConsoleCaptureStorage() {
113
+ if (!consoleGuardInstalled)
114
+ return undefined;
115
+ if (consoleCaptureStorage === undefined) {
116
+ consoleCaptureStorage = new AsyncLocalStorage();
117
+ }
118
+ return consoleCaptureStorage;
119
+ }
120
+ /**
121
+ * Module evaluation is the one window `AsyncLocalStorage` cannot wrap: the
122
+ * module graph is evaluated by the loader, not by a pi-lens call. It is
123
+ * synchronous, so a plain flag is enough (#1333's original concern — a
124
+ * transitively loaded dependency writing during its own init).
125
+ */
126
+ let moduleLoadWindowOpen = false;
127
+ /**
128
+ * True while pi-lens owns execution, so console writes belong in the log.
129
+ *
130
+ * `consoleCaptureStorage` may not have been constructed yet (S1b) — that state
131
+ * means "no window was ever opened through `runInConsoleCaptureWindow`", i.e.
132
+ * the same as an empty store, so it reads as "no window" rather than throwing.
133
+ */
134
+ export function isConsoleCaptureActive() {
135
+ return (moduleLoadWindowOpen || consoleCaptureStorage?.getStore() === true);
136
+ }
137
+ /**
138
+ * Open the module-evaluation window. Called by `clients/console-guard-install.ts`
139
+ * before any other pi-lens module evaluates.
140
+ *
141
+ * The window closes explicitly at the end of `index.ts`. The backstop below
142
+ * closes it anyway if that never runs (an import throws, or the entry changes
143
+ * shape), because a leaked window would capture the host's output — the very
144
+ * bug this design fixes. Module evaluation is synchronous, so the end of the
145
+ * current macrotask is always past it. The timer is unref'd, so it can never
146
+ * hold a one-shot CLI process open (defect shape 4).
147
+ */
148
+ export function openModuleLoadConsoleWindow() {
149
+ if (moduleLoadWindowOpen)
150
+ return;
151
+ moduleLoadWindowOpen = true;
152
+ const backstop = setImmediate(() => {
153
+ moduleLoadWindowOpen = false;
154
+ });
155
+ backstop.unref?.();
156
+ }
157
+ /** Close the module-evaluation window. Idempotent. */
158
+ export function closeModuleLoadConsoleWindow() {
159
+ moduleLoadWindowOpen = false;
160
+ }
161
+ /**
162
+ * Run `fn` inside a capture window. Console writes from `fn`, and from anything
163
+ * `fn` schedules, go to the extension log instead of the terminal.
164
+ *
165
+ * When the guard was never installed (kill switch or test mode), there is
166
+ * nothing for a window to gate — `installConsoleGuard`'s own dispatcher is the
167
+ * only reader of `isConsoleCaptureActive()`, and it short-circuits before that
168
+ * call in both cases. Skip constructing the `AsyncLocalStorage` (S1b) and run
169
+ * `fn` directly.
170
+ */
171
+ export function runInConsoleCaptureWindow(fn) {
172
+ const storage = getConsoleCaptureStorage();
173
+ if (!storage)
174
+ return fn();
175
+ return storage.run(true, fn);
176
+ }
177
+ function inCaptureWindow(fn) {
178
+ return function (...args) {
179
+ return runInConsoleCaptureWindow(() => fn.apply(this, args));
180
+ };
181
+ }
182
+ /**
183
+ * True for every host API member that can hand pi-lens's own functions back to
184
+ * the host to be called later: `on(event, handler)` and any `register*`
185
+ * method (`registerTool`, `registerCommand`, `registerMessageRenderer`,
186
+ * `registerShortcut`, `registerFlag`, `registerMarkdownTransformer`,
187
+ * `registerEntryRenderer`, `registerProvider`, and any the host adds later).
188
+ *
189
+ * This is a DENY-LIST, not an allow-list (#1434 S1a review): every member
190
+ * matching this predicate gets its function arguments wrapped, with no
191
+ * per-method exemption. The earlier allow-list form (only `on` and
192
+ * `registerTool`) let the 9 `registerCommand` call sites and
193
+ * `registerMessageRenderer` bypass the window, regressing #1333 for those
194
+ * paths — a host callback fired for one of them would still write straight to
195
+ * the terminal.
196
+ */
197
+ function isCaptureSeam(prop) {
198
+ return prop === "on" || (typeof prop === "string" && prop.startsWith("register"));
199
+ }
200
+ /**
201
+ * Wrap every function value found in `value`, in place. Handles the two
202
+ * shapes a `register*`/`on` call takes today: a function passed directly
203
+ * (`on(event, handler)`, `registerMessageRenderer(type, fn)`), and a
204
+ * function ONE level inside a plain options/definition object
205
+ * (`options.handler`, `tool.execute`).
206
+ *
207
+ * Deliberately NOT recursive past that one level (#1434 perf review): a tool
208
+ * definition's `parameters`/`schema` is a large, deeply nested TypeBox object
209
+ * that holds no functions, but walking its full tree on every `registerTool`
210
+ * call — across every tool, on every extension activation, across the many
211
+ * test files that re-activate the extension per case — measurably slowed
212
+ * activation (a wiring test tripped its 5s budget under transform load; see
213
+ * the commit body for the measured before/after). Checking only the
214
+ * argument's own top-level keys is O(keys), independent of how deep an
215
+ * unrelated nested value's own structure goes, and covers every shape
216
+ * PI-LENS actually registers (`options.handler`, `tool.execute` — never two
217
+ * levels deep). It does NOT cover every shape the host's `ExtensionAPI` type
218
+ * permits: `registerProvider`'s `config.oauth.*` callbacks sit two levels
219
+ * deep and `config.models[]` sits behind a skipped array. pi-lens never
220
+ * calls `registerProvider`; extend the descent if that changes (same known-
221
+ * gap convention as the `pi.events` note in AGENTS.md).
222
+ *
223
+ * Mutates the object in place rather than copying — a spread copy would drop
224
+ * non-enumerable or prototype-carried members of a definition object (defect
225
+ * shape 5), and these definitions are pi-lens's own, built just above the
226
+ * register call.
227
+ */
228
+ function wrapFunctionsInPlace(value) {
229
+ if (typeof value === "function") {
230
+ return inCaptureWindow(value);
231
+ }
232
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
233
+ return value;
234
+ }
235
+ const obj = value;
236
+ for (const key of Object.keys(obj)) {
237
+ const propValue = obj[key];
238
+ if (typeof propValue === "function") {
239
+ assignWrapped(obj, key, propValue);
240
+ }
241
+ }
242
+ return value;
243
+ }
244
+ /**
245
+ * Assign a wrapped function back onto `obj[key]`, degrading instead of
246
+ * throwing or dropping the registration when the property resists (S2b).
247
+ * ESM is always strict mode, so assigning into a non-writable data property
248
+ * throws a `TypeError`; `Object.defineProperty` is tried next (it can
249
+ * redefine a configurable-but-non-writable property); if both fail the
250
+ * property is frozen solid, so the ORIGINAL unwrapped function is left in
251
+ * place — the registration still succeeds, just without the console-capture
252
+ * net for that one callback, which is strictly better than the tool/command
253
+ * never registering at all.
254
+ */
255
+ function assignWrapped(obj, key, fn) {
256
+ const wrapped = inCaptureWindow(fn);
257
+ try {
258
+ obj[key] = wrapped;
259
+ return;
260
+ }
261
+ catch {
262
+ // Non-writable data property — fall through to defineProperty.
263
+ }
264
+ try {
265
+ Object.defineProperty(obj, key, {
266
+ value: wrapped,
267
+ writable: true,
268
+ configurable: true,
269
+ enumerable: true,
270
+ });
271
+ }
272
+ catch {
273
+ // Frozen solid: leave the original unwrapped function in place rather
274
+ // than throwing (which would abort the whole register call) or silently
275
+ // dropping it.
276
+ }
277
+ }
278
+ /**
279
+ * Wrap the host extension API so every pi-lens entry point runs in a capture
280
+ * window.
281
+ *
282
+ * pi calls our event handlers and tool bodies from its own async context, so a
283
+ * window opened during registration does not reach them. Wrapping every
284
+ * `register*`/`on` seam (see `isCaptureSeam`) covers every current and future
285
+ * handler from one place, instead of a hand-maintained list of call sites.
286
+ * Everything else forwards untouched, except it is bound to `target` (S3a) so
287
+ * a destructured reference (`const { getFlag } = pi`) keeps working, and
288
+ * wrapper functions are memoized per-proxy in `wrapperCache` (S3b) so
289
+ * `proxy.on === proxy.on` — code that compares handler identity, or a test
290
+ * asserting a mock was called with a specific function reference across two
291
+ * reads of the same property, sees a stable value.
292
+ */
293
+ export function withConsoleCaptureWindows(api) {
294
+ const wrapperCache = new Map();
295
+ const proxy = new Proxy(api, {
296
+ get(target, prop) {
297
+ // A non-configurable, non-writable OWN data property is a proxy
298
+ // invariant: the get trap MUST return the exact value the target
299
+ // holds, or the engine throws a TypeError on read. Degrade to the raw
300
+ // value instead of tripping that invariant (S2a) — a frozen host API
301
+ // loses the capture window for that member, but keeps working.
302
+ const descriptor = Reflect.getOwnPropertyDescriptor(target, prop);
303
+ if (descriptor && descriptor.writable === false && descriptor.configurable === false) {
304
+ return descriptor.value;
305
+ }
306
+ const cached = wrapperCache.get(prop);
307
+ if (cached !== undefined)
308
+ return cached;
309
+ const value = Reflect.get(target, prop, target);
310
+ if (typeof value !== "function")
311
+ return value;
312
+ const method = value;
313
+ // A host that returns `this` for chaining would hand back the raw API,
314
+ // so a chained `on(...).on(...)` would register an unwrapped handler.
315
+ // Keep the proxy on the chain.
316
+ const keepProxy = (result) => result === target ? proxy : result;
317
+ // Pass-through members are cached too (S3a/S3b: `proxy.getFlag ===
318
+ // proxy.getFlag`), but the cached wrapper re-reads `target[prop]` on
319
+ // EVERY call rather than closing over `method` -- a plain
320
+ // `method.bind(target)` pins the function reference captured at first
321
+ // access, so a host (or a test simulating one) that reassigns its own
322
+ // method after registration would silently keep calling the stale one.
323
+ // Re-reading keeps the cached wrapper's identity stable while staying
324
+ // live to whatever `target[prop]` currently is.
325
+ const wrapper = isCaptureSeam(prop)
326
+ ? (...args) => {
327
+ const wrapped = args.map((arg) => wrapFunctionsInPlace(arg));
328
+ return keepProxy(method.apply(target, wrapped));
329
+ }
330
+ : (...args) => {
331
+ const current = Reflect.get(target, prop, target);
332
+ return current.apply(target, args);
333
+ };
334
+ wrapperCache.set(prop, wrapper);
335
+ return wrapper;
336
+ },
337
+ });
338
+ return proxy;
339
+ }
340
+ function formatConsoleArgs(args) {
341
+ return args
342
+ .map((arg) => {
343
+ if (typeof arg === "string")
344
+ return arg;
345
+ if (arg instanceof Error)
346
+ return arg.stack ?? arg.message;
347
+ try {
348
+ return JSON.stringify(arg) ?? String(arg);
349
+ }
350
+ catch {
351
+ return String(arg);
352
+ }
353
+ })
354
+ .join(" ");
355
+ }
356
+ /**
357
+ * Patch every console method on the extension entry path so a transitively
358
+ * loaded dependency cannot write raw bytes into pi's frame — the pi-side
359
+ * mirror of `mcp/server.ts`'s `console.log = console.error` guard, which
360
+ * protects the JSON-RPC stdout channel for the same structural reason.
361
+ *
362
+ * The patch is a DISPATCHER, not a permanent reroute (#1434). It sends a write
363
+ * to the extension log only while pi-lens owns execution; every other write
364
+ * goes to the original console method. pi's own one-shot CLI commands print
365
+ * through `console.log`, so an unconditional reroute silenced them: `pi list`
366
+ * exited 0 with no output in any project whose cwd loaded the extension first.
367
+ *
368
+ * This is a NET, not the fix: pi-lens's own sites are migrated to real sinks
369
+ * with real schemas. Idempotent, and inert under test mode (vitest owns the
370
+ * console) and under `PI_LENS_CONSOLE_GUARD=0`.
371
+ *
372
+ * Returns true when the patch was applied by this call.
373
+ */
374
+ export function installConsoleGuard() {
375
+ if (consoleGuardInstalled)
376
+ return false;
377
+ if (isTestMode())
378
+ return false;
379
+ if (process.env.PI_LENS_CONSOLE_GUARD === "0")
380
+ return false;
381
+ consoleGuardInstalled = true;
382
+ const target = console;
383
+ for (const method of CONSOLE_METHODS) {
384
+ const original = target[method];
385
+ if (typeof original !== "function")
386
+ continue;
387
+ const originalFn = original;
388
+ originalConsoleMethods.set(method, originalFn);
389
+ const replacement = (...args) => {
390
+ if (!isConsoleCaptureActive()) {
391
+ originalFn.apply(console, args);
392
+ return;
393
+ }
394
+ logExtension({
395
+ subsystem: "console",
396
+ level: method === "warn" ? "warn" : method === "error" ? "error" : "debug",
397
+ message: formatConsoleArgs(args),
398
+ metadata: { method },
399
+ });
400
+ };
401
+ installedConsoleMethods.set(method, replacement);
402
+ target[method] = replacement;
403
+ }
404
+ return true;
405
+ }
406
+ /**
407
+ * Restore the exact console methods captured at install time.
408
+ *
409
+ * A method someone else patched after us is left alone — restoring it would
410
+ * clobber their replacement. Returns true when this call uninstalled.
411
+ */
412
+ export function uninstallConsoleGuard() {
413
+ if (!consoleGuardInstalled)
414
+ return false;
415
+ consoleGuardInstalled = false;
416
+ const target = console;
417
+ for (const [method, original] of originalConsoleMethods) {
418
+ if (target[method] === installedConsoleMethods.get(method)) {
419
+ target[method] = original;
420
+ }
421
+ }
422
+ originalConsoleMethods.clear();
423
+ installedConsoleMethods.clear();
424
+ return true;
425
+ }
426
+ /** Test-only: uninstall the guard and close every open capture window. */
427
+ export function _resetConsoleGuardForTests() {
428
+ uninstallConsoleGuard();
429
+ consoleGuardInstalled = false;
430
+ consoleCaptureStorage = undefined;
431
+ moduleLoadWindowOpen = false;
432
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Host run-mode awareness (#1334 S2).
3
+ *
4
+ * pi tells every extension which mode it is running in — verified against the
5
+ * pinned host types (`@earendil-works/pi-coding-agent/dist/core/extensions/
6
+ * types.d.ts`):
7
+ *
8
+ * export type ExtensionMode = "tui" | "rpc" | "json" | "print"; // line 208
9
+ * interface ExtensionContext { mode: ExtensionMode; hasUI: boolean; … }
10
+ * // lines 212-215
11
+ *
12
+ * The host's own comment on `mode` is the contract this module encodes:
13
+ * *"Use `"tui"` to guard terminal-only UI such as custom components."*
14
+ *
15
+ * pi-lens previously derived terminal ownership from nothing at all — it
16
+ * mounted its widget and chattered through `ui.notify` in every mode, including
17
+ * `print` and `json`, where the process is a one-shot producing machine- or
18
+ * pipe-consumed output and there is no live TUI to render into.
19
+ *
20
+ * Two independent questions, deliberately NOT the same predicate:
21
+ *
22
+ * - *Is there a TUI to mount a custom component into?* Only `"tui"`. `rpc`
23
+ * has `hasUI: true` (dialogs work over the protocol) but no terminal
24
+ * component surface, so the widget must not mount there either.
25
+ * - *Should proactive chatter reach the human?* No in `print` and `json` —
26
+ * one-shot/machine output. Yes in `tui` and `rpc`.
27
+ *
28
+ * This is complementary to, and independent of, the #1338/#1333 console guard:
29
+ * that establishes "never write raw to the terminal"; this decides whether the
30
+ * HOST's own render path should be used at all in a given mode.
31
+ *
32
+ * Stateless by design: `mode` lives on the ctx pi hands to every event and
33
+ * command handler, so each call site reads it from the ctx it already has —
34
+ * no latched global to go stale across a session replacement.
35
+ */
36
+ const KNOWN_MODES = new Set(["tui", "rpc", "json", "print"]);
37
+ /**
38
+ * Feature-detected read of `ctx.mode`.
39
+ *
40
+ * Returns `"unknown"` for a host that predates the field, or for any value
41
+ * outside the four documented modes (a future pi may add one; treating an
42
+ * unrecognized mode as "unknown" keeps current behavior rather than guessing
43
+ * a suppression that could hide output).
44
+ */
45
+ export function readExtensionMode(ctx) {
46
+ try {
47
+ const mode = ctx?.mode;
48
+ if (typeof mode !== "string" || !KNOWN_MODES.has(mode))
49
+ return "unknown";
50
+ return mode;
51
+ }
52
+ catch {
53
+ return "unknown";
54
+ }
55
+ }
56
+ /**
57
+ * Whether a terminal-only custom component (the pi-lens diagnostics widget) can
58
+ * be mounted. `"unknown"` mounts — older hosts must behave exactly as before.
59
+ */
60
+ export function supportsTuiWidget(mode) {
61
+ return mode === "tui" || mode === "unknown";
62
+ }
63
+ /**
64
+ * Whether proactive `ui.notify` chatter should be suppressed (logged only).
65
+ * True only for the two non-interactive one-shot modes.
66
+ */
67
+ export function suppressesUserNotify(mode) {
68
+ return mode === "print" || mode === "json";
69
+ }
70
+ /** Short human-readable reason for a suppression, for the ndjson/debug log. */
71
+ export function modeSuppressionNote(mode) {
72
+ return `suppressed in "${mode}" mode (no interactive TUI)`;
73
+ }
@@ -88,6 +88,9 @@ export const KIND_EXTENSIONS = {
88
88
  ".hs",
89
89
  ".lhs",
90
90
  ],
91
+ "helm-template": [
92
+ ".tpl",
93
+ ],
91
94
  html: [
92
95
  ".htm",
93
96
  ".html",
@@ -169,6 +172,7 @@ export const KIND_EXTENSIONS = {
169
172
  ".tf",
170
173
  ".tfvars",
171
174
  ],
175
+ terragrunt: [],
172
176
  toml: [
173
177
  ".toml",
174
178
  ],
@@ -181,6 +185,36 @@ export const KIND_EXTENSIONS = {
181
185
  ".zon",
182
186
  ],
183
187
  };
188
+ /** Return whether a path has an extension registered for the given file kind. */
189
+ export function hasKindExtension(filePath, kind) {
190
+ const extension = extname(filePath).toLowerCase();
191
+ return KIND_EXTENSIONS[kind].some((candidate) => candidate === extension);
192
+ }
193
+ // Fact providers intentionally stay on the ordinary JS/TS source extensions.
194
+ // Vue/Svelte files are classified as jsts for project-wide discovery, but their
195
+ // embedded-language contents are not valid inputs for these tree-sitter facts.
196
+ // Keep that one policy decision here so the function and import providers agree.
197
+ const JSTS_FACT_EXTENSIONS = new Set(KIND_EXTENSIONS.jsts.filter((extension) => ![".vue", ".svelte"].includes(extension)));
198
+ /** Whether the JS/TS fact providers should parse this path. */
199
+ export function isJstsFactFile(filePath) {
200
+ return JSTS_FACT_EXTENSIONS.has(extname(filePath).toLowerCase());
201
+ }
202
+ // Bash access tracking also accepts common text/config files which do not have
203
+ // a semantic FileKind. Every source extension is derived from KIND_EXTENSIONS;
204
+ // only this explicit legacy text/config allowlist lives outside that registry.
205
+ const NON_KIND_READABLE_EXTENSIONS = new Set([
206
+ ".txt",
207
+ ".env",
208
+ ".cfg",
209
+ ".conf",
210
+ ".ini",
211
+ ".xml",
212
+ ]);
213
+ /** Whether bash file-access parsing should treat a path as source-like. */
214
+ export function isReadableSourceFile(filePath) {
215
+ const extension = extname(filePath).toLowerCase();
216
+ return (Object.keys(KIND_EXTENSIONS).some((kind) => hasKindExtension(filePath, kind)) || NON_KIND_READABLE_EXTENSIONS.has(extension));
217
+ }
184
218
  // --- Shared Project Root Markers ---
185
219
  /**
186
220
  * .NET project/solution root-marker globs (refs #895). Single source of truth
@@ -200,6 +234,19 @@ export const DOTNET_FSHARP_ROOT_MARKERS = [
200
234
  "*.fsproj",
201
235
  "*.sln",
202
236
  ];
237
+ /**
238
+ * Terragrunt's unit/root entrypoint filenames, lowercase. Single source of truth
239
+ * for every subsystem that has to agree on what counts as a terragrunt file —
240
+ * SPECIAL_FILENAMES below, tool-policy.ts's linter and formatter policies,
241
+ * formatters.ts's terragruntHclFormatter, and language-profile.ts's project/root
242
+ * markers. Same rule as the .NET markers above: never hand-copy this list at a
243
+ * call site. tests/clients/terragrunt-filenames.test.ts asserts every consumer
244
+ * honors every name here, so a drifting call site fails CI.
245
+ */
246
+ export const TERRAGRUNT_FILENAMES = [
247
+ "terragrunt.hcl",
248
+ "root.hcl",
249
+ ];
203
250
  // Reverse map: extension → file kind (for fast lookup)
204
251
  const EXT_TO_KIND = new Map();
205
252
  for (const [kind, exts] of Object.entries(KIND_EXTENSIONS)) {
@@ -218,6 +265,10 @@ const SPECIAL_FILENAMES = [
218
265
  { pattern: /^CMakeLists\.txt$/i, kind: "cmake" },
219
266
  { pattern: /^Makefile$/i, kind: "shell" },
220
267
  { pattern: /^Dockerfile(\.\w+)?$/i, kind: "docker" },
268
+ ...TERRAGRUNT_FILENAMES.map((name) => ({
269
+ pattern: new RegExp(`^${name.replaceAll(".", "\\.")}$`, "i"),
270
+ kind: "terragrunt",
271
+ })),
221
272
  ];
222
273
  // --- Detection Functions ---
223
274
  /**
@@ -294,6 +345,7 @@ export const CODE_KINDS = new Set([
294
345
  "gleam",
295
346
  "go",
296
347
  "haskell",
348
+ "helm-template",
297
349
  "java",
298
350
  "jsts",
299
351
  "kotlin",
@@ -310,6 +362,7 @@ export const CODE_KINDS = new Set([
310
362
  "sql",
311
363
  "swift",
312
364
  "terraform",
365
+ "terragrunt",
313
366
  "zig",
314
367
  ]);
315
368
  /** Data/doc/markup/config kinds — still enumerated (that's #894's point), but
@@ -376,11 +429,13 @@ export function getFileKindLabel(kind) {
376
429
  lua: "Lua",
377
430
  zig: "Zig",
378
431
  haskell: "Haskell",
432
+ "helm-template": "Helm template",
379
433
  elixir: "Elixir",
380
434
  gleam: "Gleam",
381
435
  ocaml: "OCaml",
382
436
  clojure: "Clojure",
383
437
  terraform: "Terraform",
438
+ terragrunt: "Terragrunt",
384
439
  nix: "Nix",
385
440
  toml: "TOML",
386
441
  };
@@ -444,11 +499,13 @@ export function getLanguageId(kind) {
444
499
  lua: "lua",
445
500
  zig: "zig",
446
501
  haskell: "haskell",
502
+ "helm-template": "helm",
447
503
  elixir: "elixir",
448
504
  gleam: "gleam",
449
505
  ocaml: "ocaml",
450
506
  clojure: "clojure",
451
507
  terraform: "terraform",
508
+ terragrunt: "terragrunt",
452
509
  nix: "nix",
453
510
  toml: "toml",
454
511
  };
@@ -5,8 +5,9 @@
5
5
  * can skip checks that don't apply (e.g. no complexity checks on generated
6
6
  * files, no logic-density checks on re-export barrels).
7
7
  */
8
- import { basename, dirname } from "node:path";
8
+ import { basename, dirname, win32 } from "node:path";
9
9
  import { isGeneratedOrArtifact } from "./generated-artifacts.js";
10
+ import { isWindowsPath } from "./path-utils.js";
10
11
  // --- Detection ---
11
12
  const RE_EXPORT_LINE = /^export\s+(type\s+)?\*\s+from\s+|^export\s*\{[^}]*\}\s+from\s+/;
12
13
  function isReExportBarrel(content) {
@@ -36,10 +37,24 @@ function isTypeStub(content) {
36
37
  /**
37
38
  * Classify the structural role of a file. Pass `content` for higher
38
39
  * accuracy (enables generated-code detection, barrel detection, etc.).
40
+ *
41
+ * `detectFileRole` is platform-native by design — normal same-OS paths
42
+ * (POSIX on Linux, win32 on Windows) go through the module-default
43
+ * `basename`/`dirname`, unchanged from before. But a WINDOWS-SHAPED path
44
+ * (drive letter or UNC prefix, per `isWindowsPath`) is parsed with
45
+ * `path.win32.basename`/`dirname` regardless of the running OS (refs #1152,
46
+ * the #1150 class): on Linux the module-default `dirname` finds no `/` in a
47
+ * `C:\...` path, collapses to `"."`, and the dir-based branches below
48
+ * (`/tests/`, `/spec/`, …) silently misclassify. On win32 this branch is a
49
+ * no-op — `win32.basename`/`dirname` already equal the module default there
50
+ * — so native Windows classification is unchanged.
39
51
  */
40
52
  export function detectFileRole(filePath, content) {
41
- const base = basename(filePath).toLowerCase();
42
- const dir = dirname(filePath).replace(/\\/g, "/").toLowerCase();
53
+ const windowsShaped = isWindowsPath(filePath);
54
+ const base = (windowsShaped ? win32.basename(filePath) : basename(filePath)).toLowerCase();
55
+ const dir = (windowsShaped ? win32.dirname(filePath) : dirname(filePath))
56
+ .replace(/\\/g, "/")
57
+ .toLowerCase();
43
58
  // --- Test ---
44
59
  if (base.includes(".test.") ||
45
60
  base.includes(".spec.") ||