@herbertgao/pi-extensions 2026.8.2 → 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 +9 -2
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +6 -8
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +5 -7
- 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 +5 -3
- 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} +2 -6
- 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 +379 -85
- 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 +65 -775
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/{feature → renderer}/markdown-enhance.ts +35 -31
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{mouse-hover.ts → mouse/hover.ts} +5 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{mouse-interaction.ts → mouse/interaction.ts} +34 -35
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{mouse-layout.ts → mouse/layout.ts} +5 -21
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{mouse-packets.ts → mouse/packets.ts} +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{mouse-scroll.ts → mouse/scroll.ts} +48 -37
- 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 +2 -2
- 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} +18 -8
- 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/utils/fullscreen-detect.ts +0 -27
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
- package/node_modules/@herbertgao/pi-subagents/package.json +2 -2
- 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/index.ts +33 -35
- 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/pi-mcp-adapter/CHANGELOG.md +19 -0
- package/node_modules/pi-mcp-adapter/README.md +19 -4
- package/node_modules/pi-mcp-adapter/agent-dir.ts +40 -0
- package/node_modules/pi-mcp-adapter/commands.ts +12 -2
- package/node_modules/pi-mcp-adapter/direct-tools.ts +6 -8
- package/node_modules/pi-mcp-adapter/index.ts +15 -3
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +87 -4
- package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +138 -61
- package/node_modules/pi-mcp-adapter/mcp-oauth-provider.ts +43 -4
- package/node_modules/pi-mcp-adapter/oauth.ts +48 -0
- package/node_modules/pi-mcp-adapter/package.json +8 -2
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +8 -10
- package/node_modules/pi-mcp-adapter/tool-registrar.ts +187 -3
- package/node_modules/pi-mcp-adapter/types.ts +2 -0
- 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 +19 -9
- 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
|
@@ -6,9 +6,9 @@ import {
|
|
|
6
6
|
visibleWidth,
|
|
7
7
|
type Component,
|
|
8
8
|
} from "@earendil-works/pi-tui";
|
|
9
|
-
import { TOOL_LOADING_INTERVAL_MS, toolLoadingIcon } from "
|
|
10
|
-
import { sanitizeToolResultText } from "
|
|
11
|
-
import { showMoreHintText } from "
|
|
9
|
+
import { TOOL_LOADING_INTERVAL_MS, toolLoadingIcon } from "../../utils/tool-loading-icon.ts";
|
|
10
|
+
import { sanitizeToolResultText } from "../../utils/tool-result-sanitize.ts";
|
|
11
|
+
import { showMoreHintText } from "../show-more-hint.ts";
|
|
12
12
|
|
|
13
13
|
const PATCH_KEY = Symbol.for("pi.ccstyle.tool-grouping-patch");
|
|
14
14
|
const PARENT_KEY = Symbol.for("pi.ccstyle.tool-grouping-parent");
|
|
@@ -101,7 +101,7 @@ function stripLeadingStatusIcon(line: string): string {
|
|
|
101
101
|
);
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
function stripBackgroundAnsi(line: string): string {
|
|
104
|
+
export function stripBackgroundAnsi(line: string): string {
|
|
105
105
|
return line.replace(/\x1b\[(?:4[0-9]|10[0-7]|48(?:(?:;|:)[0-9]+)+|49)m/g, "");
|
|
106
106
|
}
|
|
107
107
|
|
|
@@ -126,15 +126,25 @@ function stripLeadingSpaces(line: string, count: number): string {
|
|
|
126
126
|
return ansi + line.slice(offset);
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
|
|
129
|
+
/** 生成一行铺满 width 的 slot 背景行;bgAnsiOverride 可替换背景 ANSI(用于提亮等)。 */
|
|
130
|
+
export function paddedBackgroundRow(
|
|
131
|
+
theme: any,
|
|
132
|
+
slot: string,
|
|
133
|
+
content: string,
|
|
134
|
+
width: number,
|
|
135
|
+
bgAnsiOverride?: string,
|
|
136
|
+
): string {
|
|
130
137
|
const innerWidth = Math.max(0, width - 2);
|
|
131
138
|
const clipped = truncateToWidth(stripBackgroundAnsi(content), innerWidth, "");
|
|
132
139
|
const row = ` ${clipped}${" ".repeat(Math.max(0, innerWidth - visibleWidth(clipped)))} `;
|
|
133
|
-
if (typeof theme?.bg !== "function") return row;
|
|
134
140
|
const bgAnsi =
|
|
135
|
-
|
|
141
|
+
bgAnsiOverride ||
|
|
142
|
+
(typeof theme?.bg === "function"
|
|
143
|
+
? theme.getBgAnsi?.(slot) || theme.bg(slot, "").match(/^\x1b\[[0-?]*[ -/]*[@-~]/)?.[0] || ""
|
|
144
|
+
: "");
|
|
136
145
|
const stable = bgAnsi ? row.replace(/\x1b\[(?:0)?m/g, (reset) => reset + bgAnsi) : row;
|
|
137
|
-
return theme.bg(slot, stable);
|
|
146
|
+
if (!bgAnsi) return typeof theme?.bg === "function" ? theme.bg(slot, stable) : row;
|
|
147
|
+
return `${bgAnsi}${stable}\x1b[49m`;
|
|
138
148
|
}
|
|
139
149
|
|
|
140
150
|
function oneLine(value: unknown, max = 96): string {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Text, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
|
|
2
2
|
import { inspect } from "node:util";
|
|
3
|
-
import { config } from "
|
|
4
|
-
import { showMoreHintText } from "
|
|
5
|
-
import { TOOL_LOADING_INTERVAL_MS, toolLoadingIcon } from "
|
|
6
|
-
import { sanitizeToolResultText } from "
|
|
3
|
+
import { config } from "../../config/config.ts";
|
|
4
|
+
import { showMoreHintText } from "../show-more-hint.ts";
|
|
5
|
+
import { TOOL_LOADING_INTERVAL_MS, toolLoadingIcon } from "../../utils/tool-loading-icon.ts";
|
|
6
|
+
import { sanitizeToolResultText } from "../../utils/tool-result-sanitize.ts";
|
|
7
7
|
|
|
8
8
|
const TOOL_VIEWPORT_WIDTH_RATIO = 0.8;
|
|
9
9
|
|
|
@@ -677,15 +677,6 @@ export function renderExpandedToolResult(
|
|
|
677
677
|
return new Text(theme.fg(color, renderCollapsedToolResult("Done")), 0, 0);
|
|
678
678
|
}
|
|
679
679
|
|
|
680
|
-
export function formatExpandHint(lineCount: number): string {
|
|
681
|
-
return ` (${lineCount} more line${lineCount === 1 ? "" : "s"} / click)`;
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
function expandHint(theme: any, lineCount: number, hovered = false): string {
|
|
685
|
-
// Keep interaction guidance neutral; it should not inherit success/error
|
|
686
|
-
// coloring from the tool result surrounding it.
|
|
687
|
-
return theme.fg(hovered ? "text" : "muted", formatExpandHint(lineCount));
|
|
688
|
-
}
|
|
689
680
|
const toolViewMarker = (id: number, section: ToolIoSection) =>
|
|
690
681
|
`_cc:v${id}:${section === "input" ? "i" : "o"}`;
|
|
691
682
|
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
// fullscreen 模式探测:官方 fullscreen TUI(TuiAltScreen)由官方独占布局,
|
|
2
|
-
// 插件渲染层应让位。检测方式是瞬时 setWidget 拿 tui 实例检查 mode。
|
|
3
|
-
const PROBE_KEY = "cc-fullscreen-probe";
|
|
4
|
-
|
|
5
1
|
/**
|
|
6
2
|
* 官方 0.84+ 的 tui 引用是惰性 Proxy(createInteractiveTuiReference):
|
|
7
3
|
* 函数属性每次 get 都返回新包装,执行时才解析到当前实现。
|
|
@@ -13,26 +9,3 @@ export function isLazyProxyTui(tui: any): boolean {
|
|
|
13
9
|
const probe = tui.requestRender;
|
|
14
10
|
return typeof probe === "function" && probe !== tui.requestRender;
|
|
15
11
|
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* 探测当前会话的 TUI 是否运行在官方 fullscreen 模式。
|
|
19
|
-
* 无 setWidget 的环境(测试 mock)视为 regular。
|
|
20
|
-
*/
|
|
21
|
-
export function isFullscreenUi(ctx: { ui?: any }): boolean {
|
|
22
|
-
if (typeof ctx?.ui?.setWidget !== "function") return false;
|
|
23
|
-
let fullscreen = false;
|
|
24
|
-
try {
|
|
25
|
-
ctx.ui.setWidget(PROBE_KEY, (tui: any) => {
|
|
26
|
-
fullscreen = tui?.mode === "fullscreen";
|
|
27
|
-
return { render: () => 0, invalidate() {} };
|
|
28
|
-
});
|
|
29
|
-
} catch {
|
|
30
|
-
// 探测失败按 regular 处理,避免误伤
|
|
31
|
-
}
|
|
32
|
-
try {
|
|
33
|
-
ctx.ui.setWidget(PROBE_KEY, undefined);
|
|
34
|
-
} catch {
|
|
35
|
-
// 忽略
|
|
36
|
-
}
|
|
37
|
-
return fullscreen;
|
|
38
|
-
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herbertgao/pi-cc-extensions",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.53",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "A Pi productivity suite with Claude Code-style UI, context inspection, and agent/session references",
|
|
6
6
|
"type": "module",
|
|
@@ -69,8 +69,8 @@
|
|
|
69
69
|
},
|
|
70
70
|
"x-upstream": {
|
|
71
71
|
"package": "pi-cc-extensions",
|
|
72
|
-
"version": "0.8.
|
|
72
|
+
"version": "0.8.54",
|
|
73
73
|
"repository": "https://github.com/minuque/pi-cc-extensions",
|
|
74
|
-
"commit": "
|
|
74
|
+
"commit": "8372ecaff7f079ab4452db47328c3238620a4885"
|
|
75
75
|
}
|
|
76
76
|
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.15.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#27](https://github.com/HerbertGao/pi-extensions/pull/27) [`32bb76c`](https://github.com/HerbertGao/pi-extensions/commit/32bb76c117971de27db9c2b521d19df3ba9ea322) Thanks [@HerbertGao](https://github.com/HerbertGao)! - Keep worktree-isolated agents inside their copy, preserve real Agent tool startup errors, and render unknown or failed Agent results without misleading completion status.
|
|
8
|
+
|
|
3
9
|
## 0.15.2
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herbertgao/pi-subagents",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.3",
|
|
4
4
|
"description": "Claude Code-style autonomous subagents for Pi, with HerbertGao-maintained UI extensions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -66,6 +66,6 @@
|
|
|
66
66
|
"package": "@tintinweb/pi-subagents",
|
|
67
67
|
"version": "0.15.0",
|
|
68
68
|
"repository": "https://github.com/tintinweb/pi-subagents",
|
|
69
|
-
"commit": "
|
|
69
|
+
"commit": "c83dd82"
|
|
70
70
|
}
|
|
71
71
|
}
|
|
@@ -321,6 +321,7 @@ export class AgentManager {
|
|
|
321
321
|
// stay undefined otherwise so plain worktree runs keep resolving config
|
|
322
322
|
// (incl. relative extension paths and memory) inside the worktree copy.
|
|
323
323
|
cwd: worktreeCwd ?? customCwd,
|
|
324
|
+
worktreeBase: worktreeCwd ? baseCwd : undefined,
|
|
324
325
|
configCwd:
|
|
325
326
|
options.configCwd ?? (customCwd !== undefined ? ctx.cwd : undefined),
|
|
326
327
|
signal: record.abortController!.signal,
|
|
@@ -414,6 +414,8 @@ export interface RunOptions {
|
|
|
414
414
|
thinkingLevel?: ThinkingLevel
|
|
415
415
|
/** Override working directory (e.g. for worktree isolation). */
|
|
416
416
|
cwd?: string
|
|
417
|
+
/** Original checkout path when cwd is an isolated worktree copy. */
|
|
418
|
+
worktreeBase?: string
|
|
417
419
|
/**
|
|
418
420
|
* Where .pi config is discovered (project extensions, skills, pi settings,
|
|
419
421
|
* agent memory). Default: same as the working directory. The manager sets
|
|
@@ -602,7 +604,7 @@ export async function runAgent(
|
|
|
602
604
|
const parentSystemPrompt = ctx.getSystemPrompt()
|
|
603
605
|
|
|
604
606
|
// Build prompt extras (memory, skill preloading)
|
|
605
|
-
const extras: PromptExtras = {}
|
|
607
|
+
const extras: PromptExtras = { worktreeBase: options.worktreeBase }
|
|
606
608
|
|
|
607
609
|
// Resolve extensions/skills: isolated overrides to false
|
|
608
610
|
const extensions = options.isolated ? false : config.extensions
|
|
@@ -1241,12 +1241,12 @@ Terse command-style prompts produce shallow, generic work.
|
|
|
1241
1241
|
)
|
|
1242
1242
|
},
|
|
1243
1243
|
|
|
1244
|
-
renderResult(result, { expanded, isPartial }, theme) {
|
|
1244
|
+
renderResult(result, { expanded, isPartial }, theme, renderContext) {
|
|
1245
|
+
const resultText =
|
|
1246
|
+
result.content[0]?.type === "text" ? result.content[0].text : ""
|
|
1245
1247
|
const details = result.details as AgentDetails | undefined
|
|
1246
|
-
if (!details) {
|
|
1247
|
-
|
|
1248
|
-
result.content[0]?.type === "text" ? result.content[0].text : ""
|
|
1249
|
-
return new Text(text, 0, 0)
|
|
1248
|
+
if (renderContext?.isError || !details?.status) {
|
|
1249
|
+
return new Text(resultText, 0, 0)
|
|
1250
1250
|
}
|
|
1251
1251
|
|
|
1252
1252
|
// Helper: build "haiku · thinking: high · ↻5≤30 · 3 tool uses · 33.8k tokens" stats string
|
|
@@ -1301,8 +1301,6 @@ Terse command-style prompts produce shallow, generic work.
|
|
|
1301
1301
|
line += " " + theme.fg("dim", "·") + " " + theme.fg("dim", duration)
|
|
1302
1302
|
|
|
1303
1303
|
if (expanded) {
|
|
1304
|
-
const resultText =
|
|
1305
|
-
result.content[0]?.type === "text" ? result.content[0].text : ""
|
|
1306
1304
|
if (resultText) {
|
|
1307
1305
|
const lines = resultText.split("\n").slice(0, 50)
|
|
1308
1306
|
for (const l of lines) {
|
|
@@ -1332,6 +1330,10 @@ Terse command-style prompts produce shallow, generic work.
|
|
|
1332
1330
|
return new Text(line, 0, 0)
|
|
1333
1331
|
}
|
|
1334
1332
|
|
|
1333
|
+
if (details.status !== "error" && details.status !== "aborted") {
|
|
1334
|
+
return new Text(resultText, 0, 0)
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1335
1337
|
// ---- Error / Aborted (hard max_turns) ----
|
|
1336
1338
|
const s = stats(details)
|
|
1337
1339
|
let line = theme.fg("error", "✗") + (s ? " " + s : "")
|
|
@@ -1598,23 +1600,22 @@ Terse command-style prompts produce shallow, generic work.
|
|
|
1598
1600
|
}
|
|
1599
1601
|
}
|
|
1600
1602
|
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
}
|
|
1603
|
+
// A throw here means the agent never started. Let it out: Pi marks a
|
|
1604
|
+
// tool call failed only when execute throws, while a returned message
|
|
1605
|
+
// reads to the model as a subagent that ran and reported this.
|
|
1606
|
+
id = manager.spawn(pi, ctx, subagentType, params.prompt, {
|
|
1607
|
+
description: params.description,
|
|
1608
|
+
model,
|
|
1609
|
+
maxTurns: effectiveMaxTurns,
|
|
1610
|
+
isolated,
|
|
1611
|
+
inheritContext,
|
|
1612
|
+
thinkingLevel: thinking,
|
|
1613
|
+
isBackground: true,
|
|
1614
|
+
isolation,
|
|
1615
|
+
invocation: agentInvocation,
|
|
1616
|
+
rootSessionId: ctx.sessionManager.getSessionId(),
|
|
1617
|
+
...bgCallbacks,
|
|
1618
|
+
})
|
|
1618
1619
|
|
|
1619
1620
|
// Set output file + join mode synchronously after spawn, before the
|
|
1620
1621
|
// event loop yields — onSessionCreated is async so this is safe.
|
|
@@ -1774,18 +1775,15 @@ Terse command-style prompts produce shallow, generic work.
|
|
|
1774
1775
|
},
|
|
1775
1776
|
)
|
|
1776
1777
|
record = fgResult.record
|
|
1777
|
-
}
|
|
1778
|
+
} finally {
|
|
1779
|
+
// A startup throw propagates as a failed tool call without leaving
|
|
1780
|
+
// the spinner running or a finished agent in the widget.
|
|
1778
1781
|
clearInterval(spinnerInterval)
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
// Clean up foreground agent from widget
|
|
1785
|
-
if (fgId) {
|
|
1786
|
-
agentActivity.delete(fgId)
|
|
1787
|
-
widget.markFinished(fgId)
|
|
1788
|
-
fleet.onAgentFinished(fgId)
|
|
1782
|
+
if (fgId) {
|
|
1783
|
+
agentActivity.delete(fgId)
|
|
1784
|
+
widget.markFinished(fgId)
|
|
1785
|
+
fleet.onAgentFinished(fgId)
|
|
1786
|
+
}
|
|
1789
1787
|
}
|
|
1790
1788
|
|
|
1791
1789
|
// Get final token count
|
|
@@ -399,47 +399,38 @@ export function createNestedSubagentTools(
|
|
|
399
399
|
// one earlier would silently give a grandchild the wrong worktree base, the
|
|
400
400
|
// wrong conversation under inherit_context, and the wrong inherited model.
|
|
401
401
|
//
|
|
402
|
-
//
|
|
403
|
-
//
|
|
404
|
-
//
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
const id = context.manager.spawn(
|
|
408
|
-
context.pi,
|
|
409
|
-
ctx,
|
|
410
|
-
resolvedType,
|
|
411
|
-
params.prompt,
|
|
412
|
-
{
|
|
413
|
-
...options,
|
|
414
|
-
isBackground: true,
|
|
415
|
-
},
|
|
416
|
-
)
|
|
417
|
-
// Synchronous, before the event loop yields — onSessionCreated fires
|
|
418
|
-
// asynchronously inside runAgent, so the file is attached in time.
|
|
419
|
-
attachTranscript(id)
|
|
420
|
-
return textResult(
|
|
421
|
-
`Nested agent started in background. Agent ID: ${id}`,
|
|
422
|
-
)
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
const { record } = await context.manager.spawnAndWait(
|
|
402
|
+
// Startup throws mean no child ran. Let them propagate so Pi marks the
|
|
403
|
+
// nested Agent tool call failed instead of presenting the message as a
|
|
404
|
+
// successful child result.
|
|
405
|
+
if (invocation.runInBackground) {
|
|
406
|
+
const id = context.manager.spawn(
|
|
426
407
|
context.pi,
|
|
427
408
|
ctx,
|
|
428
409
|
resolvedType,
|
|
429
410
|
params.prompt,
|
|
430
|
-
{
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
formatRecord(record, "inline"),
|
|
435
|
-
record.status === "error",
|
|
436
|
-
)
|
|
437
|
-
} catch (err) {
|
|
438
|
-
return textResult(
|
|
439
|
-
err instanceof Error ? err.message : String(err),
|
|
440
|
-
true,
|
|
411
|
+
{
|
|
412
|
+
...options,
|
|
413
|
+
isBackground: true,
|
|
414
|
+
},
|
|
441
415
|
)
|
|
416
|
+
// Synchronous, before the event loop yields — onSessionCreated fires
|
|
417
|
+
// asynchronously inside runAgent, so the file is attached in time.
|
|
418
|
+
attachTranscript(id)
|
|
419
|
+
return textResult(`Nested agent started in background. Agent ID: ${id}`)
|
|
442
420
|
}
|
|
421
|
+
|
|
422
|
+
const { record } = await context.manager.spawnAndWait(
|
|
423
|
+
context.pi,
|
|
424
|
+
ctx,
|
|
425
|
+
resolvedType,
|
|
426
|
+
params.prompt,
|
|
427
|
+
{ ...options, signal },
|
|
428
|
+
attachTranscript,
|
|
429
|
+
)
|
|
430
|
+
return textResult(
|
|
431
|
+
formatRecord(record, "inline"),
|
|
432
|
+
record.status === "error",
|
|
433
|
+
)
|
|
443
434
|
},
|
|
444
435
|
})
|
|
445
436
|
|
|
@@ -10,6 +10,8 @@ export interface PromptExtras {
|
|
|
10
10
|
memoryBlock?: string
|
|
11
11
|
/** Preloaded skill contents to inject. */
|
|
12
12
|
skillBlocks?: { name: string; content: string }[]
|
|
13
|
+
/** Original checkout path when cwd is an isolated worktree copy. */
|
|
14
|
+
worktreeBase?: string
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
/**
|
|
@@ -55,6 +57,12 @@ Platform: ${env.platform}`
|
|
|
55
57
|
}
|
|
56
58
|
const extrasSuffix =
|
|
57
59
|
extraSections.length > 0 ? "\n\n" + extraSections.join("\n") : ""
|
|
60
|
+
const worktreeSection = extras?.worktreeBase
|
|
61
|
+
? `\n\n<worktree_isolation>
|
|
62
|
+
Your working directory is an isolated git worktree copy of ${extras.worktreeBase}.
|
|
63
|
+
Work only inside it — never in ${extras.worktreeBase}, even if other instructions name that path as your working directory.
|
|
64
|
+
</worktree_isolation>`
|
|
65
|
+
: ""
|
|
58
66
|
|
|
59
67
|
if (config.promptMode === "append") {
|
|
60
68
|
const identity = parentSystemPrompt || genericBase
|
|
@@ -88,6 +96,7 @@ You are operating as a sub-agent invoked to handle a specific task.
|
|
|
88
96
|
"\n\n" +
|
|
89
97
|
activeAgentTag +
|
|
90
98
|
envBlock +
|
|
99
|
+
worktreeSection +
|
|
91
100
|
customSection +
|
|
92
101
|
extrasSuffix
|
|
93
102
|
)
|
|
@@ -100,7 +109,12 @@ You have been invoked to handle a specific task autonomously.
|
|
|
100
109
|
${envBlock}`
|
|
101
110
|
|
|
102
111
|
return (
|
|
103
|
-
activeAgentTag +
|
|
112
|
+
activeAgentTag +
|
|
113
|
+
replaceHeader +
|
|
114
|
+
worktreeSection +
|
|
115
|
+
"\n\n" +
|
|
116
|
+
config.systemPrompt +
|
|
117
|
+
extrasSuffix
|
|
104
118
|
)
|
|
105
119
|
}
|
|
106
120
|
|
|
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.23.0] - 2026-08-11
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Added interactive callback URL pasting to `/mcp-auth` for OAuth flows running on remote or headless machines. Thanks @trevorleibert-mixpanel for PR #330.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- Stopped load-time MCP initialization from printing a TUI startup error when Pi action methods are not bound yet. Thanks @21307369 for issue #327.
|
|
17
|
+
- Kept interactive OAuth authorization URLs clickable as a single terminal hyperlink. Thanks @rfccg for PR #329.
|
|
18
|
+
|
|
19
|
+
## [2.22.0] - 2026-08-11
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
- Added the `pi-mcp-adapter/oauth` subpath for URL-bound OAuth token reuse by cooperating Pi extensions. Thanks @ThePhoenixCoding for issue #323.
|
|
23
|
+
- Added `oauth.logoUri` for OAuth Dynamic Client Registration, with validation that requires an absolute HTTP(S) URL. Thanks @grinich for PR #321.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- Materialized binary MCP resources as private temporary files before model-facing output, with bounded per-session cleanup. Thanks @zenworr and @shaworr for PR #324.
|
|
27
|
+
- Named OAuth callback pages and dynamic client registrations after rebranded Pi hosts, while preserving stock Pi defaults and avoiding guessed client homepages. Thanks @grinich for PR #320.
|
|
28
|
+
|
|
10
29
|
## [2.21.2] - 2026-08-09
|
|
11
30
|
|
|
12
31
|
### Fixed
|
|
@@ -153,6 +153,17 @@ A supplied `config` is a complete, isolated snapshot. It is not merged with file
|
|
|
153
153
|
|
|
154
154
|
With `configPath` and no `config`, the adapter keeps normal file merge behavior, and that path takes precedence over argv and `--mcp-config`. The default export keeps the normal file-based behavior. OAuth credentials are stored in the operating system credential store and keyed by the configured server name; URL binding prevents credentials from being accepted for a different server URL. `settings.oauthDir` and `MCP_OAUTH_DIR` are used only as legacy plaintext import locations for older `tokens.json` files, not as credential namespaces. CSRF state and PKCE verifiers are flow-local, so concurrent authorization flows do not share transient secrets.
|
|
155
155
|
|
|
156
|
+
Cooperating Pi extensions can use `pi-mcp-adapter/oauth` to reuse URL-bound OAuth tokens without deep-importing private files:
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import { getMcpOAuthTokensForUrl, updateMcpOAuthTokensForUrl } from "pi-mcp-adapter/oauth";
|
|
160
|
+
|
|
161
|
+
const tokens = await getMcpOAuthTokensForUrl("jira", "https://jira.example.com/mcp");
|
|
162
|
+
updateMcpOAuthTokensForUrl("jira", "https://jira.example.com/mcp", { accessToken: "..." });
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The public subpath exposes only token read/update helpers plus a status helper. The async read path uses the adapter's refresh logic before it returns tokens. The helpers keep secure-store storage, URL binding, refresh persistence, chunk handling, legacy import, and fail-closed credential-store errors. They do not expose client registration secrets, PKCE verifiers, or OAuth state.
|
|
166
|
+
|
|
156
167
|
### Runtime status snapshots
|
|
157
168
|
|
|
158
169
|
Extensions can subscribe to the adapter's versioned shared event-bus channel instead of parsing `/mcp` or `mcp({})` output:
|
|
@@ -203,7 +214,8 @@ In the configuration examples below, `30000` is illustrative only. If `requestTi
|
|
|
203
214
|
| `oauth.scope` | Requested OAuth scopes |
|
|
204
215
|
| `oauth.redirectUri` | Exact localhost redirect URI for browser OAuth, including port and path, for providers that pre-register callbacks |
|
|
205
216
|
| `oauth.clientName` | Client display name advertised during Dynamic Client Registration fallback |
|
|
206
|
-
| `oauth.clientUri` | Client homepage URI advertised during Dynamic Client Registration fallback |
|
|
217
|
+
| `oauth.clientUri` | Client homepage URI advertised during Dynamic Client Registration fallback. Defaults to `piConfig.clientUri` from the host's manifest when set, and is omitted rather than guessed under a rebranded host |
|
|
218
|
+
| `oauth.logoUri` | Client logo URL advertised during Dynamic Client Registration fallback (RFC 7591 `logo_uri`). Must be an absolute `http(s)` URL — consent screens fetch it server-side, so local paths render nothing. Omitted from the registration request when unset |
|
|
207
219
|
| `oauth.skipIssuerMetadataValidation` | `true` disables the OAuth authorization-server metadata issuer check for this server. This weakens OAuth mix-up protection and should only be used for known-misconfigured internal servers while their metadata is being fixed. |
|
|
208
220
|
| `bearerToken` / `bearerTokenEnv` | Token or env var name; `bearerToken` supports `${VAR}` and `$env:VAR` interpolation. A leading `!` in `bearerToken` runs a command when the HTTP server connects; use `!!` for a literal leading `!`. |
|
|
209
221
|
| `lifecycle` | `"lazy"` (default), `"eager"`, `"keep-alive"`, or `"lazy-keep-alive"` |
|
|
@@ -253,7 +265,9 @@ The adapter owns only its client socket and closes that connection when the Pi r
|
|
|
253
265
|
|
|
254
266
|
### Remote/headless OAuth
|
|
255
267
|
|
|
256
|
-
If Pi is running on a remote server and
|
|
268
|
+
If Pi is running on a remote server, `/mcp-auth <server>` prints the authorization URL and opens a callback input. Open the URL in your local browser. After approval, the browser may fail to load the localhost callback page because localhost refers to your workstation; copy the full URL from its address bar and paste it into Pi. The input closes automatically instead when the browser can reach Pi's callback directly.
|
|
269
|
+
|
|
270
|
+
The same flow is available through the proxy tool for non-interactive clients. Persistent OAuth still requires an available OS credential store; on headless Linux that usually means an unlocked Secret Service/libsecret keyring. The adapter fails closed instead of falling back to plaintext credentials when the secure store is unavailable.
|
|
257
271
|
|
|
258
272
|
On Linux, if credential access fails because Pi inherited a revoked session keyring, the adapter uses a best-effort recovery path through `keyctl session - node <packaged helper>` so explicit re-authentication can write fresh credentials without killing a long-lived tmux server. This path requires `keyctl` and `node` on `PATH`; missing, locked, or otherwise unavailable credential stores still fail closed.
|
|
259
273
|
|
|
@@ -372,9 +386,10 @@ Oversized MCP tool/resource results are guarded by default so a single huge resp
|
|
|
372
386
|
|
|
373
387
|
- Inline text output is capped at **50 KiB / 2,000 lines** (matching Pi's built-in `bash` guard). Larger output is truncated to a head preview and the full text is saved to a temp file whose path is included in the result, so the agent can `read`/`grep` it.
|
|
374
388
|
- **Image content blocks pass through unchanged** — only text output is guarded. Images are delivered to the provider as native image content.
|
|
389
|
+
- Binary resource blobs up to **10 MiB** are decoded to private temp files and replaced with file references. Each session is limited to **100 MiB** and **10,000 files**. The files are removed at session teardown.
|
|
375
390
|
- In proxy mode, `details.mcpResult` is kept raw when its JSON is **≤ 16 KiB**; larger results are replaced with a compact summary (block counts, sizes, key previews) and the raw JSON is saved to a temp file. Direct tools keep their lean details and never carry `mcpResult`.
|
|
376
391
|
|
|
377
|
-
Tune the limits with the object form:
|
|
392
|
+
Tune the text and details limits with the object form:
|
|
378
393
|
|
|
379
394
|
```json
|
|
380
395
|
{
|
|
@@ -384,7 +399,7 @@ Tune the limits with the object form:
|
|
|
384
399
|
}
|
|
385
400
|
```
|
|
386
401
|
|
|
387
|
-
Set `"outputGuard": false` — or the env kill switch `MCP_OUTPUT_GUARD=0` — to disable
|
|
402
|
+
Set `"outputGuard": false` — or the env kill switch `MCP_OUTPUT_GUARD=0` — to disable text and details guarding. Binary resource materialization and its safety limits remain active. Output-guard spill files are created with mode `0600` under the system temp directory and are not cleaned up automatically; note that spilled MCP output may contain sensitive data.
|
|
388
403
|
|
|
389
404
|
### MCP Scripting
|
|
390
405
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
1
2
|
import { homedir } from "node:os";
|
|
2
3
|
import { join, resolve } from "node:path";
|
|
3
4
|
|
|
@@ -18,3 +19,42 @@ export function getAgentDir(): string {
|
|
|
18
19
|
export function getAgentPath(...segments: string[]): string {
|
|
19
20
|
return join(getAgentDir(), ...segments);
|
|
20
21
|
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* What the host calls itself.
|
|
25
|
+
*
|
|
26
|
+
* pi supports rebranding through `piConfig.name` in the package.json that its
|
|
27
|
+
* `getPackageDir()` resolves, and distributions built on pi (arc, tau, …) point
|
|
28
|
+
* `PI_PACKAGE_DIR` at their own manifest. Read that manifest directly rather
|
|
29
|
+
* than importing pi: this package deliberately depends on pi-ai and pi-tui
|
|
30
|
+
* only, and `getAgentDir()` above reads its env var the same self-contained way.
|
|
31
|
+
*
|
|
32
|
+
* Falls back to "pi", which is what pi's own APP_NAME resolves to.
|
|
33
|
+
*/
|
|
34
|
+
function readPiConfig(): { name?: unknown; clientUri?: unknown } | undefined {
|
|
35
|
+
const dir = process.env.PI_PACKAGE_DIR?.trim()
|
|
36
|
+
if (!dir) return undefined
|
|
37
|
+
try {
|
|
38
|
+
const manifest = JSON.parse(readFileSync(join(resolve(dir), "package.json"), "utf8")) as {
|
|
39
|
+
piConfig?: { name?: unknown; clientUri?: unknown }
|
|
40
|
+
}
|
|
41
|
+
return manifest.piConfig
|
|
42
|
+
} catch {
|
|
43
|
+
return undefined
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function getAppName(): string {
|
|
48
|
+
const name = readPiConfig()?.name
|
|
49
|
+
return typeof name === "string" && name.trim() ? name.trim() : "pi"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Home page the host declares for itself, via `piConfig.clientUri` in the same
|
|
54
|
+
* manifest that carries `piConfig.name`. Only the distribution knows its own
|
|
55
|
+
* URL, so this is the one place it can come from without guessing.
|
|
56
|
+
*/
|
|
57
|
+
export function getAppClientUri(): string | undefined {
|
|
58
|
+
const uri = readPiConfig()?.clientUri
|
|
59
|
+
return typeof uri === "string" && uri.trim() ? uri.trim() : undefined
|
|
60
|
+
}
|
|
@@ -25,6 +25,10 @@ import { loadOnboardingState, markSetupCompleted as persistSetupCompleted, markS
|
|
|
25
25
|
import { openPath, resolveServerUrl, sanitizeTerminalText } from "./utils.ts";
|
|
26
26
|
import { isAbortError } from "./runtime-owner.ts";
|
|
27
27
|
|
|
28
|
+
function terminalHyperlink(label: string, url: string): string {
|
|
29
|
+
return `\u001B]8;;${sanitizeTerminalText(url)}\u001B\\${sanitizeTerminalText(label)}\u001B]8;;\u001B\\`;
|
|
30
|
+
}
|
|
31
|
+
|
|
28
32
|
export async function showStatus(state: McpExtensionState, ctx: ExtensionContext): Promise<void> {
|
|
29
33
|
if (!ctx.hasUI) return;
|
|
30
34
|
|
|
@@ -273,11 +277,17 @@ export async function authenticateServer(
|
|
|
273
277
|
...(authStorageOptions.baseDir ? { authStorageOptions } : {}),
|
|
274
278
|
onAuthorizationUrl: (authorizationUrl) => {
|
|
275
279
|
ui.notify(
|
|
276
|
-
`Open this URL to authenticate ${serverName}:\n\n${authorizationUrl}\n\n` +
|
|
277
|
-
"After approving,
|
|
280
|
+
`Open this URL to authenticate ${serverName}:\n\n${terminalHyperlink(authorizationUrl, authorizationUrl)}\n\n` +
|
|
281
|
+
"After approving, Pi will complete automatically if the browser can reach its localhost callback. " +
|
|
282
|
+
"On a remote machine, copy the full localhost URL from the browser address bar and paste it into Pi.",
|
|
278
283
|
"info"
|
|
279
284
|
);
|
|
280
285
|
},
|
|
286
|
+
onAuthorizationInput: (_authorizationUrl, inputSignal) => ui.input(
|
|
287
|
+
`Complete ${serverName} OAuth`,
|
|
288
|
+
"Paste the full callback URL, or wait for automatic completion",
|
|
289
|
+
{ signal: inputSignal },
|
|
290
|
+
),
|
|
281
291
|
...(signal ? { signal } : {}),
|
|
282
292
|
...(runtime ? { runtime } : {}),
|
|
283
293
|
});
|
|
@@ -8,7 +8,7 @@ import { abortable, throwIfAborted } from "./abort.ts";
|
|
|
8
8
|
import { isServerCacheValid, parseDirectToolSelectors } from "./metadata-cache.ts";
|
|
9
9
|
export { getMissingConfiguredDirectToolServers } from "./metadata-cache.ts";
|
|
10
10
|
import { formatSchema } from "./tool-metadata.ts";
|
|
11
|
-
import { resolveMcpResultContent, transformMcpContent } from "./tool-registrar.ts";
|
|
11
|
+
import { resolveMcpResultContent, transformMcpContent, transformMcpResourceContents } from "./tool-registrar.ts";
|
|
12
12
|
import { guardMcpOutput, guardedMcpDetails, resolveMcpOutputGuardOptions } from "./mcp-output-guard.ts";
|
|
13
13
|
import { maybeStartUiSession, summarizeUiSessionResult, type UiSessionRuntime } from "./ui-session.ts";
|
|
14
14
|
import { formatToolName, isServerDisabled, isToolAllowed, resolveToolPrefix } from "./types.ts";
|
|
@@ -20,6 +20,7 @@ import { combineAbortSignals, isAbortError } from "./runtime-owner.ts";
|
|
|
20
20
|
import { ensureToolCallApproved } from "./tool-approval.ts";
|
|
21
21
|
|
|
22
22
|
type ClientCallToolResult = Awaited<ReturnType<Client["callTool"]>>;
|
|
23
|
+
type ClientReadResourceResult = Awaited<ReturnType<Client["readResource"]>>;
|
|
23
24
|
|
|
24
25
|
const BUILTIN_NAMES = new Set(["read", "bash", "edit", "write", "grep", "find", "ls", "mcp"]);
|
|
25
26
|
const INSTRUCTIONS_SNIPPET_LENGTH = 150;
|
|
@@ -435,7 +436,7 @@ export function createDirectToolExecutor(
|
|
|
435
436
|
state.manager.incrementInFlight(spec.serverName);
|
|
436
437
|
|
|
437
438
|
if (spec.resourceUri) {
|
|
438
|
-
const result = await withSessionRecovery(
|
|
439
|
+
const result = await withSessionRecovery<ClientReadResourceResult>(
|
|
439
440
|
{
|
|
440
441
|
manager: state.manager,
|
|
441
442
|
config: state.config,
|
|
@@ -445,10 +446,7 @@ export function createDirectToolExecutor(
|
|
|
445
446
|
spec.serverName,
|
|
446
447
|
(conn) => conn.client.readResource({ uri: spec.resourceUri! }, requestOptions),
|
|
447
448
|
);
|
|
448
|
-
const content = (result.contents ?? [])
|
|
449
|
-
type: "text" as const,
|
|
450
|
-
text: "text" in c ? c.text : ("blob" in c ? `[Binary data: ${(c as { mimeType?: string }).mimeType ?? "unknown"}]` : JSON.stringify(c)),
|
|
451
|
-
}));
|
|
449
|
+
const content = transformMcpResourceContents(result.contents ?? [], state.owner?.signal);
|
|
452
450
|
const guarded = await guardMcpOutput(content.length > 0 ? content : [{ type: "text" as const, text: "(empty resource)" }], outputGuardOptions);
|
|
453
451
|
return {
|
|
454
452
|
content: guarded.content,
|
|
@@ -487,7 +485,7 @@ export function createDirectToolExecutor(
|
|
|
487
485
|
|
|
488
486
|
if (result.isError) {
|
|
489
487
|
const mcpContent = (result.content ?? []) as McpContent[];
|
|
490
|
-
const content = transformMcpContent(mcpContent);
|
|
488
|
+
const content = transformMcpContent(mcpContent, state.owner?.signal);
|
|
491
489
|
const outputContent = content.length > 0 ? content : [{ type: "text" as const, text: "(empty result)" }];
|
|
492
490
|
const schemaText = spec.inputSchema ? `\n\nExpected parameters:\n${formatSchema(spec.inputSchema)}` : "";
|
|
493
491
|
const guarded = await guardMcpOutput(outputContent, { ...outputGuardOptions, prefix: "Error: ", suffix: schemaText, emptyTextFallback: "Tool execution failed" });
|
|
@@ -497,7 +495,7 @@ export function createDirectToolExecutor(
|
|
|
497
495
|
};
|
|
498
496
|
}
|
|
499
497
|
|
|
500
|
-
const content = resolveMcpResultContent(result as Record<string, unknown
|
|
498
|
+
const content = resolveMcpResultContent(result as Record<string, unknown>, state.owner?.signal);
|
|
501
499
|
const outputContent = content.length > 0 ? content : [{ type: "text" as const, text: "(empty result)" }];
|
|
502
500
|
if (hasUi) {
|
|
503
501
|
const uiSummary = summarizeUiSessionResult(uiSession);
|