@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
@@ -20,10 +20,12 @@
20
20
  // many things other than "your session is gone"
21
21
  // - treat generic -32000/ConnectionClosed errors as session expiry
22
22
  // - treat AbortError/cancellation as a session failure
23
- import { ProtocolError, SdkHttpError } from "@modelcontextprotocol/client";
23
+ import { ProtocolError, SdkHttpError, UnauthorizedError } from "@modelcontextprotocol/client";
24
24
  import { logger } from "./logger.ts";
25
25
  import { throwIfAborted } from "./abort.ts";
26
26
  import { isServerDisabled, type McpConfig } from "./types.ts";
27
+ import { supportsOAuth } from "./mcp-auth-flow.ts";
28
+ import { invalidateAuthEntryCache } from "./mcp-auth.ts";
27
29
  import type { McpServerManager, ServerConnection } from "./server-manager.ts";
28
30
 
29
31
  /**
@@ -106,6 +108,11 @@ export async function withSessionRecovery<T>(
106
108
  try {
107
109
  return await fn(connection);
108
110
  } catch (err) {
111
+ const definition = deps.config.mcpServers[serverName];
112
+ if (definition && supportsOAuth(definition)
113
+ && (err instanceof UnauthorizedError || (err instanceof SdkHttpError && err.status === 401))) {
114
+ invalidateAuthEntryCache(serverName);
115
+ }
109
116
  if (!isTerminatedSession(err, hadSessionId)) {
110
117
  throw err;
111
118
  }
@@ -114,7 +121,6 @@ export async function withSessionRecovery<T>(
114
121
  // connection's definition, in case config changed since connect. If the
115
122
  // server was removed from config in the meantime there is nothing to
116
123
  // reconnect to, so surface the original error.
117
- const definition = deps.config.mcpServers[serverName];
118
124
  if (!definition) {
119
125
  throw err;
120
126
  }
@@ -24,19 +24,59 @@ export function isToolCallApprovalRequired(
24
24
  config: McpConfig,
25
25
  serverName: string,
26
26
  toolMeta: Pick<ToolMetadata, "originalName">,
27
+ toolMetadata?: ReadonlyMap<string, readonly ToolMetadata[]>,
27
28
  ): boolean {
28
29
  const definition = config.mcpServers[serverName];
29
- const approval = definition?.approveTools !== undefined
30
- ? definition.approveTools
31
- : config.settings?.approveTools;
30
+ const serverApproval = definition?.approveTools;
31
+ const approval = serverApproval !== undefined ? serverApproval : config.settings?.approveTools;
32
32
 
33
33
  if (approval === true) return true;
34
34
  if (!Array.isArray(approval) || approval.length === 0) return false;
35
35
 
36
36
  const prefix = resolveToolPrefix(definition, config.settings?.toolPrefix);
37
- return matchesToolPattern(
38
- getToolNameCandidates(toolMeta.originalName, serverName, prefix),
39
- approval,
37
+ const currentCandidates = getToolNameCandidates(toolMeta.originalName, serverName, prefix, false);
38
+ if (serverApproval !== undefined) {
39
+ if (matchesToolPattern(currentCandidates, approval)) return true;
40
+ if (!toolMetadata) return matchesToolPattern(getToolNameCandidates(toolMeta.originalName, serverName, prefix), approval);
41
+ const legacyCandidates = getToolNameCandidates(toolMeta.originalName, serverName, prefix);
42
+ const legacyEmittedName = [...currentCandidates].find(candidate => candidate !== toolMeta.originalName)?.replace(/-/g, "_");
43
+ if (legacyEmittedName) legacyCandidates.add(legacyEmittedName);
44
+ for (const candidate of currentCandidates) legacyCandidates.delete(candidate);
45
+ const otherCurrentCandidates = new Set<string>();
46
+ for (const tool of toolMetadata.get(serverName) ?? []) {
47
+ for (const candidate of getToolNameCandidates(tool.originalName, serverName, prefix, false)) {
48
+ otherCurrentCandidates.add(candidate);
49
+ }
50
+ }
51
+ for (const candidate of currentCandidates) otherCurrentCandidates.delete(candidate);
52
+ return approval.some(pattern =>
53
+ matchesToolPattern(legacyCandidates, [pattern])
54
+ && !matchesToolPattern(otherCurrentCandidates, [pattern]),
55
+ );
56
+ }
57
+
58
+
59
+ if (matchesToolPattern(currentCandidates, approval)) return true;
60
+ if (!toolMetadata) return false;
61
+
62
+ const legacyCandidates = getToolNameCandidates(toolMeta.originalName, serverName, prefix);
63
+ const legacyEmittedName = [...currentCandidates].find(candidate => candidate !== toolMeta.originalName)?.replace(/-/g, "_");
64
+ if (legacyEmittedName) legacyCandidates.add(legacyEmittedName);
65
+ for (const candidate of currentCandidates) legacyCandidates.delete(candidate);
66
+ const otherCurrentCandidates = new Set<string>();
67
+ for (const [name, metadata] of toolMetadata) {
68
+ const otherPrefix = resolveToolPrefix(config.mcpServers[name], config.settings?.toolPrefix);
69
+ for (const tool of metadata) {
70
+ for (const candidate of getToolNameCandidates(tool.originalName, name, otherPrefix, false)) {
71
+ otherCurrentCandidates.add(candidate);
72
+ }
73
+ }
74
+ }
75
+ for (const candidate of currentCandidates) otherCurrentCandidates.delete(candidate);
76
+
77
+ return approval.some(pattern =>
78
+ matchesToolPattern(legacyCandidates, [pattern])
79
+ && !matchesToolPattern(otherCurrentCandidates, [pattern]),
40
80
  );
41
81
  }
42
82
 
@@ -94,6 +134,7 @@ export async function ensureToolCallApproved(
94
134
  args: Record<string, unknown> | undefined,
95
135
  signal?: AbortSignal,
96
136
  origin: McpToolApprovalOrigin = toolMeta.resourceUri ? "resource" : "proxy",
137
+ approvalMetadata?: ReadonlyMap<string, readonly ToolMetadata[]>,
97
138
  ): Promise<ToolCallApprovalResult> {
98
139
  const cacheKey = `${serverName}\u0000${toolMeta.originalName}`;
99
140
  const approvedToolCalls = state.approvedToolCalls ??= new Map<string, true>();
@@ -109,7 +150,7 @@ export async function ensureToolCallApproved(
109
150
  }
110
151
  if (brokerDecision === "deny") return { ok: false, reason: "denied" };
111
152
 
112
- if (!isToolCallApprovalRequired(state.config, serverName, toolMeta)) {
153
+ if (!isToolCallApprovalRequired(state.config, serverName, toolMeta, approvalMetadata ?? state.toolMetadata)) {
113
154
  return { ok: true };
114
155
  }
115
156
 
@@ -1,7 +1,7 @@
1
1
  import { getToolUiResourceUri } from "./ui-app-bridge-helpers.ts";
2
2
  import type { McpExtensionState } from "./state.ts";
3
3
  import type { ToolMetadata, McpTool, McpResource, ServerEntry, ToolPrefix } from "./types.ts";
4
- import { formatToolName, isToolAllowed, resolveToolPrefix } from "./types.ts";
4
+ import { createToolSelectorCandidateIndex, formatToolName, getToolNameCandidates, isToolAllowed, resolveToolPrefix } from "./types.ts";
5
5
  import { resourceNameToToolName } from "./resource-tools.ts";
6
6
  import { extractToolUiStreamMode } from "./utils.ts";
7
7
  import { extractUiToolVisibility, isUiToolVisibleToModel } from "./ui-tool-visibility.ts";
@@ -11,19 +11,77 @@ export function buildToolMetadata(
11
11
  resources: McpResource[],
12
12
  definition: ServerEntry,
13
13
  serverName: string,
14
- prefix: ToolPrefix
14
+ prefix: ToolPrefix,
15
+ configuredServers?: Record<string, ServerEntry>,
16
+ knownMetadata?: Map<string, ToolMetadata[]>,
17
+ includeMissingConfiguredCandidates = false,
15
18
  ): { metadata: ToolMetadata[]; failedTools: string[] } {
16
19
  const metadata: ToolMetadata[] = [];
17
20
  const failedTools: string[] = [];
18
21
  const seenNames = new Set<string>();
19
22
  const effectivePrefix = resolveToolPrefix(definition, prefix);
23
+ const hasToolFilters =
24
+ (Array.isArray(definition.includeTools) && definition.includeTools.length > 0) ||
25
+ (Array.isArray(definition.excludeTools) && definition.excludeTools.length > 0);
26
+ const selectorCandidateIndex = hasToolFilters && configuredServers ? (() => {
27
+ const candidates = new Set<string>();
28
+ const additionalCandidatesByToolName = new Map<string, Set<string>>();
29
+ const evaluatedToolNames = new Set<string>();
30
+ const addCandidates = (
31
+ target: Set<string>,
32
+ originalName: string,
33
+ candidateServerName: string,
34
+ candidatePrefix: ToolPrefix,
35
+ ) => {
36
+ for (const candidate of getToolNameCandidates(originalName, candidateServerName, candidatePrefix, false)) target.add(candidate);
37
+ };
38
+
39
+ for (const tool of tools) {
40
+ if (!tool?.name) continue;
41
+ evaluatedToolNames.add(tool.name);
42
+ addCandidates(candidates, tool.name, serverName, effectivePrefix);
43
+ }
44
+ if (definition.exposeResources !== false) {
45
+ for (const resource of resources) {
46
+ const baseName = `read_${resourceNameToToolName(resource.name)}`;
47
+ evaluatedToolNames.add(baseName);
48
+ if (resource?.name && resource?.uri) addCandidates(candidates, baseName, serverName, effectivePrefix);
49
+ }
50
+ }
51
+ for (const [otherServerName, otherDefinition] of Object.entries(configuredServers)) {
52
+ if (otherServerName === serverName) continue;
53
+ const otherPrefix = resolveToolPrefix(otherDefinition, prefix);
54
+ const knownTools = knownMetadata?.get(otherServerName);
55
+ if (knownTools) {
56
+ for (const tool of knownTools) {
57
+ candidates.add(tool.name);
58
+ addCandidates(candidates, tool.originalName, otherServerName, otherPrefix);
59
+ }
60
+ } else if (!knownMetadata || includeMissingConfiguredCandidates) {
61
+ for (const toolName of evaluatedToolNames) {
62
+ let additionalCandidates = additionalCandidatesByToolName.get(toolName);
63
+ if (!additionalCandidates) {
64
+ additionalCandidates = new Set<string>();
65
+ additionalCandidatesByToolName.set(toolName, additionalCandidates);
66
+ }
67
+ addCandidates(additionalCandidates, toolName, otherServerName, otherPrefix);
68
+ if (includeMissingConfiguredCandidates) {
69
+ for (const candidate of getToolNameCandidates(toolName, otherServerName, otherPrefix, false)) {
70
+ additionalCandidates.add(candidate.replace(/-/g, "_"));
71
+ }
72
+ }
73
+ }
74
+ }
75
+ }
76
+ return createToolSelectorCandidateIndex(candidates, additionalCandidatesByToolName);
77
+ })() : undefined;
20
78
 
21
79
  for (const tool of tools) {
22
80
  if (!tool?.name) {
23
81
  failedTools.push("(unnamed)");
24
82
  continue;
25
83
  }
26
- if (!isToolAllowed(tool.name, serverName, effectivePrefix, definition.includeTools, definition.excludeTools)) {
84
+ if (!isToolAllowed(tool.name, serverName, effectivePrefix, definition.includeTools, definition.excludeTools, selectorCandidateIndex)) {
27
85
  continue;
28
86
  }
29
87
 
@@ -59,7 +117,7 @@ export function buildToolMetadata(
59
117
  if (definition.exposeResources !== false) {
60
118
  for (const resource of resources) {
61
119
  const baseName = `read_${resourceNameToToolName(resource.name)}`;
62
- if (!isToolAllowed(baseName, serverName, effectivePrefix, definition.includeTools, definition.excludeTools)) {
120
+ if (!isToolAllowed(baseName, serverName, effectivePrefix, definition.includeTools, definition.excludeTools, selectorCandidateIndex)) {
63
121
  continue;
64
122
  }
65
123
 
@@ -1,5 +1,5 @@
1
1
  import type { AgentToolResult, ToolRenderResultOptions } from "@earendil-works/pi-coding-agent";
2
- import { type Component, Text } from "@earendil-works/pi-tui";
2
+ import { type Component, Text, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
3
3
 
4
4
  type McpToolResultDetails = Record<string, unknown> & { error?: unknown };
5
5
  type McpToolContentBlock = AgentToolResult<McpToolResultDetails>["content"][number];
@@ -23,8 +23,27 @@ export interface McpProxyToolCallInput {
23
23
  action?: string;
24
24
  }
25
25
 
26
+ interface McpToolRenderState {
27
+ compactTitle?: string;
28
+ }
29
+
26
30
  interface McpToolRenderContext {
27
31
  isError: boolean;
32
+ isPartial?: boolean;
33
+ expanded?: boolean;
34
+ state?: McpToolRenderState;
35
+ }
36
+
37
+ export type McpToolResultRendering = "compact" | "boxed";
38
+
39
+ export interface McpToolRenderOptions {
40
+ resultRendering: McpToolResultRendering;
41
+ collapsedResultLines: 1 | 2 | 3;
42
+ }
43
+
44
+ export interface McpToolRenderSettings {
45
+ toolResultRendering?: unknown;
46
+ collapsedResultLines?: unknown;
28
47
  }
29
48
 
30
49
  export interface McpToolResultDisplay {
@@ -33,10 +52,62 @@ export interface McpToolResultDisplay {
33
52
  }
34
53
 
35
54
  const DEFAULT_MAX_CALL_INPUT_CHARS = 1500;
36
- const DEFAULT_MAX_COLLAPSED_LINES = 3;
55
+ const DEFAULT_BOXED_COLLAPSED_LINES = 3;
56
+ const DEFAULT_COMPACT_COLLAPSED_LINES = 1;
37
57
  const DEFAULT_MAX_COLLAPSED_CHARS = 8000;
38
58
  const COLLAPSED_RENDER_CHAR_SLACK = 8;
39
59
 
60
+ class EmptyComponent implements Component {
61
+ render(): string[] {
62
+ return [];
63
+ }
64
+
65
+ invalidate(): void {}
66
+ }
67
+
68
+ class CompactMcpToolResult implements Component {
69
+ private rendered: { width: number; lines: string[] } | null = null;
70
+
71
+ constructor(
72
+ private readonly title: string,
73
+ private readonly display: McpToolResultDisplay,
74
+ private readonly theme: RenderTheme,
75
+ ) {}
76
+
77
+ render(width: number): string[] {
78
+ const safeWidth = Math.max(1, Math.floor(width));
79
+ if (this.rendered?.width === safeWidth) return this.rendered.lines;
80
+
81
+ const resultLines = this.display.lines.filter((line, index, lines) => {
82
+ return !(this.display.truncated && index === lines.length - 1 && line === "…");
83
+ });
84
+ const lines = resultLines.length > 0 ? resultLines : [""];
85
+ const bodies = lines.map((line, index) => {
86
+ const prefix = index === 0 && this.title ? `${this.theme.fg("toolTitle", this.title)} → ` : "";
87
+ return `${prefix}${this.theme.fg("toolOutput", line)}`;
88
+ });
89
+ const hiddenText = this.display.truncated || bodies.some((body) => visibleWidth(body) > safeWidth);
90
+ const rendered = bodies.map((body, index) => {
91
+ const suffix = hiddenText && index === bodies.length - 1 ? " … (Ctrl+O to expand)" : "";
92
+ if (!suffix) return truncateToWidth(body, safeWidth, "…");
93
+ if (safeWidth >= suffix.length + 20) {
94
+ return `${truncateToWidth(body, safeWidth - suffix.length, "…")}${this.theme.fg("muted", suffix)}`;
95
+ }
96
+ const shortSuffix = " (Ctrl+O)";
97
+ if (safeWidth >= shortSuffix.length + 5) {
98
+ return `${truncateToWidth(body, safeWidth - shortSuffix.length, "…")}${this.theme.fg("muted", shortSuffix)}`;
99
+ }
100
+ return truncateToWidth(this.theme.fg("muted", shortSuffix.trim()), safeWidth, "…");
101
+ });
102
+ this.rendered = { width: safeWidth, lines: rendered };
103
+ return rendered;
104
+ }
105
+
106
+ invalidate(): void {
107
+ this.rendered = null;
108
+ }
109
+ }
110
+
40
111
  class CollapsibleText implements Component {
41
112
  private readonly fullText: Text;
42
113
  private readonly footerText: Text;
@@ -47,8 +118,8 @@ class CollapsibleText implements Component {
47
118
  private readonly text: string,
48
119
  private readonly expanded: boolean,
49
120
  private readonly maxCollapsedLines: number,
50
- private readonly ellipsis: string,
51
- private readonly expandHint: string,
121
+ ellipsis: string,
122
+ expandHint: string,
52
123
  private readonly preTruncated = false,
53
124
  ) {
54
125
  this.fullText = new Text(text, 0, 0);
@@ -168,13 +239,52 @@ function renderToolCallLines(lines: string[], theme?: RenderTheme) {
168
239
  return new Text([styledTitle, ...styledRest].join("\n"), 0, 0);
169
240
  }
170
241
 
171
- export function renderMcpProxyToolCall(args: McpProxyToolCallInput, theme?: RenderTheme) {
172
- return renderToolCallLines(formatMcpProxyToolCallLines(args), theme);
242
+ export function resolveMcpToolRenderOptions(settings?: McpToolRenderSettings): McpToolRenderOptions {
243
+ const resultRendering = settings?.toolResultRendering === "boxed" ? "boxed" : "compact";
244
+ const collapsedLines = settings?.collapsedResultLines;
245
+ const defaultLines = resultRendering === "boxed" ? DEFAULT_BOXED_COLLAPSED_LINES : DEFAULT_COMPACT_COLLAPSED_LINES;
246
+ return {
247
+ resultRendering,
248
+ collapsedResultLines: collapsedLines === 1 || collapsedLines === 2 || collapsedLines === 3 ? collapsedLines : defaultLines,
249
+ };
250
+ }
251
+
252
+ function shouldUseCompactFinalRender(options: McpToolRenderOptions, context?: McpToolRenderContext): boolean {
253
+ return options.resultRendering === "compact"
254
+ && context !== undefined
255
+ && context.isPartial === false
256
+ && context.expanded !== true
257
+ && context.isError !== true;
173
258
  }
174
259
 
175
- export function createMcpDirectToolCallRenderer(displayName: string) {
176
- return (args: Record<string, unknown>, theme?: RenderTheme) => {
177
- return renderToolCallLines(formatMcpDirectToolCallLines(displayName, args), theme);
260
+ function renderToolCall(
261
+ lines: string[],
262
+ theme: RenderTheme | undefined,
263
+ context: McpToolRenderContext | undefined,
264
+ options: McpToolRenderOptions,
265
+ ) {
266
+ if (context?.state) context.state.compactTitle = lines[0] ?? "mcp";
267
+ if (shouldUseCompactFinalRender(options, context)) return new EmptyComponent();
268
+ return renderToolCallLines(lines, theme);
269
+ }
270
+
271
+ export function renderMcpProxyToolCall(
272
+ args: McpProxyToolCallInput,
273
+ theme?: RenderTheme,
274
+ context?: McpToolRenderContext,
275
+ ) {
276
+ return renderToolCall(formatMcpProxyToolCallLines(args), theme, context, resolveMcpToolRenderOptions());
277
+ }
278
+
279
+ export function createMcpProxyToolCallRenderer(options: McpToolRenderOptions) {
280
+ return (args: McpProxyToolCallInput, theme?: RenderTheme, context?: McpToolRenderContext) => {
281
+ return renderToolCall(formatMcpProxyToolCallLines(args), theme, context, options);
282
+ };
283
+ }
284
+
285
+ export function createMcpDirectToolCallRenderer(displayName: string, options = resolveMcpToolRenderOptions()) {
286
+ return (args: Record<string, unknown>, theme?: RenderTheme, context?: McpToolRenderContext) => {
287
+ return renderToolCall(formatMcpDirectToolCallLines(displayName, args), theme, context, options);
178
288
  };
179
289
  }
180
290
 
@@ -254,7 +364,7 @@ export function formatMcpToolResultIdentity(details: McpToolResultDetails | unde
254
364
  export function formatMcpToolResultLines(
255
365
  result: Pick<AgentToolResult<McpToolResultDetails>, "content">,
256
366
  expanded: boolean,
257
- maxCollapsedLines = 3,
367
+ maxCollapsedLines = DEFAULT_BOXED_COLLAPSED_LINES,
258
368
  maxCollapsedChars = DEFAULT_MAX_COLLAPSED_CHARS,
259
369
  ): McpToolResultDisplay {
260
370
  if (!expanded) {
@@ -271,6 +381,7 @@ export function renderMcpToolResult(
271
381
  options: ToolRenderResultOptions,
272
382
  theme?: RenderTheme,
273
383
  context?: McpToolRenderContext,
384
+ renderOptions = resolveMcpToolRenderOptions(),
274
385
  ) {
275
386
  const activeTheme = theme ?? plainTheme;
276
387
  if (options.isPartial) {
@@ -279,7 +390,13 @@ export function renderMcpToolResult(
279
390
 
280
391
  const hasErrorDetails = Boolean(result.details.error);
281
392
  const expanded = options.expanded || context?.isError === true || hasErrorDetails;
282
- const display = formatMcpToolResultLines(result, expanded);
393
+ if (!expanded && renderOptions.resultRendering === "compact") {
394
+ const display = formatMcpToolResultLines(result, false, renderOptions.collapsedResultLines);
395
+ const title = context?.state?.compactTitle ?? formatMcpToolResultIdentity(result.details) ?? "";
396
+ return new CompactMcpToolResult(title, display, activeTheme);
397
+ }
398
+
399
+ const display = formatMcpToolResultLines(result, expanded, renderOptions.collapsedResultLines);
283
400
  const identity = formatMcpToolResultIdentity(result.details);
284
401
  const output = [
285
402
  ...(identity ? [activeTheme.fg("muted", identity)] : []),
@@ -289,9 +406,18 @@ export function renderMcpToolResult(
289
406
  return new CollapsibleText(
290
407
  output,
291
408
  expanded,
292
- DEFAULT_MAX_COLLAPSED_LINES + (identity ? 1 : 0),
409
+ renderOptions.collapsedResultLines + (identity ? 1 : 0),
293
410
  activeTheme.fg("muted", "…"),
294
411
  activeTheme.fg("muted", "(Ctrl+O to expand)"),
295
412
  display.truncated,
296
413
  );
297
414
  }
415
+
416
+ export function createMcpToolResultRenderer(renderOptions: McpToolRenderOptions) {
417
+ return (
418
+ result: AgentToolResult<McpToolResultDetails>,
419
+ options: ToolRenderResultOptions,
420
+ theme?: RenderTheme,
421
+ context?: McpToolRenderContext,
422
+ ) => renderMcpToolResult(result, options, theme, context, renderOptions);
423
+ }