@herbertgao/pi-extensions 2026.8.4 → 2026.8.5

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 (288) hide show
  1. package/README.md +4 -4
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +10 -2
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +10 -2
  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/index.ts +7 -6
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +5 -8
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
  13. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  14. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +8 -0
  15. package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
  16. package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
  17. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
  18. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
  19. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +15 -2
  20. package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
  21. package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
  22. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
  23. package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
  24. package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
  25. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
  26. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  27. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
  28. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
  29. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
  30. package/node_modules/@narumitw/pi-btw/README.md +8 -7
  31. package/node_modules/@narumitw/pi-btw/package.json +2 -2
  32. package/node_modules/@narumitw/pi-btw/src/menu.ts +1 -0
  33. package/node_modules/pi-lens/CHANGELOG.md +2440 -954
  34. package/node_modules/pi-lens/README.md +13 -0
  35. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
  36. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
  37. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
  38. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
  39. package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
  40. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
  41. package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
  42. package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
  43. package/node_modules/pi-lens/dist/clients/biome-client.js +29 -25
  44. package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
  45. package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
  46. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
  47. package/node_modules/pi-lens/dist/clients/bus-publish.js +10 -3
  48. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
  49. package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
  50. package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
  51. package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
  52. package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
  53. package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
  54. package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
  55. package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
  56. package/node_modules/pi-lens/dist/clients/console-guard-install.js +14 -0
  57. package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
  58. package/node_modules/pi-lens/dist/clients/dead-code-client.js +2 -1
  59. package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
  60. package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
  61. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
  62. package/node_modules/pi-lens/dist/clients/dependency-checker.js +347 -75
  63. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +61 -11
  64. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +10 -3
  65. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +63 -20
  66. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
  67. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
  68. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
  69. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
  70. package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
  71. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1085 -681
  72. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
  73. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
  74. package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
  75. package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
  76. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
  77. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
  78. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
  79. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
  80. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +154 -0
  81. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
  82. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
  83. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +14 -6
  84. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
  85. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
  86. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
  87. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
  88. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
  89. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
  90. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
  91. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +163 -0
  92. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
  93. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +277 -26
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
  99. package/node_modules/pi-lens/dist/clients/disposition-publish.js +10 -3
  100. package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
  101. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
  102. package/node_modules/pi-lens/dist/clients/extension-log.js +139 -0
  103. package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
  104. package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
  105. package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
  106. package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
  107. package/node_modules/pi-lens/dist/clients/format-events-publish.js +16 -3
  108. package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
  109. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
  110. package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
  111. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
  112. package/node_modules/pi-lens/dist/clients/git-guard.js +681 -11
  113. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
  114. package/node_modules/pi-lens/dist/clients/go-client.js +2 -1
  115. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +8 -0
  116. package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
  117. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
  118. package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
  119. package/node_modules/pi-lens/dist/clients/installer/index.js +390 -99
  120. package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
  121. package/node_modules/pi-lens/dist/clients/jscpd-client.js +31 -54
  122. package/node_modules/pi-lens/dist/clients/knip-client.js +15 -36
  123. package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
  124. package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
  125. package/node_modules/pi-lens/dist/clients/latency-logger.js +23 -1
  126. package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
  127. package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
  128. package/node_modules/pi-lens/dist/clients/lens-events.js +27 -4
  129. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
  130. package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
  131. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +30 -0
  132. package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
  133. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +1 -1
  134. package/node_modules/pi-lens/dist/clients/lsp/client.js +493 -48
  135. package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
  136. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +86 -0
  137. package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
  138. package/node_modules/pi-lens/dist/clients/lsp/index.js +1807 -780
  139. package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
  140. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
  141. package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
  142. package/node_modules/pi-lens/dist/clients/lsp/server.js +196 -32
  143. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
  144. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
  145. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
  146. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +123 -32
  147. package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
  148. package/node_modules/pi-lens/dist/clients/mcp/session.js +216 -8
  149. package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
  150. package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
  151. package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
  152. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
  153. package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
  154. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
  155. package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
  156. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
  157. package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
  158. package/node_modules/pi-lens/dist/clients/pipeline.js +47 -13
  159. package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
  160. package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
  161. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
  162. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
  163. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
  164. package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
  165. package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
  166. package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
  167. package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
  168. package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
  169. package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
  170. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
  171. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
  172. package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
  173. package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
  174. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
  175. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
  176. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
  177. package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
  178. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
  179. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
  180. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
  181. package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
  182. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +107 -73
  183. package/node_modules/pi-lens/dist/clients/runtime-context.js +36 -12
  184. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +74 -6
  185. package/node_modules/pi-lens/dist/clients/runtime-session.js +405 -117
  186. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
  187. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +218 -23
  188. package/node_modules/pi-lens/dist/clients/runtime-turn.js +237 -64
  189. package/node_modules/pi-lens/dist/clients/rust-client.js +2 -1
  190. package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
  191. package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -1
  192. package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
  193. package/node_modules/pi-lens/dist/clients/sg-runner.js +284 -174
  194. package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
  195. package/node_modules/pi-lens/dist/clients/smells-rollup.js +224 -0
  196. package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
  197. package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
  198. package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
  199. package/node_modules/pi-lens/dist/clients/startup-timing.js +1 -1
  200. package/node_modules/pi-lens/dist/clients/test-runner-client.js +38 -8
  201. package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
  202. package/node_modules/pi-lens/dist/clients/tool-policy.js +388 -39
  203. package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
  204. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
  205. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
  206. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
  207. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
  208. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
  209. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
  210. package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
  211. package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
  212. package/node_modules/pi-lens/dist/clients/warm-attach.js +33 -13
  213. package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
  214. package/node_modules/pi-lens/dist/clients/word-index.js +391 -64
  215. package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
  216. package/node_modules/pi-lens/dist/index.js +49361 -36888
  217. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
  218. package/node_modules/pi-lens/dist/mcp/server.js +211 -44
  219. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
  220. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +200 -36
  221. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +153 -40
  222. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
  223. package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
  224. package/node_modules/pi-lens/docs/agent-guide.md +2 -2
  225. package/node_modules/pi-lens/docs/agent-tools.md +21 -10
  226. package/node_modules/pi-lens/docs/analysisall.md +192 -0
  227. package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
  228. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +5 -2
  229. package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
  230. package/node_modules/pi-lens/docs/environment-variables.md +44 -0
  231. package/node_modules/pi-lens/docs/fable.md +27 -0
  232. package/node_modules/pi-lens/docs/features.md +31 -2
  233. package/node_modules/pi-lens/docs/globalconfig.md +45 -1
  234. package/node_modules/pi-lens/docs/language-coverage.md +4 -3
  235. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
  236. package/node_modules/pi-lens/docs/mcp.md +37 -4
  237. package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
  238. package/node_modules/pi-lens/docs/settings.md +12 -1
  239. package/node_modules/pi-lens/docs/tools.md +4 -1
  240. package/node_modules/pi-lens/docs/usage.md +18 -0
  241. package/node_modules/pi-lens/package.json +10 -10
  242. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
  243. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
  244. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
  245. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
  246. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
  247. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
  248. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
  249. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
  250. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
  251. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
  252. package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
  253. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
  254. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +55 -2
  255. package/node_modules/pi-mcp-adapter/CHANGELOG.md +25 -0
  256. package/node_modules/pi-mcp-adapter/README.md +34 -3
  257. package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
  258. package/node_modules/pi-mcp-adapter/commands.ts +15 -7
  259. package/node_modules/pi-mcp-adapter/direct-tools.ts +54 -7
  260. package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
  261. package/node_modules/pi-mcp-adapter/index.ts +8 -3
  262. package/node_modules/pi-mcp-adapter/init.ts +29 -5
  263. package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
  264. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
  265. package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
  266. package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
  267. package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
  268. package/node_modules/pi-mcp-adapter/metadata-cache.ts +27 -4
  269. package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
  270. package/node_modules/pi-mcp-adapter/package.json +3 -3
  271. package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
  272. package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
  273. package/node_modules/pi-mcp-adapter/server-manager.ts +36 -7
  274. package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
  275. package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
  276. package/node_modules/pi-mcp-adapter/tool-metadata.ts +42 -4
  277. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
  278. package/node_modules/pi-mcp-adapter/types.ts +93 -27
  279. package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
  280. package/package.json +11 -12
  281. package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
  282. package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
  283. package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
  284. package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
  285. package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
  286. package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
  287. package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
  288. package/node_modules/pi-lens/dist/clients/types.js +0 -11
@@ -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 { 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,57 @@ 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 getOtherCurrentCandidates = (toolName: string): Set<string> | undefined => {
24
+ if (!configuredServers) return undefined;
25
+ const candidates = new Set<string>();
26
+ const addCandidates = (originalName: string, candidateServerName: string, candidatePrefix: ToolPrefix) => {
27
+ for (const candidate of getToolNameCandidates(originalName, candidateServerName, candidatePrefix, false)) candidates.add(candidate);
28
+ };
29
+
30
+ for (const tool of tools) {
31
+ if (tool?.name) addCandidates(tool.name, serverName, effectivePrefix);
32
+ }
33
+ if (definition.exposeResources !== false) {
34
+ for (const resource of resources) {
35
+ if (resource?.name && resource?.uri) addCandidates(`read_${resourceNameToToolName(resource.name)}`, serverName, effectivePrefix);
36
+ }
37
+ }
38
+ for (const [otherServerName, otherDefinition] of Object.entries(configuredServers)) {
39
+ if (otherServerName === serverName) continue;
40
+ const knownTools = knownMetadata?.get(otherServerName);
41
+ if (knownTools) {
42
+ const otherPrefix = resolveToolPrefix(otherDefinition, prefix);
43
+ for (const tool of knownTools) {
44
+ candidates.add(tool.name);
45
+ addCandidates(tool.originalName, otherServerName, otherPrefix);
46
+ }
47
+ } else if (!knownMetadata || includeMissingConfiguredCandidates) {
48
+ const otherPrefix = resolveToolPrefix(otherDefinition, prefix);
49
+ addCandidates(toolName, otherServerName, otherPrefix);
50
+ if (includeMissingConfiguredCandidates) {
51
+ for (const candidate of getToolNameCandidates(toolName, otherServerName, otherPrefix, false)) candidates.add(candidate.replace(/-/g, "_"));
52
+ }
53
+ }
54
+ }
55
+ for (const candidate of getToolNameCandidates(toolName, serverName, effectivePrefix, false)) candidates.delete(candidate);
56
+ return candidates;
57
+ };
20
58
 
21
59
  for (const tool of tools) {
22
60
  if (!tool?.name) {
23
61
  failedTools.push("(unnamed)");
24
62
  continue;
25
63
  }
26
- if (!isToolAllowed(tool.name, serverName, effectivePrefix, definition.includeTools, definition.excludeTools)) {
64
+ if (!isToolAllowed(tool.name, serverName, effectivePrefix, definition.includeTools, definition.excludeTools, getOtherCurrentCandidates(tool.name))) {
27
65
  continue;
28
66
  }
29
67
 
@@ -59,7 +97,7 @@ export function buildToolMetadata(
59
97
  if (definition.exposeResources !== false) {
60
98
  for (const resource of resources) {
61
99
  const baseName = `read_${resourceNameToToolName(resource.name)}`;
62
- if (!isToolAllowed(baseName, serverName, effectivePrefix, definition.includeTools, definition.excludeTools)) {
100
+ if (!isToolAllowed(baseName, serverName, effectivePrefix, definition.includeTools, definition.excludeTools, getOtherCurrentCandidates(baseName))) {
63
101
  continue;
64
102
  }
65
103
 
@@ -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
+ }
@@ -395,6 +395,13 @@ export interface ServerEntry {
395
395
  // Include/exclude specific MCP tools/resources by original or prefixed name
396
396
  includeTools?: string[];
397
397
  excludeTools?: string[];
398
+ /**
399
+ * Extra search keywords per tool, keyed by original name, prefixed name, or
400
+ * glob (same matching rules as includeTools/excludeTools). Keywords boost
401
+ * mcp({ search }) ranking only — they never appear in tool schemas,
402
+ * describe output, or the metadata cache.
403
+ */
404
+ searchKeywords?: Record<string, string[]>;
398
405
  // Require interactive approval before calling matching MCP tools/resources.
399
406
  approveTools?: boolean | string[];
400
407
  // Debug
@@ -473,6 +480,8 @@ export interface McpSettings {
473
480
  showStatusIcon?: boolean;
474
481
  /** Footer status verbosity: full details, compact connected/enabled count, or no footer status. Defaults to full. */
475
482
  mcpFooterStatus?: McpFooterStatus;
483
+ /** Show successful startup connection notifications. Defaults to true. */
484
+ notifyOnStartupConnect?: boolean;
476
485
  /** Discover detected host-specific MCP configs only when explicitly enabled. */
477
486
  hostConfigDiscovery?: HostConfigDiscovery;
478
487
  /** Agent Plugin package directories to load MCP servers from. */
@@ -482,6 +491,10 @@ export interface McpSettings {
482
491
  directTools?: boolean;
483
492
  /** Register the trusted MCP-only JavaScript scripting tool. Defaults to true; set false to hide it. */
484
493
  scriptMode?: boolean;
494
+ /** Render MCP tool results as compact self-rendered rows by default, or as the legacy boxed row. */
495
+ toolResultRendering?: "compact" | "boxed";
496
+ /** Number of result text lines to show before expansion. Supports 1, 2, or 3. Defaults to 1 in compact mode and 3 in boxed mode. */
497
+ collapsedResultLines?: 1 | 2 | 3;
485
498
  /** Default approval gate for matching tools/resources; per-server settings override it. */
486
499
  approveTools?: boolean | string[];
487
500
  disableProxyTool?: boolean;
@@ -635,18 +648,25 @@ export interface McpPanelResult {
635
648
  /**
636
649
  * Get server prefix based on tool prefix mode.
637
650
  */
651
+ function sanitizeServerPrefix(serverName: string, preserveProviderValid = true): string {
652
+ const validCharacters = preserveProviderValid ? /^[A-Za-z0-9_-]$/ : /^[A-Za-z0-9]$/;
653
+ return Array.from(serverName, char =>
654
+ validCharacters.test(char) ? char : `_${char.codePointAt(0)!.toString(16)}_`,
655
+ ).join("");
656
+ }
657
+
638
658
  export function getServerPrefix(
639
659
  serverName: string,
640
660
  mode: ToolPrefix
641
661
  ): string {
642
662
  if (mode === "none") return "";
643
663
  if (mode === "short") {
644
- let short = serverName.replace(/-?mcp$/i, "").replace(/-/g, "_");
664
+ let short = sanitizeServerPrefix(serverName.replace(/-?mcp$/i, ""));
645
665
  if (!short) short = "mcp";
646
666
  return short;
647
667
  }
648
- if (mode === "mcp") return `mcp__${serverName.replace(/-/g, "_")}`;
649
- return serverName.replace(/-/g, "_");
668
+ if (mode === "mcp") return `mcp__${sanitizeServerPrefix(serverName)}`;
669
+ return sanitizeServerPrefix(serverName);
650
670
  }
651
671
 
652
672
  /**
@@ -700,11 +720,9 @@ export function resolveServerFromToolName(
700
720
  if (candidates.length === 0) return undefined;
701
721
  candidates.sort((a, b) => b.prefix.length - a.prefix.length);
702
722
  const best = candidates[0];
703
- // Fail safe: two distinct server names can normalize to the same prefix
704
- // (e.g. my-server and my_server both -> my_server under "server" mode).
705
- // When that happens the owning server is ambiguous; return undefined so a
706
- // downstream permission gate falls back to its existing wildcard path rather
707
- // than enforcing a rule against the wrong server.
723
+ // Fail safe: short mode can intentionally map names such as foo and foo-mcp
724
+ // to the same prefix. Return undefined so a downstream permission gate uses
725
+ // its existing wildcard path rather than enforcing a rule against the wrong server.
708
726
  if (candidates.some((c) => c.prefix === best!.prefix && c.name !== best!.name)) {
709
727
  return undefined;
710
728
  }
@@ -722,22 +740,48 @@ export function formatPromptCommandName(
722
740
  serverName: string,
723
741
  prefix: ToolPrefix,
724
742
  ): string {
725
- const serverPart = getServerPrefix(serverName, prefix) || serverName.replace(/-/g, "_") || "server";
743
+ const serverPart = getServerPrefix(serverName, prefix) || sanitizeServerPrefix(serverName) || "server";
726
744
  return `mcp__${serverPart}__${sanitizePromptName(promptName)}`;
727
745
  }
728
746
 
729
- function normalizeToolName(value: string): string {
730
- return value.replace(/-/g, "_");
747
+ function getLegacyServerPrefix(serverName: string, mode: ToolPrefix): string {
748
+ if (mode === "none") return "";
749
+ if (mode === "short") return sanitizeServerPrefix(serverName.replace(/-?mcp$/i, ""), false) || "mcp";
750
+ if (mode === "mcp") return `mcp__${sanitizeServerPrefix(serverName, false)}`;
751
+ return sanitizeServerPrefix(serverName, false);
731
752
  }
732
753
 
733
- export function getToolNameCandidates(toolName: string, serverName: string, prefix: ToolPrefix): Set<string> {
734
- return new Set<string>([
735
- normalizeToolName(toolName),
736
- normalizeToolName(formatToolName(toolName, serverName, prefix)),
737
- normalizeToolName(formatToolName(toolName, serverName, "server")),
738
- normalizeToolName(formatToolName(toolName, serverName, "short")),
739
- normalizeToolName(formatToolName(toolName, serverName, "mcp")),
754
+ function formatLegacyToolName(toolName: string, serverName: string, prefix: ToolPrefix): string {
755
+ const serverPrefix = getLegacyServerPrefix(serverName, prefix);
756
+ const sanitizedToolName = toolName.replace(/[.-]/g, "_");
757
+ return serverPrefix ? `${serverPrefix}_${sanitizedToolName}` : sanitizedToolName;
758
+ }
759
+
760
+ export function getToolNameCandidates(toolName: string, serverName: string, prefix: ToolPrefix, includeLegacy = true): Set<string> {
761
+ const candidates = new Set<string>([
762
+ toolName,
763
+ formatToolName(toolName, serverName, prefix),
764
+ formatToolName(toolName, serverName, "server"),
765
+ formatToolName(toolName, serverName, "short"),
766
+ formatToolName(toolName, serverName, "mcp"),
740
767
  ]);
768
+ if (includeLegacy) {
769
+ const legacyToolName = toolName.replace(/-/g, "_");
770
+ candidates.add(legacyToolName);
771
+ candidates.add(formatToolName(legacyToolName, serverName, prefix));
772
+ candidates.add(formatToolName(legacyToolName, serverName, "server"));
773
+ candidates.add(formatToolName(legacyToolName, serverName, "short"));
774
+ candidates.add(formatToolName(legacyToolName, serverName, "mcp"));
775
+ candidates.add(formatLegacyToolName(toolName, serverName, prefix));
776
+ candidates.add(formatLegacyToolName(toolName, serverName, "server"));
777
+ candidates.add(formatLegacyToolName(toolName, serverName, "short"));
778
+ candidates.add(formatLegacyToolName(toolName, serverName, "mcp"));
779
+ candidates.add(formatToolName(toolName, serverName, prefix).replace(/-/g, "_"));
780
+ candidates.add(formatToolName(toolName, serverName, "server").replace(/-/g, "_"));
781
+ candidates.add(formatToolName(toolName, serverName, "short").replace(/-/g, "_"));
782
+ candidates.add(formatToolName(toolName, serverName, "mcp").replace(/-/g, "_"));
783
+ }
784
+ return candidates;
741
785
  }
742
786
 
743
787
  function globToRegExp(pattern: string): RegExp {
@@ -750,11 +794,10 @@ export function matchesToolPattern(candidates: Set<string>, patterns?: unknown):
750
794
 
751
795
  for (const pattern of patterns) {
752
796
  if (typeof pattern !== "string") continue;
753
- const normalized = normalizeToolName(pattern);
754
- if (!normalized.includes("*") && !normalized.includes("?") && candidates.has(normalized)) {
797
+ if (!pattern.includes("*") && !pattern.includes("?") && candidates.has(pattern)) {
755
798
  return true;
756
799
  }
757
- if ((normalized.includes("*") || normalized.includes("?")) && [...candidates].some(candidate => globToRegExp(normalized).test(candidate))) {
800
+ if ((pattern.includes("*") || pattern.includes("?")) && [...candidates].some(candidate => globToRegExp(pattern).test(candidate))) {
758
801
  return true;
759
802
  }
760
803
  }
@@ -762,23 +805,45 @@ export function matchesToolPattern(candidates: Set<string>, patterns?: unknown):
762
805
  return false;
763
806
  }
764
807
 
808
+ function matchesToolSelector(
809
+ toolName: string,
810
+ serverName: string,
811
+ prefix: ToolPrefix,
812
+ patterns: unknown,
813
+ otherCurrentCandidates?: Set<string>,
814
+ ): boolean {
815
+ const currentCandidates = getToolNameCandidates(toolName, serverName, prefix, false);
816
+ if (matchesToolPattern(currentCandidates, patterns)) return true;
817
+ if (!otherCurrentCandidates) return matchesToolPattern(getToolNameCandidates(toolName, serverName, prefix), patterns);
818
+ const legacyCandidates = getToolNameCandidates(toolName, serverName, prefix);
819
+ for (const candidate of currentCandidates) legacyCandidates.delete(candidate);
820
+ if (!Array.isArray(patterns)) return false;
821
+ return patterns.some(pattern =>
822
+ typeof pattern === "string"
823
+ && !matchesToolPattern(otherCurrentCandidates, [pattern])
824
+ && matchesToolPattern(legacyCandidates, [pattern]),
825
+ );
826
+ }
827
+
765
828
  export function isToolIncluded(
766
829
  toolName: string,
767
830
  serverName: string,
768
831
  prefix: ToolPrefix,
769
- includeTools?: unknown
832
+ includeTools?: unknown,
833
+ otherCurrentCandidates?: Set<string>,
770
834
  ): boolean {
771
835
  if (!Array.isArray(includeTools) || includeTools.length === 0) return true;
772
- return matchesToolPattern(getToolNameCandidates(toolName, serverName, prefix), includeTools);
836
+ return matchesToolSelector(toolName, serverName, prefix, includeTools, otherCurrentCandidates);
773
837
  }
774
838
 
775
839
  export function isToolExcluded(
776
840
  toolName: string,
777
841
  serverName: string,
778
842
  prefix: ToolPrefix,
779
- excludeTools?: unknown
843
+ excludeTools?: unknown,
844
+ otherCurrentCandidates?: Set<string>,
780
845
  ): boolean {
781
- return matchesToolPattern(getToolNameCandidates(toolName, serverName, prefix), excludeTools);
846
+ return matchesToolSelector(toolName, serverName, prefix, excludeTools, otherCurrentCandidates);
782
847
  }
783
848
 
784
849
  export function isToolAllowed(
@@ -787,7 +852,8 @@ export function isToolAllowed(
787
852
  prefix: ToolPrefix,
788
853
  includeTools?: unknown,
789
854
  excludeTools?: unknown,
855
+ otherCurrentCandidates?: Set<string>,
790
856
  ): boolean {
791
- return isToolIncluded(toolName, serverName, prefix, includeTools)
792
- && !isToolExcluded(toolName, serverName, prefix, excludeTools);
857
+ return isToolIncluded(toolName, serverName, prefix, includeTools, otherCurrentCandidates)
858
+ && !isToolExcluded(toolName, serverName, prefix, excludeTools, otherCurrentCandidates);
793
859
  }
@@ -18,6 +18,7 @@ import type { McpExtensionState } from "./state.ts";
18
18
  import { SessionRecoveryAuthRequiredError, withSessionRecovery, type SessionRecoveryDeps } from "./session-recovery.ts";
19
19
  import { ensureToolCallApproved, isToolCallApprovalRequired } from "./tool-approval.ts";
20
20
  import { extractUiToolVisibility, isUiToolCallableByApp, isUiToolVisibleToModel } from "./ui-tool-visibility.ts";
21
+ import { resourceNameToToolName } from "./resource-tools.ts";
21
22
  import {
22
23
  createUiModelContextUpdate,
23
24
  extractUiPromptText,
@@ -451,6 +452,23 @@ export async function startUiServer(options: UiServerOptions): Promise<UiServerH
451
452
  ...(toolDefinition?.inputSchema !== undefined ? { inputSchema: toolDefinition.inputSchema } : {}),
452
453
  ...(uiVisibility !== undefined ? { uiVisibility } : {}),
453
454
  };
455
+ const approvalMetadata = new Map(options.state?.toolMetadata);
456
+ const definition = options.config?.mcpServers[options.serverName] ?? options.state?.config.mcpServers[options.serverName];
457
+ approvalMetadata.set(options.serverName, [
458
+ ...connection.tools.map(tool => ({
459
+ name: tool.name,
460
+ originalName: tool.name,
461
+ description: tool.description ?? "",
462
+ })),
463
+ ...(definition?.exposeResources !== false ? (connection.resources ?? []).map(resource => {
464
+ const originalName = `read_${resourceNameToToolName(resource.name)}`;
465
+ return {
466
+ name: originalName,
467
+ originalName,
468
+ description: resource.description ?? `Read resource: ${resource.uri}`,
469
+ };
470
+ }) : []),
471
+ ]);
454
472
  const approval = options.state
455
473
  ? await ensureToolCallApproved(
456
474
  options.state,
@@ -459,8 +477,9 @@ export async function startUiServer(options: UiServerOptions): Promise<UiServerH
459
477
  callArgs.arguments,
460
478
  options.state.owner?.signal,
461
479
  "iframe",
480
+ approvalMetadata,
462
481
  )
463
- : options.config && isToolCallApprovalRequired(options.config, options.serverName, toolMeta)
482
+ : options.config && isToolCallApprovalRequired(options.config, options.serverName, toolMeta, approvalMetadata)
464
483
  ? { ok: false as const, reason: "approval_required_headless" as const }
465
484
  : { ok: true as const };
466
485
  if (approval.ok === false) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@herbertgao/pi-extensions",
3
- "version": "2026.8.4",
3
+ "version": "2026.8.5",
4
4
  "description": "Aggregate installer for HerbertGao-maintained Pi extensions.",
5
5
  "keywords": [
6
6
  "extensions",
@@ -42,7 +42,7 @@
42
42
  "@earendil-works/pi-tui": "^0.84.1",
43
43
  "@effect/platform-node": "4.0.0-beta.103",
44
44
  "@effect/platform-node-shared": "4.0.0-beta.103",
45
- "@herbertgao/pi-cc-extensions": "0.8.53",
45
+ "@herbertgao/pi-cc-extensions": "0.8.54",
46
46
  "@herbertgao/pi-copy-response": "0.2.6",
47
47
  "@herbertgao/pi-handoff": "1.1.2",
48
48
  "@herbertgao/pi-inline-skills": "1.0.5",
@@ -51,18 +51,18 @@
51
51
  "@herbertgao/pi-recap": "0.4.4",
52
52
  "@herbertgao/pi-rename": "0.4.2",
53
53
  "@herbertgao/pi-stash": "0.1.1",
54
- "@herbertgao/pi-subagents": "0.15.3",
54
+ "@herbertgao/pi-subagents": "0.15.4",
55
55
  "@herbertgao/pi-titlebar-spinner": "0.1.3",
56
- "@juicesharp/rpiv-ask-user-question": "2.4.0",
57
- "@juicesharp/rpiv-config": "^2.4.0",
56
+ "@juicesharp/rpiv-ask-user-question": "2.5.2",
57
+ "@juicesharp/rpiv-config": "^2.5.2",
58
58
  "@modelcontextprotocol/client": "2.0.0",
59
59
  "@modelcontextprotocol/core": "2.0.0",
60
60
  "@modelcontextprotocol/ext-apps": "^1.2.2",
61
61
  "@modelcontextprotocol/sdk": "^1.29.0",
62
62
  "@mozilla/readability": "^0.6.0",
63
63
  "@napi-rs/keyring": "^1.3.0",
64
- "@narumitw/pi-btw": "0.50.0",
65
- "@narumitw/pi-tui-kit": "^0.49.1",
64
+ "@narumitw/pi-btw": "0.51.0",
65
+ "@narumitw/pi-tui-kit": "^0.54.0",
66
66
  "@noble/ed25519": "^3.1.0",
67
67
  "@pi-plugins/fast-mode": "0.1.9",
68
68
  "@shikijs/cli": "^4.0.2",
@@ -77,13 +77,13 @@
77
77
  "jiti": "^2.7.0",
78
78
  "js-yaml": "^5.2.2",
79
79
  "linkedom": "^0.16.0",
80
- "minimatch": "^10.2.5",
80
+ "minimatch": "^10.2.6",
81
81
  "nanoid": "^5.0.0",
82
82
  "open": "^10.2.0",
83
83
  "p-limit": "^6.1.0",
84
84
  "pi-footer": "0.5.1",
85
- "pi-lens": "3.8.74",
86
- "pi-mcp-adapter": "2.23.0",
85
+ "pi-lens": "4.0.0",
86
+ "pi-mcp-adapter": "2.25.0",
87
87
  "pi-web-access": "0.22.0",
88
88
  "pidusage": "^4.0.1",
89
89
  "promise.try": "^2.0.1",
@@ -161,8 +161,7 @@
161
161
  "skills": [
162
162
  "./node_modules/@dietrichgebert/ponytail/skills",
163
163
  "./node_modules/pi-mcp-adapter/skills",
164
- "./node_modules/pi-lens/skills",
165
- "./node_modules/remote-pi/skills"
164
+ "./node_modules/pi-lens/skills"
166
165
  ]
167
166
  }
168
167
  }