@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
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
import qrTerminal from "qrcode-terminal";
|
|
3
|
+
/** Default ephemeral-token lifetime (also the QR rotation period). */
|
|
4
|
+
export const TOKEN_TTL_MS = 60_000;
|
|
5
|
+
/** Bounds for a caller-supplied pairing TTL (e.g. `/remote-pi pair --ttl <s>`). */
|
|
6
|
+
export const PAIR_TTL_MIN_MS = 10_000;
|
|
7
|
+
export const PAIR_TTL_MAX_MS = 600_000;
|
|
8
|
+
/** Clamp an arbitrary ttl (ms) into the safe pairing range; NaN → default. */
|
|
9
|
+
export function clampPairTtlMs(ttlMs) {
|
|
10
|
+
if (!Number.isFinite(ttlMs))
|
|
11
|
+
return TOKEN_TTL_MS;
|
|
12
|
+
return Math.min(PAIR_TTL_MAX_MS, Math.max(PAIR_TTL_MIN_MS, Math.floor(ttlMs)));
|
|
13
|
+
}
|
|
14
|
+
/** Encapsulates the single active QR token. One instance per Pi process. */
|
|
15
|
+
export class QRSession {
|
|
16
|
+
active = null;
|
|
17
|
+
/** Generates a fresh 16-byte random token encoded as base64url. */
|
|
18
|
+
generateToken() {
|
|
19
|
+
return randomBytes(16).toString("base64url");
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Issues a new active token, invalidating any previous one.
|
|
23
|
+
* Returns the token and its expiry timestamp.
|
|
24
|
+
*/
|
|
25
|
+
issueToken(ttlMs = TOKEN_TTL_MS) {
|
|
26
|
+
const token = this.generateToken();
|
|
27
|
+
const expiresAt = Date.now() + ttlMs;
|
|
28
|
+
this.active = { token, expiresAt, consumed: false };
|
|
29
|
+
return { token, expiresAt };
|
|
30
|
+
}
|
|
31
|
+
/** Validates and atomically consumes a token. */
|
|
32
|
+
consumeToken(token) {
|
|
33
|
+
if (!this.active || this.active.token !== token)
|
|
34
|
+
return "unknown";
|
|
35
|
+
if (this.active.consumed)
|
|
36
|
+
return "consumed";
|
|
37
|
+
if (Date.now() > this.active.expiresAt)
|
|
38
|
+
return "expired";
|
|
39
|
+
this.active.consumed = true;
|
|
40
|
+
return "ok";
|
|
41
|
+
}
|
|
42
|
+
clear() {
|
|
43
|
+
this.active = null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export const qrSession = new QRSession();
|
|
47
|
+
// ── URI + display ─────────────────────────────────────────────────────────────
|
|
48
|
+
export function buildQRUri(token, longtermEdPk, // Ed25519 — only peer ID after E2E rollback
|
|
49
|
+
sessionName,
|
|
50
|
+
/**
|
|
51
|
+
* Pi room id (12 chars, base64url) derived from cwd. App routes pair_request
|
|
52
|
+
* to this room so the relay delivers it to the right Pi instance among N
|
|
53
|
+
* paralelos com mesmo epk. Adicionado no fix do plano 17 (sem `rm` o app
|
|
54
|
+
* cai em room=main e o relay drops com "dest not found").
|
|
55
|
+
*/
|
|
56
|
+
roomId) {
|
|
57
|
+
// `r` (relay URL) removed in plano 14 — relay now comes from app config /
|
|
58
|
+
// pi-ext env|config|default chain. Keeps QR ~30-50 chars shorter.
|
|
59
|
+
// `n` (session name) is kept: the app uses it for the pre-pair_ok preview
|
|
60
|
+
// screen (showing the agent name immediately after scan, before the
|
|
61
|
+
// handshake completes). Dropping it briefly shrank the QR but the QR
|
|
62
|
+
// size no longer matters now that the copy-paste URI is rendered via
|
|
63
|
+
// `pi.sendMessage` into the chat panel (not the QR overflow area).
|
|
64
|
+
const epkB64 = Buffer.from(longtermEdPk).toString("base64url");
|
|
65
|
+
const params = new URLSearchParams({
|
|
66
|
+
t: token,
|
|
67
|
+
epk: epkB64,
|
|
68
|
+
n: sessionName.slice(0, 80),
|
|
69
|
+
});
|
|
70
|
+
if (roomId)
|
|
71
|
+
params.set("rm", roomId);
|
|
72
|
+
return `remotepi://pair?${params.toString()}`;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Returns the QR ASCII as a string (pure Unicode block characters —
|
|
76
|
+
* `█ ▀ ▄` and space, NO ANSI escapes — qrcode-terminal v0.12 small mode
|
|
77
|
+
* is escape-free, see lib/main.js:48-53).
|
|
78
|
+
*
|
|
79
|
+
* The caller can either write the string to stderr (legacy path, breaks
|
|
80
|
+
* the Pi TUI layout) or inject it via `pi.sendMessage` (renders inside
|
|
81
|
+
* the chat panel as proper content).
|
|
82
|
+
*/
|
|
83
|
+
export function renderQRAscii(uri) {
|
|
84
|
+
let out = "";
|
|
85
|
+
qrTerminal.generate(uri, { small: true }, (qrcode) => { out = qrcode; });
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Legacy stderr writer — kept for the standalone CLI mode
|
|
90
|
+
* (`pi-extension/src/index.ts` bottom block, which runs outside a Pi TUI).
|
|
91
|
+
* Inside the Pi TUI extension flow, use `renderQRAscii` + `pi.sendMessage`
|
|
92
|
+
* instead — direct stderr writes from inside an extension break the TUI's
|
|
93
|
+
* scrollable output widget (the QR overflows the panel and other writes
|
|
94
|
+
* collide with the prompt area).
|
|
95
|
+
*/
|
|
96
|
+
export function displayQR(uri) {
|
|
97
|
+
const qrcode = renderQRAscii(uri);
|
|
98
|
+
process.stderr.write(`\n📱 Scan to pair:\n\n${qrcode}\n`);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Starts a rotating QR session: generates a new QR every 60s, printing it
|
|
102
|
+
* to stdout. Returns a `stop()` function that cancels the rotation and clears
|
|
103
|
+
* the active token.
|
|
104
|
+
*/
|
|
105
|
+
export function startQRRotation(longtermEdPk, sessionName, roomId) {
|
|
106
|
+
let timer = null;
|
|
107
|
+
let stopped = false;
|
|
108
|
+
const rotate = () => {
|
|
109
|
+
if (stopped)
|
|
110
|
+
return;
|
|
111
|
+
const { token, expiresAt } = qrSession.issueToken();
|
|
112
|
+
const uri = buildQRUri(token, longtermEdPk, sessionName, roomId);
|
|
113
|
+
displayQR(uri);
|
|
114
|
+
console.log(`⏱ Renews at ${new Date(expiresAt).toLocaleTimeString()} — waiting for scan…`);
|
|
115
|
+
timer = setTimeout(rotate, TOKEN_TTL_MS);
|
|
116
|
+
};
|
|
117
|
+
rotate();
|
|
118
|
+
return () => {
|
|
119
|
+
stopped = true;
|
|
120
|
+
if (timer !== null)
|
|
121
|
+
clearTimeout(timer);
|
|
122
|
+
qrSession.clear();
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=qr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qr.js","sourceRoot":"","sources":["../../src/pairing/qr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,UAAU,MAAM,iBAAiB,CAAC;AAEzC,sEAAsE;AACtE,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC;AACnC,mFAAmF;AACnF,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC;AACtC,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC;AAEvC,8EAA8E;AAC9E,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,YAAY,CAAC;IACjD,OAAO,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACjF,CAAC;AAQD,4EAA4E;AAC5E,MAAM,OAAO,SAAS;IACZ,MAAM,GAAuB,IAAI,CAAC;IAE1C,mEAAmE;IACnE,aAAa;QACX,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC/C,CAAC;IAED;;;OAGG;IACH,UAAU,CAAC,QAAgB,YAAY;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QACnC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QACrC,IAAI,CAAC,MAAM,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QACpD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IAC9B,CAAC;IAED,iDAAiD;IACjD,YAAY,CACV,KAAa;QAEb,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,KAAK;YAAE,OAAO,SAAS,CAAC;QAClE,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ;YAAE,OAAO,UAAU,CAAC;QAC5C,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS;YAAE,OAAO,SAAS,CAAC;QACzD,IAAI,CAAC,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC;QAC5B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IACrB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;AAEzC,iFAAiF;AAEjF,MAAM,UAAU,UAAU,CACxB,KAAa,EACb,YAAwB,EAAE,4CAA4C;AACtE,WAAmB;AACnB;;;;;GAKG;AACH,MAAe;IAEf,0EAA0E;IAC1E,kEAAkE;IAClE,0EAA0E;IAC1E,oEAAoE;IACpE,qEAAqE;IACrE,qEAAqE;IACrE,mEAAmE;IACnE,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QACjC,CAAC,EAAE,KAAK;QACR,GAAG,EAAE,MAAM;QACX,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;KAC5B,CAAC,CAAC;IACH,IAAI,MAAM;QAAE,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACrC,OAAO,mBAAmB,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;AAChD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,UAAU,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,GAAG,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,MAAM,IAAI,CAAC,CAAC;AAC5D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAC7B,YAAwB,EACxB,WAAmB,EACnB,MAAe;IAEf,IAAI,KAAK,GAAyC,IAAI,CAAC;IACvD,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,MAAM,MAAM,GAAG,GAAG,EAAE;QAClB,IAAI,OAAO;YAAE,OAAO;QACpB,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC;QACpD,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;QACjE,SAAS,CAAC,GAAG,CAAC,CAAC;QACf,OAAO,CAAC,GAAG,CACT,gBAAgB,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,kBAAkB,EAAE,sBAAsB,CAC/E,CAAC;QACF,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC3C,CAAC,CAAC;IAEF,MAAM,EAAE,CAAC;IAET,OAAO,GAAG,EAAE;QACV,OAAO,GAAG,IAAI,CAAC;QACf,IAAI,KAAK,KAAK,IAAI;YAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QACxC,SAAS,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { type Ed25519Keypair } from "./crypto.js";
|
|
2
|
+
/** Raised when the keyring is unreadable on a platform where it's a core OS
|
|
3
|
+
* service (macOS Keychain, Windows Credential Manager) AND no prior file
|
|
4
|
+
* identity exists. We refuse to generate a NEW identity here because that
|
|
5
|
+
* would break existing pairing — the caller surfaces this so the user can
|
|
6
|
+
* unlock the keychain and retry instead of silently re-pairing. */
|
|
7
|
+
export declare class KeyringUnavailableError extends Error {
|
|
8
|
+
constructor(cause: unknown);
|
|
9
|
+
}
|
|
10
|
+
/** Raised when no identity can be resolved (keyring unreadable, no identity
|
|
11
|
+
* file) BUT `peers.json` already lists paired devices. Minting a fresh key
|
|
12
|
+
* here would make SelfRevoke wipe those pairings — see issues #95 / #69. */
|
|
13
|
+
export declare class PairedIdentityMissingError extends Error {
|
|
14
|
+
constructor(pairedCount: number, cause: unknown);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Minimal backend interface for credential reads/writes. Swappable so
|
|
18
|
+
* tests can inject a controlled in-memory store without touching the OS
|
|
19
|
+
* keyring (which is shared with the developer's own credentials).
|
|
20
|
+
*
|
|
21
|
+
* Errors thrown by `read`/`write`/`delete` signal "backend unavailable on
|
|
22
|
+
* this platform" — callers fall back to the file store on first failure.
|
|
23
|
+
* Returning `undefined` from `read` means "no such entry" (a normal,
|
|
24
|
+
* non-error condition).
|
|
25
|
+
*/
|
|
26
|
+
export interface KeyStoreBackend {
|
|
27
|
+
read(service: string, account: string): Promise<string | undefined>;
|
|
28
|
+
write(service: string, account: string, value: string): Promise<void>;
|
|
29
|
+
delete(service: string, account: string): Promise<boolean>;
|
|
30
|
+
}
|
|
31
|
+
/** Test-only: force (or clear with `null`) a memoized binding-load failure, so
|
|
32
|
+
* the Bun/no-native-binding branch is reachable without a Bun host. */
|
|
33
|
+
export declare function _setNativeBindingErrorForTest(err: unknown): void;
|
|
34
|
+
/** Test-only: swap (or clear with `null`) the keyring backend. */
|
|
35
|
+
export declare function _setKeyStoreBackendForTest(backend: KeyStoreBackend | null): void;
|
|
36
|
+
/** Test-only: force `_keyringExpectedAvailable()` (so a darwin test host can
|
|
37
|
+
* exercise the Linux/headless branch and vice-versa). `null` restores the
|
|
38
|
+
* real platform check. */
|
|
39
|
+
export declare function _setKeyringExpectedForTest(value: boolean | null): void;
|
|
40
|
+
/** Test-only: shrink retry attempts/delay so the persistent-failure path is
|
|
41
|
+
* fast. `null`/omitted restores defaults. */
|
|
42
|
+
export declare function _setKeyringRetryForTest(attempts: number | null, delayMs?: number): void;
|
|
43
|
+
/**
|
|
44
|
+
* Returns the Pi-secret Ed25519 keypair, generating + persisting one on
|
|
45
|
+
* first call. Resolution order:
|
|
46
|
+
* 1. Existing file `~/.pi/remote/identity.json`, if present — it WINS over
|
|
47
|
+
* the keyring. A file identity is only ever written by the headless/
|
|
48
|
+
* degraded fallback (step 4) or an explicit `REMOTE_PI_ALLOW_FILE_IDENTITY`
|
|
49
|
+
* opt-in, so its mere presence means this machine established its identity
|
|
50
|
+
* as a file and the mobile device paired against THAT pubkey. If the
|
|
51
|
+
* platform keyring later becomes readable (D-Bus/libsecret installed, a
|
|
52
|
+
* desktop session, or a stale/other entry from another install), reading
|
|
53
|
+
* it first would mask the file identity — returning a DIFFERENT key, or
|
|
54
|
+
* (when the keyring is empty) minting a fresh one and persisting it —
|
|
55
|
+
* silently breaking the existing pairing. So when both exist, file wins.
|
|
56
|
+
* 2. New keyring service `dev.remotepi.pi` (read retried — a transiently
|
|
57
|
+
* locked Keychain throws; we don't treat that as "no key")
|
|
58
|
+
* 3. Old keyring service `dev.remotepi.mac` (migrate → step 2, delete old)
|
|
59
|
+
* 4. Generate a fresh keypair, BUT only when it's safe to: either both
|
|
60
|
+
* keyring reads succeeded and returned nothing (genuine first run), or
|
|
61
|
+
* the keyring is genuinely unavailable on a platform without a core one
|
|
62
|
+
* (headless Linux → a file identity is minted here). On macOS/Windows a
|
|
63
|
+
* persistent read failure with no file identity throws
|
|
64
|
+
* `KeyringUnavailableError` instead of minting a new key — generating
|
|
65
|
+
* there silently breaks existing pairing (the "lost pairing after idle"
|
|
66
|
+
* bug). `REMOTE_PI_ALLOW_FILE_IDENTITY=1` opts back into a file identity
|
|
67
|
+
* for headless macOS/Windows hosts.
|
|
68
|
+
*
|
|
69
|
+
* Idempotent: subsequent calls return the same identity. The migration
|
|
70
|
+
* runs at most once per machine (the old entry is deleted after copy).
|
|
71
|
+
*/
|
|
72
|
+
export declare function getOrCreateEd25519Keypair(): Promise<Ed25519Keypair>;
|
|
73
|
+
export interface PeerRecord {
|
|
74
|
+
name: string;
|
|
75
|
+
remote_epk: string;
|
|
76
|
+
paired_at: string;
|
|
77
|
+
}
|
|
78
|
+
export declare function listPeers(): Promise<PeerRecord[]>;
|
|
79
|
+
declare const _ownerStorageTokenBrand: unique symbol;
|
|
80
|
+
/** Opaque, process-local provenance for one canonical Owner storage slot. */
|
|
81
|
+
export type OwnerStorageToken = {
|
|
82
|
+
readonly [_ownerStorageTokenBrand]: true;
|
|
83
|
+
};
|
|
84
|
+
export interface OwnerStorageSnapshotRecord {
|
|
85
|
+
readonly rawOwnerPubkey: unknown;
|
|
86
|
+
readonly token: OwnerStorageToken;
|
|
87
|
+
}
|
|
88
|
+
export type ConditionalPeerRemoval = {
|
|
89
|
+
readonly outcome: "removed";
|
|
90
|
+
readonly nextToken: OwnerStorageToken;
|
|
91
|
+
} | {
|
|
92
|
+
readonly outcome: "stale" | "not_found" | "no_authority";
|
|
93
|
+
};
|
|
94
|
+
export declare function addPeer(record: PeerRecord): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Returns the set of distinct `remote_epk` values in peers.json.
|
|
97
|
+
*
|
|
98
|
+
* In the current pairing model (plan/23 + plan/24), each `remote_epk` is the
|
|
99
|
+
* Owner's Ed25519 pubkey — and we treat each as a distinct Owner the Pi has
|
|
100
|
+
* been paired with. Used by the mesh self-revoke poller (plan/24 Wave 3) to
|
|
101
|
+
* know which Owners' mesh blobs to fetch.
|
|
102
|
+
*/
|
|
103
|
+
export declare function listOwnerPubkeys(): Promise<unknown[]>;
|
|
104
|
+
/**
|
|
105
|
+
* Atomically snapshots raw Owner handles and their canonical-slot provenance.
|
|
106
|
+
* The token is deliberately process-local and opaque to callers.
|
|
107
|
+
*/
|
|
108
|
+
export declare function snapshotOwnerPubkeys(): Promise<readonly OwnerStorageSnapshotRecord[]>;
|
|
109
|
+
/**
|
|
110
|
+
* Removes one exact raw handle only when its snapshot provenance still owns
|
|
111
|
+
* the target canonical Owner slot. The final authority/token checks and sync
|
|
112
|
+
* write share the existing serialized mutation lane.
|
|
113
|
+
*/
|
|
114
|
+
export declare function conditionalRemovePeer(remoteEpk: string, expectedToken: OwnerStorageToken, canCommit?: () => boolean): Promise<ConditionalPeerRemoval>;
|
|
115
|
+
export declare function removePeer(remoteEpk: string, canCommit?: () => boolean): Promise<boolean>;
|
|
116
|
+
/** Test-only: expose the identity-file path so tests can clean it. */
|
|
117
|
+
export declare const _IDENTITY_FILE_FOR_TEST: string;
|
|
118
|
+
/** Test-only: expose unlink for cleanup. */
|
|
119
|
+
export declare const _unlinkIdentityFileForTest: () => Promise<void>;
|
|
120
|
+
export {};
|