@herbertgao/pi-extensions 2026.8.1 → 2026.8.3
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.
- package/README.md +13 -3
- package/node_modules/@czottmann/pi-automode/README.md +16 -2
- package/node_modules/@czottmann/pi-automode/docs/GLOSSARY.md +35 -0
- package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +18 -9
- package/node_modules/@czottmann/pi-automode/docs/defaults.md +6 -2
- package/node_modules/@czottmann/pi-automode/examples/automode.local.json +6 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +11 -7
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +100 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +32 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +78 -3
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/hard-deny.ts +16 -4
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/paths.ts +23 -1
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/permissions.ts +22 -1
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/types.ts +18 -2
- package/node_modules/@czottmann/pi-automode/package.json +4 -4
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-audit.md +5 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-debt.md +5 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-gain.md +5 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-help.md +5 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-review.md +5 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail.md +5 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/ponytail-frontmatter.cjs +23 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/ponytail.mjs +99 -0
- package/node_modules/@dietrichgebert/ponytail/.qoder/rules/ponytail.md +30 -0
- package/node_modules/@dietrichgebert/ponytail/.qoder-plugin/plugin.json +16 -0
- package/node_modules/@dietrichgebert/ponytail/AGENTS.md +32 -0
- package/node_modules/@dietrichgebert/ponytail/LICENSE +21 -0
- package/node_modules/@dietrichgebert/ponytail/README.es.md +298 -0
- package/node_modules/@dietrichgebert/ponytail/README.ko.md +315 -0
- package/node_modules/@dietrichgebert/ponytail/README.md +351 -0
- package/node_modules/@dietrichgebert/ponytail/assets/benchmark-3model.svg +21 -0
- package/node_modules/@dietrichgebert/ponytail/assets/benchmark-agentic.svg +62 -0
- package/node_modules/@dietrichgebert/ponytail/assets/logo-dark.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/logo-dark.svg +115 -0
- package/node_modules/@dietrichgebert/ponytail/assets/logo-greenpt-dark.svg +27 -0
- package/node_modules/@dietrichgebert/ponytail/assets/logo-greenpt.svg +27 -0
- package/node_modules/@dietrichgebert/ponytail/assets/logo.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/social-preview.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner-es.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner-ko.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/claude-codex-hooks.json +44 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/copilot-hooks.json +21 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-activate.js +96 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-config.js +169 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-instructions.js +98 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-mode-tracker.js +130 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-runtime.js +85 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-statusline.ps1 +24 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-statusline.sh +18 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-subagent.js +77 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/qoder-hooks.json +26 -0
- package/node_modules/@dietrichgebert/ponytail/package.json +47 -0
- package/node_modules/@dietrichgebert/ponytail/pi-extension/index.js +211 -0
- package/node_modules/@dietrichgebert/ponytail/pi-extension/package.json +8 -0
- package/node_modules/@dietrichgebert/ponytail/scripts/uninstall.js +60 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail/SKILL.md +120 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-audit/SKILL.md +41 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-debt/SKILL.md +44 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-gain/SKILL.md +50 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-help/SKILL.md +71 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-review/SKILL.md +57 -0
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +6 -10
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +5 -9
- package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/hero.en.svg +101 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +1 -17
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +15 -9
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/{utils/agent-summary.ts → feature/agent-summary/core.ts} +37 -35
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{agent-summary.ts → agent-summary/index.ts} +3 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +24 -83
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{session-reference.ts → reference/index.ts} +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{agent-autocomplete.ts → reference/subagent.ts} +19 -9
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{pi-startup-header.ts → shell/startup-header.ts} +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{working-message.ts → shell/working-message.ts} +5 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +32 -28
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +452 -94
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +727 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/index.ts +66 -776
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/{feature → renderer}/markdown-enhance.ts +134 -11
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +130 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{mouse-interaction.ts → mouse/interaction.ts} +90 -568
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +144 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/packets.ts +143 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/scroll.ts +195 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/ansi-utils.ts +56 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/diff-renderer.ts +4 -4
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/line-width-safety.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/write-display-utils.ts +12 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/write-execution.ts +1 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-grouping.ts → tool/grouping.ts} +27 -10
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-result.ts → tool/result.ts} +4 -13
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/transcript-refresh.ts +91 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/fullscreen-detect.ts +0 -27
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-cc-extensions/themes/cc-dark.json +1 -0
- package/node_modules/@herbertgao/pi-cc-extensions/themes/cc-light.json +2 -2
- package/node_modules/@herbertgao/pi-stash/README.md +9 -9
- package/node_modules/@herbertgao/pi-stash/package.json +1 -1
- package/node_modules/@herbertgao/pi-stash/src/index.ts +2 -1
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +20 -0
- package/node_modules/@herbertgao/pi-subagents/README.md +6 -2
- package/node_modules/@herbertgao/pi-subagents/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +1 -0
- package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +3 -1
- package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +85 -11
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +61 -39
- package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +26 -35
- package/node_modules/@herbertgao/pi-subagents/src/prompts.ts +15 -1
- package/node_modules/@herbertgao/pi-subagents/src/settings.ts +12 -0
- package/node_modules/@herbertgao/pi-subagents/src/types.ts +2 -0
- package/node_modules/@narumitw/pi-btw/LICENSE +21 -0
- package/node_modules/@narumitw/pi-btw/README.md +210 -0
- package/node_modules/@narumitw/pi-btw/package.json +53 -0
- package/node_modules/@narumitw/pi-btw/src/bring-to-main.ts +632 -0
- package/node_modules/@narumitw/pi-btw/src/btw.ts +996 -0
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +339 -0
- package/node_modules/@narumitw/pi-btw/src/index.ts +1 -0
- package/node_modules/@narumitw/pi-btw/src/menu.ts +296 -0
- package/node_modules/@narumitw/pi-btw/src/settings.ts +237 -0
- package/node_modules/@narumitw/pi-btw/src/side-thread.ts +238 -0
- package/node_modules/@narumitw/pi-btw/src/text.ts +10 -0
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +620 -0
- package/node_modules/@pi-plugins/fast-mode/LICENSE +21 -0
- package/node_modules/@pi-plugins/fast-mode/README.md +92 -0
- package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts +6 -0
- package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts.map +1 -0
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +2026 -0
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -0
- package/node_modules/@pi-plugins/fast-mode/package.json +73 -0
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +78 -0
- package/node_modules/pi-mcp-adapter/README.md +80 -16
- package/node_modules/pi-mcp-adapter/agent-dir.ts +40 -0
- package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +377 -0
- package/node_modules/pi-mcp-adapter/commands.ts +21 -9
- package/node_modules/pi-mcp-adapter/config.ts +110 -49
- package/node_modules/pi-mcp-adapter/direct-tools.ts +40 -27
- package/node_modules/pi-mcp-adapter/elicitation-handler.ts +37 -36
- package/node_modules/pi-mcp-adapter/errors.ts +21 -17
- package/node_modules/pi-mcp-adapter/host-html-template.ts +13 -7
- package/node_modules/pi-mcp-adapter/index.ts +52 -17
- package/node_modules/pi-mcp-adapter/init.ts +9 -7
- package/node_modules/pi-mcp-adapter/json-schema-validator.ts +2 -2
- package/node_modules/pi-mcp-adapter/lifecycle.ts +8 -8
- package/node_modules/pi-mcp-adapter/logger.ts +1 -1
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +122 -25
- package/node_modules/pi-mcp-adapter/mcp-auth.ts +120 -2
- package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +138 -61
- package/node_modules/pi-mcp-adapter/mcp-code.ts +13 -11
- package/node_modules/pi-mcp-adapter/mcp-oauth-provider.ts +62 -17
- package/node_modules/pi-mcp-adapter/mcp-output-guard.ts +15 -11
- package/node_modules/pi-mcp-adapter/mcp-panel.ts +34 -15
- package/node_modules/pi-mcp-adapter/mcp-probe.ts +131 -34
- package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +2 -2
- package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +7 -4
- package/node_modules/pi-mcp-adapter/mcp-trace.ts +59 -64
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +34 -26
- package/node_modules/pi-mcp-adapter/npx-resolver.ts +6 -4
- package/node_modules/pi-mcp-adapter/oauth-handler.ts +1 -1
- package/node_modules/pi-mcp-adapter/oauth.ts +48 -0
- package/node_modules/pi-mcp-adapter/onboarding-state.ts +19 -11
- package/node_modules/pi-mcp-adapter/package.json +20 -9
- package/node_modules/pi-mcp-adapter/panel-keys.ts +20 -4
- package/node_modules/pi-mcp-adapter/prompts.ts +2 -2
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +56 -21
- package/node_modules/pi-mcp-adapter/sampling-handler.ts +22 -15
- package/node_modules/pi-mcp-adapter/search-ranking.ts +2 -1
- package/node_modules/pi-mcp-adapter/server-manager.ts +165 -113
- package/node_modules/pi-mcp-adapter/session-recovery.ts +11 -12
- package/node_modules/pi-mcp-adapter/skills/mcp-scripting/SKILL.md +3 -3
- package/node_modules/pi-mcp-adapter/state.ts +3 -1
- package/node_modules/pi-mcp-adapter/tool-approval.ts +67 -4
- package/node_modules/pi-mcp-adapter/tool-metadata.ts +6 -5
- package/node_modules/pi-mcp-adapter/tool-registrar.ts +187 -3
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +14 -2
- package/node_modules/pi-mcp-adapter/ts-shape.ts +9 -2
- package/node_modules/pi-mcp-adapter/types.ts +111 -22
- package/node_modules/pi-mcp-adapter/ui-app-bridge-helpers.ts +40 -0
- package/node_modules/pi-mcp-adapter/ui-resource-handler.ts +28 -19
- package/node_modules/pi-mcp-adapter/ui-server.ts +90 -58
- package/node_modules/pi-mcp-adapter/ui-session.ts +16 -14
- package/node_modules/pi-mcp-adapter/unix-socket-transport.ts +4 -4
- package/node_modules/pi-mcp-adapter/utils.ts +23 -9
- package/node_modules/pi-web-access/CHANGELOG.md +45 -0
- package/node_modules/pi-web-access/README.md +104 -29
- package/node_modules/pi-web-access/bocha.ts +221 -0
- package/node_modules/pi-web-access/curator-page.ts +113 -12
- package/node_modules/pi-web-access/curator-server.ts +56 -20
- package/node_modules/pi-web-access/datalab-pdf-extract.ts +568 -0
- package/node_modules/pi-web-access/duckduckgo.ts +123 -0
- package/node_modules/pi-web-access/extract.ts +288 -143
- package/node_modules/pi-web-access/feature-config.ts +29 -0
- package/node_modules/pi-web-access/gemini-api.ts +4 -0
- package/node_modules/pi-web-access/gemini-search.ts +45 -12
- package/node_modules/pi-web-access/gemini-web.ts +68 -3
- package/node_modules/pi-web-access/index.ts +160 -71
- package/node_modules/pi-web-access/jina-search.ts +284 -0
- package/node_modules/pi-web-access/kagi.ts +12 -12
- package/node_modules/pi-web-access/openai-search.ts +12 -2
- package/node_modules/pi-web-access/package.json +4 -3
- package/node_modules/pi-web-access/pdf-extract.ts +327 -228
- package/node_modules/pi-web-access/storage.ts +440 -2
- package/node_modules/pi-web-access/summary-model-scope.ts +1 -1
- package/node_modules/pi-web-access/summary-review.ts +4 -2
- package/node_modules/pi-web-access/video-extract.ts +10 -8
- package/node_modules/pi-web-access/xai-search.ts +12 -2
- package/node_modules/pi-web-access/youtube-extract.ts +2 -1
- package/node_modules/remote-pi/LICENSE +21 -0
- package/node_modules/remote-pi/README.md +675 -0
- package/node_modules/remote-pi/dist/actions/handlers.d.ts +122 -0
- package/node_modules/remote-pi/dist/actions/handlers.js +160 -0
- package/node_modules/remote-pi/dist/actions/handlers.js.map +1 -0
- package/node_modules/remote-pi/dist/actions/registry.d.ts +39 -0
- package/node_modules/remote-pi/dist/actions/registry.js +58 -0
- package/node_modules/remote-pi/dist/actions/registry.js.map +1 -0
- package/node_modules/remote-pi/dist/bin/supervisord.d.ts +2 -0
- package/node_modules/remote-pi/dist/bin/supervisord.js +86 -0
- package/node_modules/remote-pi/dist/bin/supervisord.js.map +1 -0
- package/node_modules/remote-pi/dist/commands/builtin_mirror.d.ts +58 -0
- package/node_modules/remote-pi/dist/commands/builtin_mirror.js +71 -0
- package/node_modules/remote-pi/dist/commands/builtin_mirror.js.map +1 -0
- package/node_modules/remote-pi/dist/commands/list_commands.d.ts +60 -0
- package/node_modules/remote-pi/dist/commands/list_commands.js +73 -0
- package/node_modules/remote-pi/dist/commands/list_commands.js.map +1 -0
- package/node_modules/remote-pi/dist/config.d.ts +62 -0
- package/node_modules/remote-pi/dist/config.js +115 -0
- package/node_modules/remote-pi/dist/config.js.map +1 -0
- package/node_modules/remote-pi/dist/daemon/client.d.ts +20 -0
- package/node_modules/remote-pi/dist/daemon/client.js +131 -0
- package/node_modules/remote-pi/dist/daemon/client.js.map +1 -0
- package/node_modules/remote-pi/dist/daemon/control_protocol.d.ts +176 -0
- package/node_modules/remote-pi/dist/daemon/control_protocol.js +63 -0
- package/node_modules/remote-pi/dist/daemon/control_protocol.js.map +1 -0
- package/node_modules/remote-pi/dist/daemon/cron_log.d.ts +45 -0
- package/node_modules/remote-pi/dist/daemon/cron_log.js +72 -0
- package/node_modules/remote-pi/dist/daemon/cron_log.js.map +1 -0
- package/node_modules/remote-pi/dist/daemon/cron_registry.d.ts +80 -0
- package/node_modules/remote-pi/dist/daemon/cron_registry.js +194 -0
- package/node_modules/remote-pi/dist/daemon/cron_registry.js.map +1 -0
- package/node_modules/remote-pi/dist/daemon/id.d.ts +24 -0
- package/node_modules/remote-pi/dist/daemon/id.js +36 -0
- package/node_modules/remote-pi/dist/daemon/id.js.map +1 -0
- package/node_modules/remote-pi/dist/daemon/install.d.ts +170 -0
- package/node_modules/remote-pi/dist/daemon/install.js +547 -0
- package/node_modules/remote-pi/dist/daemon/install.js.map +1 -0
- package/node_modules/remote-pi/dist/daemon/registry.d.ts +63 -0
- package/node_modules/remote-pi/dist/daemon/registry.js +153 -0
- package/node_modules/remote-pi/dist/daemon/registry.js.map +1 -0
- package/node_modules/remote-pi/dist/daemon/rpc_child.d.ts +194 -0
- package/node_modules/remote-pi/dist/daemon/rpc_child.js +389 -0
- package/node_modules/remote-pi/dist/daemon/rpc_child.js.map +1 -0
- package/node_modules/remote-pi/dist/daemon/supervisor.d.ts +93 -0
- package/node_modules/remote-pi/dist/daemon/supervisor.js +596 -0
- package/node_modules/remote-pi/dist/daemon/supervisor.js.map +1 -0
- package/node_modules/remote-pi/dist/extension_ui_bridge.d.ts +26 -0
- package/node_modules/remote-pi/dist/extension_ui_bridge.js +341 -0
- package/node_modules/remote-pi/dist/extension_ui_bridge.js.map +1 -0
- package/node_modules/remote-pi/dist/index.d.ts +213 -0
- package/node_modules/remote-pi/dist/index.js +4996 -0
- package/node_modules/remote-pi/dist/index.js.map +1 -0
- package/node_modules/remote-pi/dist/mcp/mesh_result.d.ts +10 -0
- package/node_modules/remote-pi/dist/mcp/mesh_result.js +42 -0
- package/node_modules/remote-pi/dist/mcp/mesh_result.js.map +1 -0
- package/node_modules/remote-pi/dist/mcp/mesh_server.d.ts +16 -0
- package/node_modules/remote-pi/dist/mcp/mesh_server.js +327 -0
- package/node_modules/remote-pi/dist/mcp/mesh_server.js.map +1 -0
- package/node_modules/remote-pi/dist/mesh/canonical.d.ts +30 -0
- package/node_modules/remote-pi/dist/mesh/canonical.js +61 -0
- package/node_modules/remote-pi/dist/mesh/canonical.js.map +1 -0
- package/node_modules/remote-pi/dist/mesh/client.d.ts +18 -0
- package/node_modules/remote-pi/dist/mesh/client.js +125 -0
- package/node_modules/remote-pi/dist/mesh/client.js.map +1 -0
- package/node_modules/remote-pi/dist/mesh/encoding.d.ts +38 -0
- package/node_modules/remote-pi/dist/mesh/encoding.js +216 -0
- package/node_modules/remote-pi/dist/mesh/encoding.js.map +1 -0
- package/node_modules/remote-pi/dist/mesh/self_revoke.d.ts +73 -0
- package/node_modules/remote-pi/dist/mesh/self_revoke.js +401 -0
- package/node_modules/remote-pi/dist/mesh/self_revoke.js.map +1 -0
- package/node_modules/remote-pi/dist/mesh/siblings.d.ts +49 -0
- package/node_modules/remote-pi/dist/mesh/siblings.js +159 -0
- package/node_modules/remote-pi/dist/mesh/siblings.js.map +1 -0
- package/node_modules/remote-pi/dist/mesh/types.d.ts +34 -0
- package/node_modules/remote-pi/dist/mesh/types.js +11 -0
- package/node_modules/remote-pi/dist/mesh/types.js.map +1 -0
- package/node_modules/remote-pi/dist/mesh/verify.d.ts +17 -0
- package/node_modules/remote-pi/dist/mesh/verify.js +86 -0
- package/node_modules/remote-pi/dist/mesh/verify.js.map +1 -0
- package/node_modules/remote-pi/dist/pairing/crypto.d.ts +8 -0
- package/node_modules/remote-pi/dist/pairing/crypto.js +22 -0
- package/node_modules/remote-pi/dist/pairing/crypto.js.map +1 -0
- package/node_modules/remote-pi/dist/pairing/handshake.d.ts +28 -0
- package/node_modules/remote-pi/dist/pairing/handshake.js +113 -0
- package/node_modules/remote-pi/dist/pairing/handshake.js.map +1 -0
- package/node_modules/remote-pi/dist/pairing/noise-sha256.d.ts +16 -0
- package/node_modules/remote-pi/dist/pairing/noise-sha256.js +103 -0
- package/node_modules/remote-pi/dist/pairing/noise-sha256.js.map +1 -0
- package/node_modules/remote-pi/dist/pairing/qr.d.ts +59 -0
- package/node_modules/remote-pi/dist/pairing/qr.js +125 -0
- package/node_modules/remote-pi/dist/pairing/qr.js.map +1 -0
- package/node_modules/remote-pi/dist/pairing/storage.d.ts +120 -0
- package/node_modules/remote-pi/dist/pairing/storage.js +604 -0
- package/node_modules/remote-pi/dist/pairing/storage.js.map +1 -0
- package/node_modules/remote-pi/dist/protocol/codec.d.ts +7 -0
- package/node_modules/remote-pi/dist/protocol/codec.js +49 -0
- package/node_modules/remote-pi/dist/protocol/codec.js.map +1 -0
- package/node_modules/remote-pi/dist/protocol/types.d.ts +393 -0
- package/node_modules/remote-pi/dist/protocol/types.js +2 -0
- package/node_modules/remote-pi/dist/protocol/types.js.map +1 -0
- package/node_modules/remote-pi/dist/rooms.d.ts +29 -0
- package/node_modules/remote-pi/dist/rooms.js +57 -0
- package/node_modules/remote-pi/dist/rooms.js.map +1 -0
- package/node_modules/remote-pi/dist/session/address.d.ts +49 -0
- package/node_modules/remote-pi/dist/session/address.js +58 -0
- package/node_modules/remote-pi/dist/session/address.js.map +1 -0
- package/node_modules/remote-pi/dist/session/agent_bridge.d.ts +55 -0
- package/node_modules/remote-pi/dist/session/agent_bridge.js +146 -0
- package/node_modules/remote-pi/dist/session/agent_bridge.js.map +1 -0
- package/node_modules/remote-pi/dist/session/bridge.d.ts +37 -0
- package/node_modules/remote-pi/dist/session/bridge.js +130 -0
- package/node_modules/remote-pi/dist/session/bridge.js.map +1 -0
- package/node_modules/remote-pi/dist/session/broker.d.ts +189 -0
- package/node_modules/remote-pi/dist/session/broker.js +507 -0
- package/node_modules/remote-pi/dist/session/broker.js.map +1 -0
- package/node_modules/remote-pi/dist/session/broker_remote.d.ts +74 -0
- package/node_modules/remote-pi/dist/session/broker_remote.js +583 -0
- package/node_modules/remote-pi/dist/session/broker_remote.js.map +1 -0
- package/node_modules/remote-pi/dist/session/cwd_lock.d.ts +33 -0
- package/node_modules/remote-pi/dist/session/cwd_lock.js +126 -0
- package/node_modules/remote-pi/dist/session/cwd_lock.js.map +1 -0
- package/node_modules/remote-pi/dist/session/envelope.d.ts +33 -0
- package/node_modules/remote-pi/dist/session/envelope.js +117 -0
- package/node_modules/remote-pi/dist/session/envelope.js.map +1 -0
- package/node_modules/remote-pi/dist/session/global_config.d.ts +33 -0
- package/node_modules/remote-pi/dist/session/global_config.js +73 -0
- package/node_modules/remote-pi/dist/session/global_config.js.map +1 -0
- package/node_modules/remote-pi/dist/session/ipc.d.ts +27 -0
- package/node_modules/remote-pi/dist/session/ipc.js +22 -0
- package/node_modules/remote-pi/dist/session/ipc.js.map +1 -0
- package/node_modules/remote-pi/dist/session/leader_election.d.ts +32 -0
- package/node_modules/remote-pi/dist/session/leader_election.js +106 -0
- package/node_modules/remote-pi/dist/session/leader_election.js.map +1 -0
- package/node_modules/remote-pi/dist/session/local_config.d.ts +55 -0
- package/node_modules/remote-pi/dist/session/local_config.js +157 -0
- package/node_modules/remote-pi/dist/session/local_config.js.map +1 -0
- package/node_modules/remote-pi/dist/session/mesh_message.d.ts +20 -0
- package/node_modules/remote-pi/dist/session/mesh_message.js +28 -0
- package/node_modules/remote-pi/dist/session/mesh_message.js.map +1 -0
- package/node_modules/remote-pi/dist/session/mesh_node.d.ts +116 -0
- package/node_modules/remote-pi/dist/session/mesh_node.js +573 -0
- package/node_modules/remote-pi/dist/session/mesh_node.js.map +1 -0
- package/node_modules/remote-pi/dist/session/peer.d.ts +139 -0
- package/node_modules/remote-pi/dist/session/peer.js +451 -0
- package/node_modules/remote-pi/dist/session/peer.js.map +1 -0
- package/node_modules/remote-pi/dist/session/peer_inventory.d.ts +13 -0
- package/node_modules/remote-pi/dist/session/peer_inventory.js +48 -0
- package/node_modules/remote-pi/dist/session/peer_inventory.js.map +1 -0
- package/node_modules/remote-pi/dist/session/peer_limits.d.ts +9 -0
- package/node_modules/remote-pi/dist/session/peer_limits.js +21 -0
- package/node_modules/remote-pi/dist/session/peer_limits.js.map +1 -0
- package/node_modules/remote-pi/dist/session/setup_wizard.d.ts +39 -0
- package/node_modules/remote-pi/dist/session/setup_wizard.js +63 -0
- package/node_modules/remote-pi/dist/session/setup_wizard.js.map +1 -0
- package/node_modules/remote-pi/dist/session/tool_gate.d.ts +5 -0
- package/node_modules/remote-pi/dist/session/tool_gate.js +11 -0
- package/node_modules/remote-pi/dist/session/tool_gate.js.map +1 -0
- package/node_modules/remote-pi/dist/session/tools.d.ts +24 -0
- package/node_modules/remote-pi/dist/session/tools.js +252 -0
- package/node_modules/remote-pi/dist/session/tools.js.map +1 -0
- package/node_modules/remote-pi/dist/session/wizard.d.ts +13 -0
- package/node_modules/remote-pi/dist/session/wizard.js +20 -0
- package/node_modules/remote-pi/dist/session/wizard.js.map +1 -0
- package/node_modules/remote-pi/dist/settings.d.ts +15 -0
- package/node_modules/remote-pi/dist/settings.js +52 -0
- package/node_modules/remote-pi/dist/settings.js.map +1 -0
- package/node_modules/remote-pi/dist/transport/peer_channel.d.ts +37 -0
- package/node_modules/remote-pi/dist/transport/peer_channel.js +98 -0
- package/node_modules/remote-pi/dist/transport/peer_channel.js.map +1 -0
- package/node_modules/remote-pi/dist/transport/pi_forward_client.d.ts +29 -0
- package/node_modules/remote-pi/dist/transport/pi_forward_client.js +62 -0
- package/node_modules/remote-pi/dist/transport/pi_forward_client.js.map +1 -0
- package/node_modules/remote-pi/dist/transport/relay_client.d.ts +91 -0
- package/node_modules/remote-pi/dist/transport/relay_client.js +206 -0
- package/node_modules/remote-pi/dist/transport/relay_client.js.map +1 -0
- package/node_modules/remote-pi/dist/ui/footer.d.ts +32 -0
- package/node_modules/remote-pi/dist/ui/footer.js +34 -0
- package/node_modules/remote-pi/dist/ui/footer.js.map +1 -0
- package/node_modules/remote-pi/docs/daemon.md +289 -0
- package/node_modules/remote-pi/package.json +88 -0
- package/node_modules/remote-pi/service-templates/launchd.plist.template +35 -0
- package/node_modules/remote-pi/service-templates/systemd.service.template +19 -0
- package/node_modules/remote-pi/service-templates/task-launcher.vbs.template +10 -0
- package/node_modules/remote-pi/service-templates/task-scheduler.xml.template +38 -0
- package/node_modules/remote-pi/skills/agent-network/SKILL.md +310 -0
- package/package.json +37 -12
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool-diff/write-display-utils.ts +0 -29
- /package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{session-reference-core.ts → reference/session.ts} +0 -0
- /package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{pi-aliases.ts → shell/aliases.ts} +0 -0
- /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/ATTRIBUTION.md +0 -0
- /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/diff-presentation.ts +0 -0
- /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/index.ts +0 -0
- /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/render-utils.ts +0 -0
- /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/shiki-highlight.ts +0 -0
- /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/types.ts +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
1
2
|
import { abortable } from "./abort.ts";
|
|
2
3
|
import { combineAbortSignals } from "./runtime-owner.ts";
|
|
3
4
|
import type { McpExtensionState } from "./state.ts";
|
|
@@ -5,7 +6,12 @@ import {
|
|
|
5
6
|
getToolNameCandidates,
|
|
6
7
|
matchesToolPattern,
|
|
7
8
|
resolveToolPrefix,
|
|
9
|
+
MCP_TOOL_APPROVAL_REQUEST_EVENT,
|
|
8
10
|
type McpConfig,
|
|
11
|
+
type McpToolApprovalDecision,
|
|
12
|
+
type McpToolApprovalHandler,
|
|
13
|
+
type McpToolApprovalOrigin,
|
|
14
|
+
type McpToolApprovalRequest,
|
|
9
15
|
type ToolMetadata,
|
|
10
16
|
} from "./types.ts";
|
|
11
17
|
import { sanitizeTerminalText } from "./utils.ts";
|
|
@@ -34,19 +40,76 @@ export function isToolCallApprovalRequired(
|
|
|
34
40
|
);
|
|
35
41
|
}
|
|
36
42
|
|
|
43
|
+
function isMcpToolApprovalDecision(value: unknown): value is McpToolApprovalDecision {
|
|
44
|
+
return value === "allow_once"
|
|
45
|
+
|| value === "allow_for_session"
|
|
46
|
+
|| value === "deny"
|
|
47
|
+
|| value === "abstain";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function requestBrokerApproval(
|
|
51
|
+
state: McpExtensionState,
|
|
52
|
+
serverName: string,
|
|
53
|
+
toolMeta: ToolMetadata,
|
|
54
|
+
args: Record<string, unknown> | undefined,
|
|
55
|
+
origin: McpToolApprovalOrigin,
|
|
56
|
+
signal?: AbortSignal,
|
|
57
|
+
): Promise<McpToolApprovalDecision> {
|
|
58
|
+
if (!state.approvalEvents) return "abstain";
|
|
59
|
+
|
|
60
|
+
let acceptingClaim = true;
|
|
61
|
+
let handler: McpToolApprovalHandler | undefined;
|
|
62
|
+
const request: McpToolApprovalRequest = {
|
|
63
|
+
requestId: randomUUID(),
|
|
64
|
+
serverName,
|
|
65
|
+
originalToolName: toolMeta.originalName,
|
|
66
|
+
prefixedToolName: toolMeta.name,
|
|
67
|
+
args: args ?? {},
|
|
68
|
+
origin,
|
|
69
|
+
...(signal !== undefined ? { signal } : {}),
|
|
70
|
+
claim(candidate: McpToolApprovalHandler) {
|
|
71
|
+
if (!acceptingClaim || handler) return false;
|
|
72
|
+
handler = candidate;
|
|
73
|
+
return true;
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
state.approvalEvents.emit(MCP_TOOL_APPROVAL_REQUEST_EVENT, request);
|
|
78
|
+
acceptingClaim = false;
|
|
79
|
+
if (!handler) return "abstain";
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const decision = await abortable(Promise.resolve().then(handler), signal);
|
|
83
|
+
return isMcpToolApprovalDecision(decision) ? decision : "deny";
|
|
84
|
+
} catch (error) {
|
|
85
|
+
if (signal?.aborted) throw error;
|
|
86
|
+
return "deny";
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
37
90
|
export async function ensureToolCallApproved(
|
|
38
91
|
state: McpExtensionState,
|
|
39
92
|
serverName: string,
|
|
40
93
|
toolMeta: ToolMetadata,
|
|
41
94
|
args: Record<string, unknown> | undefined,
|
|
42
95
|
signal?: AbortSignal,
|
|
96
|
+
origin: McpToolApprovalOrigin = toolMeta.resourceUri ? "resource" : "proxy",
|
|
43
97
|
): Promise<ToolCallApprovalResult> {
|
|
44
|
-
|
|
98
|
+
const cacheKey = `${serverName}\u0000${toolMeta.originalName}`;
|
|
99
|
+
const approvedToolCalls = state.approvedToolCalls ??= new Map<string, true>();
|
|
100
|
+
if (approvedToolCalls.has(cacheKey)) {
|
|
45
101
|
return { ok: true };
|
|
46
102
|
}
|
|
47
103
|
|
|
48
|
-
const
|
|
49
|
-
if (
|
|
104
|
+
const brokerDecision = await requestBrokerApproval(state, serverName, toolMeta, args, origin, signal);
|
|
105
|
+
if (brokerDecision === "allow_once") return { ok: true };
|
|
106
|
+
if (brokerDecision === "allow_for_session") {
|
|
107
|
+
approvedToolCalls.set(cacheKey, true);
|
|
108
|
+
return { ok: true };
|
|
109
|
+
}
|
|
110
|
+
if (brokerDecision === "deny") return { ok: false, reason: "denied" };
|
|
111
|
+
|
|
112
|
+
if (!isToolCallApprovalRequired(state.config, serverName, toolMeta)) {
|
|
50
113
|
return { ok: true };
|
|
51
114
|
}
|
|
52
115
|
|
|
@@ -71,7 +134,7 @@ export async function ensureToolCallApproved(
|
|
|
71
134
|
return { ok: true };
|
|
72
135
|
}
|
|
73
136
|
if (decision === "Allow for session") {
|
|
74
|
-
|
|
137
|
+
approvedToolCalls.set(cacheKey, true);
|
|
75
138
|
return { ok: true };
|
|
76
139
|
}
|
|
77
140
|
return { ok: false, reason: "denied" };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getToolUiResourceUri } from "
|
|
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
4
|
import { formatToolName, isToolAllowed, resolveToolPrefix } from "./types.ts";
|
|
@@ -44,14 +44,15 @@ export function buildToolMetadata(
|
|
|
44
44
|
} catch {
|
|
45
45
|
failedTools.push(tool.name);
|
|
46
46
|
}
|
|
47
|
+
const uiStreamMode = extractToolUiStreamMode(tool._meta);
|
|
47
48
|
metadata.push({
|
|
48
49
|
name,
|
|
49
50
|
originalName: tool.name,
|
|
50
51
|
description: tool.description ?? "",
|
|
51
|
-
inputSchema: tool.inputSchema,
|
|
52
|
-
uiResourceUri,
|
|
53
|
-
uiVisibility,
|
|
54
|
-
uiStreamMode:
|
|
52
|
+
...(tool.inputSchema !== undefined ? { inputSchema: tool.inputSchema } : {}),
|
|
53
|
+
...(uiResourceUri !== undefined ? { uiResourceUri } : {}),
|
|
54
|
+
...(uiVisibility !== undefined ? { uiVisibility } : {}),
|
|
55
|
+
...(uiStreamMode !== undefined ? { uiStreamMode } : {}),
|
|
55
56
|
});
|
|
56
57
|
}
|
|
57
58
|
|
|
@@ -2,12 +2,189 @@
|
|
|
2
2
|
// NOTE: Tools are NOT registered with Pi - only the unified `mcp` proxy tool is registered.
|
|
3
3
|
// This keeps the LLM context small (1 tool instead of 100s).
|
|
4
4
|
|
|
5
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
import { join } from "node:path";
|
|
5
8
|
import type { McpContent, ContentBlock } from "./types.ts";
|
|
6
9
|
|
|
10
|
+
const MAX_BINARY_RESOURCE_BYTES = 10 * 1024 * 1024;
|
|
11
|
+
const MAX_SESSION_RESOURCE_BYTES = 100 * 1024 * 1024;
|
|
12
|
+
const MAX_SESSION_RESOURCE_FILES = 10_000; // Bounds metadata from empty or tiny resources.
|
|
13
|
+
const CLEANUP_RETRY_DELAY_MS = 30_000;
|
|
14
|
+
const MAX_CLEANUP_RETRY_ATTEMPTS = 3;
|
|
15
|
+
type MaterializedResourceSession = {
|
|
16
|
+
directory: string | undefined;
|
|
17
|
+
bytes: number;
|
|
18
|
+
files: number;
|
|
19
|
+
sequence: number;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function createMaterializedResourceSession(): MaterializedResourceSession {
|
|
23
|
+
return {
|
|
24
|
+
directory: undefined,
|
|
25
|
+
bytes: 0,
|
|
26
|
+
files: 0,
|
|
27
|
+
sequence: 0,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const defaultMaterializedResourceSession = createMaterializedResourceSession();
|
|
32
|
+
const scopedMaterializedResourceSessions = new WeakMap<object, MaterializedResourceSession>();
|
|
33
|
+
const pendingCleanupDirectories = new Set<string>();
|
|
34
|
+
const cleanupRetryAttempts = new Map<string, number>();
|
|
35
|
+
let pendingCleanupRetry: ReturnType<typeof setTimeout> | undefined;
|
|
36
|
+
|
|
37
|
+
function isAbortedScope(scope: object | undefined): boolean {
|
|
38
|
+
return !!scope && "aborted" in scope && (scope as { aborted?: unknown }).aborted === true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getMaterializedResourceSession(scope?: object): MaterializedResourceSession | undefined {
|
|
42
|
+
if (isAbortedScope(scope)) return undefined;
|
|
43
|
+
if (!scope) return defaultMaterializedResourceSession;
|
|
44
|
+
let session = scopedMaterializedResourceSessions.get(scope);
|
|
45
|
+
if (!session) {
|
|
46
|
+
session = createMaterializedResourceSession();
|
|
47
|
+
scopedMaterializedResourceSessions.set(scope, session);
|
|
48
|
+
}
|
|
49
|
+
return session;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type BinaryResource = { uri?: string | undefined; text?: string | undefined; mimeType?: string | undefined; blob: string };
|
|
53
|
+
type McpResourceContent = {
|
|
54
|
+
uri: string;
|
|
55
|
+
text?: string | undefined;
|
|
56
|
+
blob?: string | undefined;
|
|
57
|
+
mimeType?: string | undefined;
|
|
58
|
+
[key: string]: unknown;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
function hasRetryableCleanupDirectory(): boolean {
|
|
62
|
+
for (const directory of pendingCleanupDirectories) {
|
|
63
|
+
if ((cleanupRetryAttempts.get(directory) ?? 0) < MAX_CLEANUP_RETRY_ATTEMPTS) return true;
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function schedulePendingCleanupRetry(): void {
|
|
69
|
+
if (pendingCleanupRetry || !hasRetryableCleanupDirectory()) return;
|
|
70
|
+
for (const directory of pendingCleanupDirectories) {
|
|
71
|
+
const attempts = cleanupRetryAttempts.get(directory) ?? 0;
|
|
72
|
+
if (attempts < MAX_CLEANUP_RETRY_ATTEMPTS) cleanupRetryAttempts.set(directory, attempts + 1);
|
|
73
|
+
}
|
|
74
|
+
pendingCleanupRetry = setTimeout(() => {
|
|
75
|
+
pendingCleanupRetry = undefined;
|
|
76
|
+
try {
|
|
77
|
+
drainPendingCleanupDirectories();
|
|
78
|
+
} catch {
|
|
79
|
+
// drainPendingCleanupDirectories already retained the paths and rescheduled another retry.
|
|
80
|
+
}
|
|
81
|
+
}, CLEANUP_RETRY_DELAY_MS);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function drainPendingCleanupDirectories(): void {
|
|
85
|
+
const failures: unknown[] = [];
|
|
86
|
+
for (const directory of Array.from(pendingCleanupDirectories)) {
|
|
87
|
+
try {
|
|
88
|
+
rmSync(directory, { recursive: true, force: true });
|
|
89
|
+
pendingCleanupDirectories.delete(directory);
|
|
90
|
+
cleanupRetryAttempts.delete(directory);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
failures.push(error);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (pendingCleanupDirectories.size === 0 && pendingCleanupRetry) {
|
|
96
|
+
clearTimeout(pendingCleanupRetry);
|
|
97
|
+
pendingCleanupRetry = undefined;
|
|
98
|
+
}
|
|
99
|
+
if (failures.length > 0) {
|
|
100
|
+
schedulePendingCleanupRetry();
|
|
101
|
+
throw new AggregateError(failures, "Failed to clean materialized MCP resources");
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function cleanupMaterializedBinaryResources(scope?: object): void {
|
|
106
|
+
const session = scope ? scopedMaterializedResourceSessions.get(scope) : defaultMaterializedResourceSession;
|
|
107
|
+
if (session?.directory) pendingCleanupDirectories.add(session.directory);
|
|
108
|
+
if (session) {
|
|
109
|
+
session.directory = undefined;
|
|
110
|
+
session.bytes = 0;
|
|
111
|
+
session.files = 0;
|
|
112
|
+
session.sequence = 0;
|
|
113
|
+
if (scope) scopedMaterializedResourceSessions.delete(scope);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
drainPendingCleanupDirectories();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function replaceBlob(resource: BinaryResource, text: string): string {
|
|
120
|
+
delete (resource as Partial<BinaryResource>).blob;
|
|
121
|
+
resource.text = text;
|
|
122
|
+
return text;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function omitBinaryResource(resource: BinaryResource, reason: string): string {
|
|
126
|
+
return replaceBlob(resource, [
|
|
127
|
+
`[Resource: ${resource.uri ?? "(no URI)"}]`,
|
|
128
|
+
`Binary content omitted: ${reason}`,
|
|
129
|
+
`MIME type: ${resource.mimeType ?? "application/octet-stream"}`,
|
|
130
|
+
].join("\n"));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function materializeBinaryResource(resource: BinaryResource, scope?: object): string {
|
|
134
|
+
const session = getMaterializedResourceSession(scope);
|
|
135
|
+
if (!session) return omitBinaryResource(resource, "runtime stopped");
|
|
136
|
+
const decodedBytes = Buffer.byteLength(resource.blob, "base64");
|
|
137
|
+
if (decodedBytes > MAX_BINARY_RESOURCE_BYTES) {
|
|
138
|
+
return omitBinaryResource(resource, "decoded size exceeds 10 MiB");
|
|
139
|
+
}
|
|
140
|
+
if (
|
|
141
|
+
session.bytes + decodedBytes > MAX_SESSION_RESOURCE_BYTES ||
|
|
142
|
+
session.files >= MAX_SESSION_RESOURCE_FILES
|
|
143
|
+
) {
|
|
144
|
+
return omitBinaryResource(resource, "session resource limit reached");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
session.directory ??= mkdtempSync(join(tmpdir(), "pi-mcp-resource-"));
|
|
149
|
+
} catch {
|
|
150
|
+
return omitBinaryResource(resource, "could not be saved");
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const filePath = join(session.directory, `resource-${++session.sequence}.bin`);
|
|
154
|
+
session.bytes += decodedBytes;
|
|
155
|
+
session.files += 1;
|
|
156
|
+
try {
|
|
157
|
+
writeFileSync(filePath, Buffer.from(resource.blob, "base64"), { flag: "wx", mode: 0o600 });
|
|
158
|
+
} catch {
|
|
159
|
+
try {
|
|
160
|
+
rmSync(filePath, { force: true });
|
|
161
|
+
session.bytes -= decodedBytes;
|
|
162
|
+
session.files -= 1;
|
|
163
|
+
} catch {
|
|
164
|
+
// Keep the reservation when a partial file cannot be removed.
|
|
165
|
+
}
|
|
166
|
+
return omitBinaryResource(resource, "could not be saved");
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return replaceBlob(resource, [
|
|
170
|
+
`[Resource: ${resource.uri ?? "(no URI)"}]`,
|
|
171
|
+
`Binary content saved to ${filePath}`,
|
|
172
|
+
`MIME type: ${resource.mimeType ?? "application/octet-stream"}`,
|
|
173
|
+
].join("\n"));
|
|
174
|
+
}
|
|
175
|
+
|
|
7
176
|
/**
|
|
8
177
|
* Transform MCP content types to Pi content blocks.
|
|
9
178
|
*/
|
|
10
|
-
export function
|
|
179
|
+
export function transformMcpResourceContents(contents: McpResourceContent[], scope?: object): ContentBlock[] {
|
|
180
|
+
return contents.map(resource => {
|
|
181
|
+
if (typeof resource.text === "string") return { type: "text" as const, text: resource.text };
|
|
182
|
+
if (typeof resource.blob === "string") return { type: "text" as const, text: materializeBinaryResource(resource as BinaryResource, scope) };
|
|
183
|
+
return { type: "text" as const, text: JSON.stringify(resource) };
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function transformMcpContent(content: McpContent[], scope?: object): ContentBlock[] {
|
|
11
188
|
return content.map(c => {
|
|
12
189
|
if (c.type === "text") {
|
|
13
190
|
return { type: "text" as const, text: c.text ?? "" };
|
|
@@ -21,6 +198,13 @@ export function transformMcpContent(content: McpContent[]): ContentBlock[] {
|
|
|
21
198
|
}
|
|
22
199
|
if (c.type === "resource") {
|
|
23
200
|
const resourceUri = c.resource?.uri ?? "(no URI)";
|
|
201
|
+
if (c.resource && "blob" in c.resource && typeof c.resource.blob === "string") {
|
|
202
|
+
const binaryResource = c.resource as typeof c.resource & { mimeType?: string; blob: string };
|
|
203
|
+
return {
|
|
204
|
+
type: "text" as const,
|
|
205
|
+
text: materializeBinaryResource(binaryResource, scope),
|
|
206
|
+
};
|
|
207
|
+
}
|
|
24
208
|
const resourceContent = c.resource?.text ?? (c.resource ? JSON.stringify(c.resource) : "(no content)");
|
|
25
209
|
return {
|
|
26
210
|
type: "text" as const,
|
|
@@ -49,8 +233,8 @@ export function transformMcpContent(content: McpContent[]): ContentBlock[] {
|
|
|
49
233
|
* Resolve a tool result's content blocks, falling back to structuredContent
|
|
50
234
|
* when content is empty.
|
|
51
235
|
*/
|
|
52
|
-
export function resolveMcpResultContent(result: Record<string, unknown
|
|
53
|
-
const blocks = transformMcpContent((Array.isArray(result.content) ? result.content : []) as McpContent[]);
|
|
236
|
+
export function resolveMcpResultContent(result: Record<string, unknown>, scope?: object): ContentBlock[] {
|
|
237
|
+
const blocks = transformMcpContent((Array.isArray(result.content) ? result.content : []) as McpContent[], scope);
|
|
54
238
|
if (blocks.length > 0) return blocks;
|
|
55
239
|
|
|
56
240
|
if (result.structuredContent !== undefined && result.structuredContent !== null) {
|
|
@@ -41,6 +41,7 @@ class CollapsibleText implements Component {
|
|
|
41
41
|
private readonly fullText: Text;
|
|
42
42
|
private readonly footerText: Text;
|
|
43
43
|
private collapsedText: { charBudget: number; fullyIncluded: boolean; text: Text } | null = null;
|
|
44
|
+
private collapsedRender: { width: number; charBudget: number; lines: string[] } | null = null;
|
|
44
45
|
|
|
45
46
|
constructor(
|
|
46
47
|
private readonly text: string,
|
|
@@ -70,18 +71,29 @@ class CollapsibleText implements Component {
|
|
|
70
71
|
fullyIncluded: prefix === this.text,
|
|
71
72
|
text: new Text(prefix, 0, 0),
|
|
72
73
|
};
|
|
74
|
+
this.collapsedRender = null;
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
const lines = this.collapsedText.text.render(width);
|
|
76
78
|
if (!this.preTruncated && this.collapsedText.fullyIncluded && lines.length <= this.maxCollapsedLines) return lines;
|
|
79
|
+
if (this.collapsedRender?.width === width && this.collapsedRender.charBudget === charBudget) {
|
|
80
|
+
return this.collapsedRender.lines;
|
|
81
|
+
}
|
|
77
82
|
|
|
78
|
-
|
|
83
|
+
const rendered = [
|
|
79
84
|
...lines.slice(0, this.maxCollapsedLines),
|
|
80
85
|
...this.footerText.render(width),
|
|
81
86
|
];
|
|
87
|
+
this.collapsedRender = { width, charBudget, lines: rendered };
|
|
88
|
+
return rendered;
|
|
82
89
|
}
|
|
83
90
|
|
|
84
|
-
invalidate(): void {
|
|
91
|
+
invalidate(): void {
|
|
92
|
+
this.fullText.invalidate();
|
|
93
|
+
this.footerText.invalidate();
|
|
94
|
+
this.collapsedText?.text.invalidate();
|
|
95
|
+
this.collapsedRender = null;
|
|
96
|
+
}
|
|
85
97
|
}
|
|
86
98
|
|
|
87
99
|
function truncateText(value: string, maxChars: number): string {
|
|
@@ -39,7 +39,10 @@ export function renderTsShape(inputSchema: unknown): string | null {
|
|
|
39
39
|
if (typeof schema.$ref !== "string") return null;
|
|
40
40
|
const match = schema.$ref.match(/^#\/(\$defs|definitions)\/([^/]+)$/);
|
|
41
41
|
if (!match) return null;
|
|
42
|
-
const
|
|
42
|
+
const definitionGroup = match[1];
|
|
43
|
+
const definitionName = match[2];
|
|
44
|
+
if (definitionGroup === undefined || definitionName === undefined) return null;
|
|
45
|
+
const definitionKey = `${definitionGroup}/${decodePointerToken(definitionName)}`;
|
|
43
46
|
if (!definitions.has(definitionKey)) return null;
|
|
44
47
|
return aliasFor(definitionKey);
|
|
45
48
|
}
|
|
@@ -108,7 +111,11 @@ function isSchema(value: unknown): value is Schema {
|
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
function hasUnsupportedKeyword(schema: Schema): boolean {
|
|
111
|
-
return UNSUPPORTED_KEYWORDS.some(keyword =>
|
|
114
|
+
return UNSUPPORTED_KEYWORDS.some(keyword => {
|
|
115
|
+
if (!Object.hasOwn(schema, keyword)) return false;
|
|
116
|
+
// `additionalProperties: false` is a closed-object constraint, not a shape that this renderer needs to understand.
|
|
117
|
+
return keyword !== "additionalProperties" || schema.additionalProperties !== false;
|
|
118
|
+
});
|
|
112
119
|
}
|
|
113
120
|
|
|
114
121
|
function decodePointerToken(token: string): string {
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
// types.ts - Core type definitions
|
|
2
|
-
import type {
|
|
3
|
-
|
|
2
|
+
import type {
|
|
3
|
+
ContentBlock as McpContentBlock,
|
|
4
|
+
ListPromptsResult,
|
|
5
|
+
ListResourcesResult,
|
|
6
|
+
ListToolsResult,
|
|
7
|
+
Transport as McpTransport,
|
|
8
|
+
} from "@modelcontextprotocol/client";
|
|
4
9
|
import type { TextContent, ImageContent } from "@earendil-works/pi-ai";
|
|
5
10
|
import type { UiStreamMode } from "./ui-stream-types.ts";
|
|
6
11
|
import type { UiToolVisibility } from "./ui-tool-visibility.ts";
|
|
@@ -48,36 +53,41 @@ export type ImportKind =
|
|
|
48
53
|
| "windsurf"
|
|
49
54
|
| "vscode";
|
|
50
55
|
|
|
51
|
-
|
|
56
|
+
type SdkTool = ListToolsResult["tools"][number];
|
|
57
|
+
type SdkResource = ListResourcesResult["resources"][number];
|
|
58
|
+
type SdkPrompt = ListPromptsResult["prompts"][number];
|
|
59
|
+
type SdkPromptArgument = NonNullable<SdkPrompt["arguments"]>[number];
|
|
60
|
+
|
|
61
|
+
// MCP wire definitions derive their field types from the installed SDK while
|
|
62
|
+
// retaining the adapter's deliberately smaller public surface.
|
|
52
63
|
export interface McpTool {
|
|
53
|
-
name:
|
|
54
|
-
title?:
|
|
55
|
-
description?:
|
|
56
|
-
inputSchema?:
|
|
57
|
-
_meta?:
|
|
64
|
+
name: SdkTool["name"];
|
|
65
|
+
title?: SdkTool["title"];
|
|
66
|
+
description?: SdkTool["description"];
|
|
67
|
+
inputSchema?: SdkTool["inputSchema"]; // JSON Schema
|
|
68
|
+
_meta?: SdkTool["_meta"];
|
|
58
69
|
}
|
|
59
70
|
|
|
60
|
-
// Resource definition from MCP server
|
|
61
71
|
export interface McpResource {
|
|
62
|
-
uri:
|
|
63
|
-
name:
|
|
64
|
-
description?:
|
|
65
|
-
mimeType?:
|
|
66
|
-
_meta?:
|
|
72
|
+
uri: SdkResource["uri"];
|
|
73
|
+
name: SdkResource["name"];
|
|
74
|
+
description?: SdkResource["description"];
|
|
75
|
+
mimeType?: SdkResource["mimeType"];
|
|
76
|
+
_meta?: SdkResource["_meta"];
|
|
67
77
|
}
|
|
68
78
|
|
|
69
79
|
export interface McpPromptArgument {
|
|
70
|
-
name:
|
|
71
|
-
description?:
|
|
72
|
-
required?:
|
|
80
|
+
name: SdkPromptArgument["name"];
|
|
81
|
+
description?: SdkPromptArgument["description"];
|
|
82
|
+
required?: SdkPromptArgument["required"];
|
|
73
83
|
}
|
|
74
84
|
|
|
75
85
|
export interface McpPrompt {
|
|
76
|
-
name:
|
|
77
|
-
title?:
|
|
78
|
-
description?:
|
|
79
|
-
arguments?:
|
|
80
|
-
_meta?:
|
|
86
|
+
name: SdkPrompt["name"];
|
|
87
|
+
title?: SdkPrompt["title"];
|
|
88
|
+
description?: SdkPrompt["description"];
|
|
89
|
+
arguments?: SdkPrompt["arguments"];
|
|
90
|
+
_meta?: SdkPrompt["_meta"];
|
|
81
91
|
}
|
|
82
92
|
|
|
83
93
|
export interface UiResourceMeta {
|
|
@@ -340,6 +350,10 @@ export interface OAuthConfig {
|
|
|
340
350
|
clientName?: string;
|
|
341
351
|
/** Client homepage URI for dynamic registration */
|
|
342
352
|
clientUri?: string;
|
|
353
|
+
/** Client logo URL for dynamic registration; shown on consent screens */
|
|
354
|
+
logoUri?: string;
|
|
355
|
+
/** Security-weakening escape hatch for known-misconfigured authorization servers. */
|
|
356
|
+
skipIssuerMetadataValidation?: boolean;
|
|
343
357
|
}
|
|
344
358
|
|
|
345
359
|
// Server configuration
|
|
@@ -387,6 +401,20 @@ export interface ServerEntry {
|
|
|
387
401
|
debug?: boolean; // Show server stderr (default: false)
|
|
388
402
|
/** Enable metadata-only JSONL protocol tracing for this server. */
|
|
389
403
|
trace?: boolean;
|
|
404
|
+
/** Force a specific HTTP MCP transport. Used by Agent Plugins, whose `type` declares the transport and forbids client fallback. */
|
|
405
|
+
httpTransport?: "streamable-http" | "sse";
|
|
406
|
+
/** Client-managed persistent data directory for Agent Plugin stdio servers. */
|
|
407
|
+
pluginDataDir?: string;
|
|
408
|
+
/** Treat env values as already resolved literals. Used for Agent Plugin env rules. */
|
|
409
|
+
literalEnv?: boolean;
|
|
410
|
+
/**
|
|
411
|
+
* MCP protocol era negotiation for this server. Defaults to `"legacy"`
|
|
412
|
+
* (byte-equivalent to pre-2026 behavior — no `versionNegotiation` is sent).
|
|
413
|
+
* `"auto"` offers the SDK's default 2026-07-28+ modern versions with
|
|
414
|
+
* legacy fallback; `"2026-07-28"` pins the connection to that revision
|
|
415
|
+
* with no fallback. `auto` and `2026-07-28` must be set explicitly.
|
|
416
|
+
*/
|
|
417
|
+
protocolVersion?: "legacy" | "auto" | "2026-07-28";
|
|
390
418
|
// Keep configuration visible without allowing connections or execution.
|
|
391
419
|
disabled?: boolean;
|
|
392
420
|
}
|
|
@@ -422,6 +450,23 @@ export interface McpTraceSettings {
|
|
|
422
450
|
maxEvents?: number;
|
|
423
451
|
}
|
|
424
452
|
|
|
453
|
+
export const MCP_TOOL_APPROVAL_REQUEST_EVENT = "pi-mcp-adapter:tool-approval-request" as const;
|
|
454
|
+
|
|
455
|
+
export type McpToolApprovalOrigin = "proxy" | "direct" | "script" | "resource" | "iframe";
|
|
456
|
+
export type McpToolApprovalDecision = "allow_once" | "allow_for_session" | "deny" | "abstain";
|
|
457
|
+
export type McpToolApprovalHandler = () => McpToolApprovalDecision | Promise<McpToolApprovalDecision>;
|
|
458
|
+
|
|
459
|
+
export interface McpToolApprovalRequest {
|
|
460
|
+
requestId: string;
|
|
461
|
+
serverName: string;
|
|
462
|
+
originalToolName: string;
|
|
463
|
+
prefixedToolName: string;
|
|
464
|
+
args: Record<string, unknown>;
|
|
465
|
+
origin: McpToolApprovalOrigin;
|
|
466
|
+
signal?: AbortSignal;
|
|
467
|
+
claim(handler: McpToolApprovalHandler): boolean;
|
|
468
|
+
}
|
|
469
|
+
|
|
425
470
|
export interface McpSettings {
|
|
426
471
|
toolPrefix?: ToolPrefix;
|
|
427
472
|
/** Show the plug prefix in MCP status and connection text (default: true). Set to false to disable it. */
|
|
@@ -430,6 +475,8 @@ export interface McpSettings {
|
|
|
430
475
|
mcpFooterStatus?: McpFooterStatus;
|
|
431
476
|
/** Discover detected host-specific MCP configs only when explicitly enabled. */
|
|
432
477
|
hostConfigDiscovery?: HostConfigDiscovery;
|
|
478
|
+
/** Agent Plugin package directories to load MCP servers from. */
|
|
479
|
+
agentPluginPaths?: string[];
|
|
433
480
|
idleTimeout?: number; // minutes, default 10, 0 to disable
|
|
434
481
|
requestTimeoutMs?: number; // milliseconds, overrides the SDK request timeout when > 0
|
|
435
482
|
directTools?: boolean;
|
|
@@ -622,6 +669,48 @@ export function resolveToolPrefix(
|
|
|
622
669
|
return definition?.toolPrefix ?? globalPrefix ?? "server";
|
|
623
670
|
}
|
|
624
671
|
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Resolve a configured MCP server name from a prefixed tool name.
|
|
675
|
+
*
|
|
676
|
+
* When the proxy tool is addressed with a fully-qualified name such as
|
|
677
|
+
* `searxng_searxng_web_search`, downstream policy systems (for example a
|
|
678
|
+
* permission gate) need to recover the owning server so they can evaluate
|
|
679
|
+
* server-scoped rules against the bare server name. This performs the inverse
|
|
680
|
+
* of {@link getServerPrefix}: it finds the longest configured server prefix
|
|
681
|
+
* that the tool name starts with and returns that server's name.
|
|
682
|
+
*
|
|
683
|
+
* @param toolName - the tool name as passed to the proxy `mcp({ tool })` call.
|
|
684
|
+
* @param serverNames - the configured MCP server names (keys of `mcpServers`).
|
|
685
|
+
* @param prefix - the active tool-prefix mode.
|
|
686
|
+
* @returns the resolved server name, or `undefined` when no prefix matches or
|
|
687
|
+
* the prefix mode is `"none"`.
|
|
688
|
+
*/
|
|
689
|
+
export function resolveServerFromToolName(
|
|
690
|
+
toolName: string,
|
|
691
|
+
serverNames: Iterable<string>,
|
|
692
|
+
prefix: ToolPrefix,
|
|
693
|
+
): string | undefined {
|
|
694
|
+
if (prefix === "none") return undefined;
|
|
695
|
+
const candidates: { name: string; prefix: string }[] = [];
|
|
696
|
+
for (const name of serverNames) {
|
|
697
|
+
const p = getServerPrefix(name, prefix);
|
|
698
|
+
if (p && toolName.startsWith(p + "_")) candidates.push({ name, prefix: p });
|
|
699
|
+
}
|
|
700
|
+
if (candidates.length === 0) return undefined;
|
|
701
|
+
candidates.sort((a, b) => b.prefix.length - a.prefix.length);
|
|
702
|
+
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.
|
|
708
|
+
if (candidates.some((c) => c.prefix === best!.prefix && c.name !== best!.name)) {
|
|
709
|
+
return undefined;
|
|
710
|
+
}
|
|
711
|
+
return best?.name;
|
|
712
|
+
}
|
|
713
|
+
|
|
625
714
|
export function sanitizePromptName(name: string): string {
|
|
626
715
|
const cleaned = name.replace(/[^A-Za-z0-9_-]+/g, "_").replace(/^[_-]+|[_-]+$/g, "");
|
|
627
716
|
if (!cleaned) return "prompt";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { UiResourcePermissions } from "./types.ts";
|
|
2
|
+
|
|
3
|
+
export const RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";
|
|
4
|
+
|
|
5
|
+
const RESOURCE_URI_META_KEY = "ui/resourceUri";
|
|
6
|
+
|
|
7
|
+
export function getToolUiResourceUri(tool: { _meta?: Record<string, unknown> | undefined }): string | undefined {
|
|
8
|
+
const meta = tool._meta;
|
|
9
|
+
let resourceUri = getNestedResourceUri(meta);
|
|
10
|
+
if (resourceUri === undefined) {
|
|
11
|
+
resourceUri = meta?.[RESOURCE_URI_META_KEY];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (typeof resourceUri === "string" && resourceUri.startsWith("ui://")) {
|
|
15
|
+
return resourceUri;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (resourceUri !== undefined) {
|
|
19
|
+
throw new Error(`Invalid UI resource URI: ${JSON.stringify(resourceUri)}`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function buildAllowAttribute(permissions: UiResourcePermissions | undefined): string {
|
|
26
|
+
if (!permissions) return "";
|
|
27
|
+
|
|
28
|
+
const allowed: string[] = [];
|
|
29
|
+
if (permissions.camera) allowed.push("camera");
|
|
30
|
+
if (permissions.microphone) allowed.push("microphone");
|
|
31
|
+
if (permissions.geolocation) allowed.push("geolocation");
|
|
32
|
+
if (permissions.clipboardWrite) allowed.push("clipboard-write");
|
|
33
|
+
return allowed.join("; ");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function getNestedResourceUri(meta: Record<string, unknown> | undefined): unknown {
|
|
37
|
+
const ui = meta?.ui;
|
|
38
|
+
if (!ui || typeof ui !== "object") return undefined;
|
|
39
|
+
return (ui as Record<string, unknown>).resourceUri;
|
|
40
|
+
}
|