@herbertgao/pi-extensions 2026.8.2 → 2026.8.4
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 +50 -2
- package/examples/pi-footer.json +275 -0
- 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-footer/CHANGELOG.md +145 -0
- package/node_modules/pi-footer/LICENSE +21 -0
- package/node_modules/pi-footer/README.md +354 -0
- package/node_modules/pi-footer/package.json +68 -0
- package/node_modules/pi-footer/src/cache.ts +106 -0
- package/node_modules/pi-footer/src/colors.ts +237 -0
- package/node_modules/pi-footer/src/config.ts +202 -0
- package/node_modules/pi-footer/src/event-widgets.ts +41 -0
- package/node_modules/pi-footer/src/extension-statuses.ts +102 -0
- package/node_modules/pi-footer/src/git.ts +135 -0
- package/node_modules/pi-footer/src/index.ts +268 -0
- package/node_modules/pi-footer/src/metrics.ts +141 -0
- package/node_modules/pi-footer/src/presets.ts +383 -0
- package/node_modules/pi-footer/src/render.ts +114 -0
- package/node_modules/pi-footer/src/separators.ts +52 -0
- package/node_modules/pi-footer/src/types.ts +122 -0
- package/node_modules/pi-footer/src/ui/color-level-confirm.ts +22 -0
- package/node_modules/pi-footer/src/ui/color-options.ts +195 -0
- package/node_modules/pi-footer/src/ui/config-lifecycle.ts +61 -0
- package/node_modules/pi-footer/src/ui/edit-colors.ts +13 -0
- package/node_modules/pi-footer/src/ui/events.ts +35 -0
- package/node_modules/pi-footer/src/ui/extension-status-picker.ts +60 -0
- package/node_modules/pi-footer/src/ui/extension-statuses.ts +73 -0
- package/node_modules/pi-footer/src/ui/fields.ts +252 -0
- package/node_modules/pi-footer/src/ui/global-menu.ts +126 -0
- package/node_modules/pi-footer/src/ui/helpers.ts +44 -0
- package/node_modules/pi-footer/src/ui/layout.ts +17 -0
- package/node_modules/pi-footer/src/ui/line-list.ts +19 -0
- package/node_modules/pi-footer/src/ui/model.ts +64 -0
- package/node_modules/pi-footer/src/ui/navigation.ts +29 -0
- package/node_modules/pi-footer/src/ui/option-edit.ts +93 -0
- package/node_modules/pi-footer/src/ui/overlay-render.ts +103 -0
- package/node_modules/pi-footer/src/ui/screen-context.ts +18 -0
- package/node_modules/pi-footer/src/ui/screen-controller.ts +27 -0
- package/node_modules/pi-footer/src/ui/screen-render.ts +32 -0
- package/node_modules/pi-footer/src/ui/screen-state.ts +20 -0
- package/node_modules/pi-footer/src/ui/screen.ts +243 -0
- package/node_modules/pi-footer/src/ui/screens/add-widget.ts +92 -0
- package/node_modules/pi-footer/src/ui/screens/confirm-exit.ts +52 -0
- package/node_modules/pi-footer/src/ui/screens/controller.ts +12 -0
- package/node_modules/pi-footer/src/ui/screens/edit-colors.ts +68 -0
- package/node_modules/pi-footer/src/ui/screens/edit-widget.ts +115 -0
- package/node_modules/pi-footer/src/ui/screens/extension-status-row.ts +61 -0
- package/node_modules/pi-footer/src/ui/screens/global.ts +75 -0
- package/node_modules/pi-footer/src/ui/screens/line-list.ts +108 -0
- package/node_modules/pi-footer/src/ui/screens/main.ts +99 -0
- package/node_modules/pi-footer/src/ui/screens/terminal.ts +121 -0
- package/node_modules/pi-footer/src/ui/screens/widget-list.ts +154 -0
- package/node_modules/pi-footer/src/ui/terminal-menu.ts +32 -0
- package/node_modules/pi-footer/src/ui/theme.ts +48 -0
- package/node_modules/pi-footer/src/ui/title-bar.ts +100 -0
- package/node_modules/pi-footer/src/ui/widget-actions.ts +76 -0
- package/node_modules/pi-footer/src/ui.ts +66 -0
- package/node_modules/pi-footer/src/widgets/context.ts +28 -0
- package/node_modules/pi-footer/src/widgets/core/active-tools.ts +17 -0
- package/node_modules/pi-footer/src/widgets/core/context-window.ts +24 -0
- package/node_modules/pi-footer/src/widgets/core/cwd-basename.ts +19 -0
- package/node_modules/pi-footer/src/widgets/core/cwd.ts +108 -0
- package/node_modules/pi-footer/src/widgets/core/event.ts +34 -0
- package/node_modules/pi-footer/src/widgets/core/external-status.ts +102 -0
- package/node_modules/pi-footer/src/widgets/core/model-provider.ts +20 -0
- package/node_modules/pi-footer/src/widgets/core/model.ts +35 -0
- package/node_modules/pi-footer/src/widgets/core/provider.ts +17 -0
- package/node_modules/pi-footer/src/widgets/core/session-name.ts +17 -0
- package/node_modules/pi-footer/src/widgets/core/text-verbosity.ts +17 -0
- package/node_modules/pi-footer/src/widgets/core/thinking-level.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/ahead-behind.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/branch.ts +81 -0
- package/node_modules/pi-footer/src/widgets/git/clean.ts +19 -0
- package/node_modules/pi-footer/src/widgets/git/deletions.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/diff.ts +38 -0
- package/node_modules/pi-footer/src/widgets/git/insertions.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/remote.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/root.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/sha.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/staged.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/status.ts +19 -0
- package/node_modules/pi-footer/src/widgets/git/unstaged.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/untracked.ts +17 -0
- package/node_modules/pi-footer/src/widgets/instance.ts +118 -0
- package/node_modules/pi-footer/src/widgets/layout/custom-text.ts +18 -0
- package/node_modules/pi-footer/src/widgets/layout/flex-separator.ts +32 -0
- package/node_modules/pi-footer/src/widgets/layout/separator.ts +57 -0
- package/node_modules/pi-footer/src/widgets/layout/spacer.ts +31 -0
- package/node_modules/pi-footer/src/widgets/options.ts +122 -0
- package/node_modules/pi-footer/src/widgets/project/runtime.ts +361 -0
- package/node_modules/pi-footer/src/widgets/registry.ts +223 -0
- package/node_modules/pi-footer/src/widgets/session/assistant-messages.ts +17 -0
- package/node_modules/pi-footer/src/widgets/session/compactions.ts +17 -0
- package/node_modules/pi-footer/src/widgets/session/elapsed.ts +18 -0
- package/node_modules/pi-footer/src/widgets/session/last-activity.ts +18 -0
- package/node_modules/pi-footer/src/widgets/session/messages.ts +19 -0
- package/node_modules/pi-footer/src/widgets/session/session-id.ts +17 -0
- package/node_modules/pi-footer/src/widgets/session/session-start.ts +18 -0
- package/node_modules/pi-footer/src/widgets/session/tool-results.ts +17 -0
- package/node_modules/pi-footer/src/widgets/session/total-messages.ts +19 -0
- package/node_modules/pi-footer/src/widgets/session/total-time.ts +18 -0
- package/node_modules/pi-footer/src/widgets/session/user-messages.ts +17 -0
- package/node_modules/pi-footer/src/widgets/store.ts +26 -0
- package/node_modules/pi-footer/src/widgets/tokens/cache-hit-rate.ts +55 -0
- package/node_modules/pi-footer/src/widgets/tokens/cache-read.ts +18 -0
- package/node_modules/pi-footer/src/widgets/tokens/cache-write.ts +18 -0
- package/node_modules/pi-footer/src/widgets/tokens/context-bar.ts +108 -0
- package/node_modules/pi-footer/src/widgets/tokens/context-length.ts +26 -0
- package/node_modules/pi-footer/src/widgets/tokens/context-remaining.ts +29 -0
- package/node_modules/pi-footer/src/widgets/tokens/context.ts +29 -0
- package/node_modules/pi-footer/src/widgets/tokens/cost.ts +51 -0
- package/node_modules/pi-footer/src/widgets/tokens/input-speed.ts +25 -0
- package/node_modules/pi-footer/src/widgets/tokens/input-tokens.ts +18 -0
- package/node_modules/pi-footer/src/widgets/tokens/output-speed.ts +25 -0
- package/node_modules/pi-footer/src/widgets/tokens/output-tokens.ts +18 -0
- package/node_modules/pi-footer/src/widgets/tokens/tokens.ts +20 -0
- package/node_modules/pi-footer/src/widgets/tokens/total-speed.ts +25 -0
- package/node_modules/pi-footer/src/widgets/tokens/total-tokens.ts +18 -0
- package/node_modules/pi-footer/src/widgets/types.ts +181 -0
- package/node_modules/pi-footer/src/widgets/utils/colors.ts +11 -0
- package/node_modules/pi-footer/src/widgets/utils/context.ts +112 -0
- package/node_modules/pi-footer/src/widgets/utils/session.ts +19 -0
- package/node_modules/pi-footer/src/widgets/utils/token-format.ts +78 -0
- 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 +25 -10
- 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,55 @@
|
|
|
1
|
+
import type { AgentSession } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
import type { ClientMessage, ServerMessage } from "../protocol/types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Abstraction over the Noise-encrypted transport.
|
|
5
|
+
* Wave 3 plugs the real channel; tests use a mock.
|
|
6
|
+
*/
|
|
7
|
+
export interface PeerChannel {
|
|
8
|
+
send(msg: ServerMessage): void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Minimal subset of BeforeToolCallContext consumed by the bridge.
|
|
12
|
+
* Shape-compatible with @mariozechner/pi-agent-core BeforeToolCallContext.
|
|
13
|
+
*/
|
|
14
|
+
export interface BridgeToolCallContext {
|
|
15
|
+
toolCall: {
|
|
16
|
+
toolCallId: string;
|
|
17
|
+
toolCall: {
|
|
18
|
+
name: string;
|
|
19
|
+
arguments: Record<string, unknown>;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
args: unknown;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Bridges an AgentSession (Pi SDK) and a PeerChannel (remote app).
|
|
26
|
+
*
|
|
27
|
+
* Wire-up at session creation:
|
|
28
|
+
* const bridge = new AgentBridge(session, channel)
|
|
29
|
+
* // pass bridge.beforeToolCallHook to createAgentSession as beforeToolCall
|
|
30
|
+
*
|
|
31
|
+
* Then route incoming client messages:
|
|
32
|
+
* channel.on('message', msg => bridge.onClientMessage(msg))
|
|
33
|
+
*/
|
|
34
|
+
export declare class AgentBridge {
|
|
35
|
+
private readonly session;
|
|
36
|
+
private readonly channel;
|
|
37
|
+
/** ID of the active user_message turn, used as in_reply_to for streaming. */
|
|
38
|
+
private currentTurnId;
|
|
39
|
+
/** Pending tool approvals keyed by tool_call_id. */
|
|
40
|
+
private readonly pendingApprovals;
|
|
41
|
+
private readonly unsubscribe;
|
|
42
|
+
constructor(session: AgentSession, channel: PeerChannel);
|
|
43
|
+
/**
|
|
44
|
+
* Pass this as `beforeToolCall` in createAgentSession options.
|
|
45
|
+
* Auto-approves whitelisted tools; pauses everything else for user approval.
|
|
46
|
+
*/
|
|
47
|
+
readonly beforeToolCallHook: (ctx: BridgeToolCallContext, signal?: AbortSignal) => Promise<{
|
|
48
|
+
block?: boolean;
|
|
49
|
+
reason?: string;
|
|
50
|
+
} | undefined>;
|
|
51
|
+
onClientMessage(msg: ClientMessage): void;
|
|
52
|
+
dispose(): void;
|
|
53
|
+
private awaitApproval;
|
|
54
|
+
private onSessionEvent;
|
|
55
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { decide } from "./tool_gate.js";
|
|
2
|
+
const APPROVAL_TIMEOUT_MS = 60_000;
|
|
3
|
+
// ── AgentBridge ───────────────────────────────────────────────────────────────
|
|
4
|
+
/**
|
|
5
|
+
* Bridges an AgentSession (Pi SDK) and a PeerChannel (remote app).
|
|
6
|
+
*
|
|
7
|
+
* Wire-up at session creation:
|
|
8
|
+
* const bridge = new AgentBridge(session, channel)
|
|
9
|
+
* // pass bridge.beforeToolCallHook to createAgentSession as beforeToolCall
|
|
10
|
+
*
|
|
11
|
+
* Then route incoming client messages:
|
|
12
|
+
* channel.on('message', msg => bridge.onClientMessage(msg))
|
|
13
|
+
*/
|
|
14
|
+
export class AgentBridge {
|
|
15
|
+
session;
|
|
16
|
+
channel;
|
|
17
|
+
/** ID of the active user_message turn, used as in_reply_to for streaming. */
|
|
18
|
+
currentTurnId = null;
|
|
19
|
+
/** Pending tool approvals keyed by tool_call_id. */
|
|
20
|
+
pendingApprovals = new Map();
|
|
21
|
+
unsubscribe;
|
|
22
|
+
constructor(session, channel) {
|
|
23
|
+
this.session = session;
|
|
24
|
+
this.channel = channel;
|
|
25
|
+
this.unsubscribe = session.subscribe(this.onSessionEvent.bind(this));
|
|
26
|
+
}
|
|
27
|
+
// ── beforeToolCall hook ────────────────────────────────────────────────────
|
|
28
|
+
/**
|
|
29
|
+
* Pass this as `beforeToolCall` in createAgentSession options.
|
|
30
|
+
* Auto-approves whitelisted tools; pauses everything else for user approval.
|
|
31
|
+
*/
|
|
32
|
+
beforeToolCallHook = async (ctx, signal) => {
|
|
33
|
+
const toolName = ctx.toolCall.toolCall.name;
|
|
34
|
+
const toolCallId = ctx.toolCall.toolCallId;
|
|
35
|
+
if (decide(toolName) === "auto") {
|
|
36
|
+
return undefined; // proceed immediately
|
|
37
|
+
}
|
|
38
|
+
// Needs user approval: emit tool_request and block until response
|
|
39
|
+
this.channel.send({
|
|
40
|
+
type: "tool_request",
|
|
41
|
+
tool_call_id: toolCallId,
|
|
42
|
+
tool: toolName,
|
|
43
|
+
args: ctx.args,
|
|
44
|
+
});
|
|
45
|
+
const decision = await this.awaitApproval(toolCallId, signal);
|
|
46
|
+
if (decision === "deny") {
|
|
47
|
+
// Cancel the whole turn — user denied execution
|
|
48
|
+
void this.session.abort();
|
|
49
|
+
return { block: true, reason: "denied by user" };
|
|
50
|
+
}
|
|
51
|
+
return undefined; // allow
|
|
52
|
+
};
|
|
53
|
+
// ── Incoming client messages ───────────────────────────────────────────────
|
|
54
|
+
onClientMessage(msg) {
|
|
55
|
+
switch (msg.type) {
|
|
56
|
+
case "user_message":
|
|
57
|
+
this.currentTurnId = msg.id;
|
|
58
|
+
void this.session.prompt(msg.text);
|
|
59
|
+
break;
|
|
60
|
+
case "approve_tool": {
|
|
61
|
+
const resolve = this.pendingApprovals.get(msg.tool_call_id);
|
|
62
|
+
if (resolve)
|
|
63
|
+
resolve(msg.decision);
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
case "cancel":
|
|
67
|
+
void this.session.abort();
|
|
68
|
+
this.channel.send({
|
|
69
|
+
type: "cancelled",
|
|
70
|
+
in_reply_to: msg.id,
|
|
71
|
+
target_id: msg.target_id,
|
|
72
|
+
});
|
|
73
|
+
break;
|
|
74
|
+
case "ping":
|
|
75
|
+
this.channel.send({ type: "pong", in_reply_to: msg.id });
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// ── Cleanup ────────────────────────────────────────────────────────────────
|
|
80
|
+
dispose() {
|
|
81
|
+
this.unsubscribe();
|
|
82
|
+
for (const resolve of this.pendingApprovals.values()) {
|
|
83
|
+
resolve("deny");
|
|
84
|
+
}
|
|
85
|
+
this.pendingApprovals.clear();
|
|
86
|
+
}
|
|
87
|
+
// ── Private ────────────────────────────────────────────────────────────────
|
|
88
|
+
awaitApproval(toolCallId, signal) {
|
|
89
|
+
return new Promise((resolve) => {
|
|
90
|
+
let settled = false;
|
|
91
|
+
const settle = (d) => {
|
|
92
|
+
if (settled)
|
|
93
|
+
return;
|
|
94
|
+
settled = true;
|
|
95
|
+
clearTimeout(timer);
|
|
96
|
+
this.pendingApprovals.delete(toolCallId);
|
|
97
|
+
resolve(d);
|
|
98
|
+
};
|
|
99
|
+
// 60 s timeout → auto-deny + inform remote peer
|
|
100
|
+
const timer = setTimeout(() => {
|
|
101
|
+
this.channel.send({
|
|
102
|
+
type: "error",
|
|
103
|
+
code: "timeout",
|
|
104
|
+
message: `tool approval timeout: ${toolCallId}`,
|
|
105
|
+
});
|
|
106
|
+
settle("deny");
|
|
107
|
+
}, APPROVAL_TIMEOUT_MS);
|
|
108
|
+
this.pendingApprovals.set(toolCallId, settle);
|
|
109
|
+
signal?.addEventListener("abort", () => settle("deny"), { once: true });
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
onSessionEvent(event) {
|
|
113
|
+
// ── text streaming ─────────────────────────────────────────────────────
|
|
114
|
+
if (event.type === "message_update" && this.currentTurnId !== null) {
|
|
115
|
+
const ae = event.assistantMessageEvent;
|
|
116
|
+
if (ae.type === "text_delta") {
|
|
117
|
+
this.channel.send({
|
|
118
|
+
type: "agent_chunk",
|
|
119
|
+
in_reply_to: this.currentTurnId,
|
|
120
|
+
delta: ae.delta,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// ── tool result ────────────────────────────────────────────────────────
|
|
125
|
+
if (event.type === "tool_execution_end") {
|
|
126
|
+
const toolResult = event.isError
|
|
127
|
+
? {
|
|
128
|
+
type: "tool_result",
|
|
129
|
+
tool_call_id: event.toolCallId,
|
|
130
|
+
error: String(event.result),
|
|
131
|
+
}
|
|
132
|
+
: {
|
|
133
|
+
type: "tool_result",
|
|
134
|
+
tool_call_id: event.toolCallId,
|
|
135
|
+
result: event.result,
|
|
136
|
+
};
|
|
137
|
+
this.channel.send(toolResult);
|
|
138
|
+
}
|
|
139
|
+
// ── turn complete ──────────────────────────────────────────────────────
|
|
140
|
+
if (event.type === "agent_end" && this.currentTurnId !== null) {
|
|
141
|
+
this.channel.send({ type: "agent_done", in_reply_to: this.currentTurnId });
|
|
142
|
+
this.currentTurnId = null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=agent_bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent_bridge.js","sourceRoot":"","sources":["../../src/session/agent_bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Broker } from "./broker.js";
|
|
2
|
+
import { BrokerRemote } from "./broker_remote.js";
|
|
3
|
+
import { PiForwardClient } from "../transport/pi_forward_client.js";
|
|
4
|
+
import type { RelayClient } from "../transport/relay_client.js";
|
|
5
|
+
import { type MeshTopologySnapshot } from "../mesh/siblings.js";
|
|
6
|
+
import type { Ed25519Keypair } from "../pairing/crypto.js";
|
|
7
|
+
/**
|
|
8
|
+
* Cross-PC mesh bridge composition. Discovery finishes before either transport
|
|
9
|
+
* half is constructed, and the returned bridge stays dormant until its caller
|
|
10
|
+
* has re-checked lifecycle ownership and calls `activate()`.
|
|
11
|
+
*/
|
|
12
|
+
export interface AttachBridgeOptions {
|
|
13
|
+
/** The leader's local Broker (from SessionPeer.localBroker()). */
|
|
14
|
+
broker: Broker;
|
|
15
|
+
/** Live relay connection. Caller owns its lifecycle. */
|
|
16
|
+
relay: RelayClient;
|
|
17
|
+
/** Relay URL in http(s):// form — for standalone topology discovery. */
|
|
18
|
+
relayUrl: string;
|
|
19
|
+
/** This host's Ed25519 identity (machine Pi-key). */
|
|
20
|
+
keypair: Ed25519Keypair;
|
|
21
|
+
/** Retained Pi-produced topology. Supplying it bypasses discovery. */
|
|
22
|
+
topology?: MeshTopologySnapshot;
|
|
23
|
+
/** Standalone discovery deadline per mesh request. Defaults to 5 seconds. */
|
|
24
|
+
meshRequestTimeoutMs?: number;
|
|
25
|
+
/** Diagnostic logger. Defaults to a no-op (avoids TUI leaks). */
|
|
26
|
+
log?: (msg: string) => void;
|
|
27
|
+
}
|
|
28
|
+
export interface CrossPcBridge {
|
|
29
|
+
brokerRemote: BrokerRemote;
|
|
30
|
+
piForward: PiForwardClient;
|
|
31
|
+
topology: MeshTopologySnapshot;
|
|
32
|
+
/** Publish the already-built router exactly once. */
|
|
33
|
+
activate(): void;
|
|
34
|
+
/** Safe before or after activation; tears down both halves exactly once. */
|
|
35
|
+
detach(): void;
|
|
36
|
+
}
|
|
37
|
+
export declare function attachCrossPcBridge(opts: AttachBridgeOptions): Promise<CrossPcBridge>;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { BrokerRemote } from "./broker_remote.js";
|
|
2
|
+
import { PiForwardClient } from "../transport/pi_forward_client.js";
|
|
3
|
+
import { MeshClient } from "../mesh/client.js";
|
|
4
|
+
import { buildTopologySnapshot, discoverTopology, } from "../mesh/siblings.js";
|
|
5
|
+
import { canonicalizeEd25519PublicKey, encodeEd25519PublicKey, } from "../mesh/encoding.js";
|
|
6
|
+
import { listOwnerPubkeys } from "../pairing/storage.js";
|
|
7
|
+
function compareAscii(left, right) {
|
|
8
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
9
|
+
}
|
|
10
|
+
function validateAlias(alias, field) {
|
|
11
|
+
if (typeof alias !== "string" || alias.length === 0 || alias.includes(":")) {
|
|
12
|
+
throw new Error(`mesh: ${field} is not a valid routing alias`);
|
|
13
|
+
}
|
|
14
|
+
return alias;
|
|
15
|
+
}
|
|
16
|
+
function validateLegacyPcLabel(label, field) {
|
|
17
|
+
if (typeof label !== "string" || label.length === 0) {
|
|
18
|
+
throw new Error(`mesh: ${field} is not a valid legacy PC label`);
|
|
19
|
+
}
|
|
20
|
+
return label;
|
|
21
|
+
}
|
|
22
|
+
function ownTopology(snapshot, expectedSelfPubkey) {
|
|
23
|
+
const selfPubkey = canonicalizeEd25519PublicKey(snapshot.self?.pcPubkey, "self public key");
|
|
24
|
+
if (selfPubkey !== expectedSelfPubkey) {
|
|
25
|
+
throw new Error("mesh: topology self public key does not match relay identity");
|
|
26
|
+
}
|
|
27
|
+
const selfLabel = validateAlias(snapshot.self.pcLabel, "self.pcLabel");
|
|
28
|
+
const selfLegacyPcLabel = validateLegacyPcLabel(snapshot.self.legacyPcLabel, "self.legacyPcLabel");
|
|
29
|
+
const self = Object.freeze({
|
|
30
|
+
pcLabel: selfLabel,
|
|
31
|
+
pcPubkey: selfPubkey,
|
|
32
|
+
legacyPcLabel: selfLegacyPcLabel,
|
|
33
|
+
});
|
|
34
|
+
const siblingKeys = new Set();
|
|
35
|
+
const siblingAliases = new Set();
|
|
36
|
+
const normalizedSiblings = [];
|
|
37
|
+
for (const [index, sibling] of snapshot.siblings.entries()) {
|
|
38
|
+
const pcPubkey = canonicalizeEd25519PublicKey(sibling.pcPubkey, `siblings[${index}].pcPubkey`);
|
|
39
|
+
if (pcPubkey === selfPubkey)
|
|
40
|
+
continue;
|
|
41
|
+
const pcLabel = validateAlias(sibling.pcLabel, `siblings[${index}].pcLabel`);
|
|
42
|
+
const legacyPcLabel = validateLegacyPcLabel(sibling.legacyPcLabel, `siblings[${index}].legacyPcLabel`);
|
|
43
|
+
if (pcLabel === selfLabel || siblingAliases.has(pcLabel)) {
|
|
44
|
+
throw new Error("mesh: duplicate sibling routing alias");
|
|
45
|
+
}
|
|
46
|
+
if (siblingKeys.has(pcPubkey)) {
|
|
47
|
+
throw new Error("mesh: duplicate sibling public key");
|
|
48
|
+
}
|
|
49
|
+
siblingAliases.add(pcLabel);
|
|
50
|
+
siblingKeys.add(pcPubkey);
|
|
51
|
+
normalizedSiblings.push(Object.freeze({ pcLabel, pcPubkey, legacyPcLabel }));
|
|
52
|
+
}
|
|
53
|
+
normalizedSiblings.sort((left, right) => compareAscii(left.pcPubkey, right.pcPubkey));
|
|
54
|
+
return Object.freeze({ self, siblings: Object.freeze(normalizedSiblings) });
|
|
55
|
+
}
|
|
56
|
+
async function discoverStandaloneTopology(opts) {
|
|
57
|
+
const silent = { warn: (_message) => { } };
|
|
58
|
+
try {
|
|
59
|
+
const owners = await listOwnerPubkeys();
|
|
60
|
+
return await discoverTopology({
|
|
61
|
+
client: new MeshClient(opts.relayUrl, {
|
|
62
|
+
...(opts.meshRequestTimeoutMs !== undefined
|
|
63
|
+
? { requestTimeoutMs: opts.meshRequestTimeoutMs }
|
|
64
|
+
: {}),
|
|
65
|
+
}),
|
|
66
|
+
ownerEpks: owners,
|
|
67
|
+
myPubkey: opts.keypair.publicKey,
|
|
68
|
+
log: silent,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return buildTopologySnapshot(opts.keypair.publicKey, []);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export async function attachCrossPcBridge(opts) {
|
|
76
|
+
const expectedSelfPubkey = encodeEd25519PublicKey(opts.keypair.publicKey, "relay public key");
|
|
77
|
+
const topology = ownTopology(opts.topology ?? await discoverStandaloneTopology(opts), expectedSelfPubkey);
|
|
78
|
+
// No Relay listeners exist until all standalone discovery has completed.
|
|
79
|
+
const piForward = new PiForwardClient(opts.relay);
|
|
80
|
+
let brokerRemote;
|
|
81
|
+
try {
|
|
82
|
+
brokerRemote = new BrokerRemote({
|
|
83
|
+
broker: opts.broker,
|
|
84
|
+
pi: piForward,
|
|
85
|
+
topology,
|
|
86
|
+
activateOnConstruct: false,
|
|
87
|
+
log: opts.log ?? (() => { }),
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
piForward.detach();
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
let state = "dormant";
|
|
95
|
+
return {
|
|
96
|
+
brokerRemote,
|
|
97
|
+
piForward,
|
|
98
|
+
topology,
|
|
99
|
+
activate() {
|
|
100
|
+
if (state !== "dormant")
|
|
101
|
+
return;
|
|
102
|
+
try {
|
|
103
|
+
brokerRemote.activate();
|
|
104
|
+
state = "active";
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
state = "detached";
|
|
108
|
+
try {
|
|
109
|
+
brokerRemote.detach();
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
piForward.detach();
|
|
113
|
+
}
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
detach() {
|
|
118
|
+
if (state === "detached")
|
|
119
|
+
return;
|
|
120
|
+
state = "detached";
|
|
121
|
+
try {
|
|
122
|
+
brokerRemote.detach();
|
|
123
|
+
}
|
|
124
|
+
finally {
|
|
125
|
+
piForward.detach();
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/session/bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import type { Server } from "node:net";
|
|
2
|
+
import { type Envelope } from "./envelope.js";
|
|
3
|
+
/**
|
|
4
|
+
* Structured view of one mesh peer (plan/38). The `address` is the canonical
|
|
5
|
+
* routing key; the other fields let a client group/label peers WITHOUT parsing
|
|
6
|
+
* the address string. `pc` is undefined for local peers (filled cross-PC in
|
|
7
|
+
* Fase 2). Returned by `list_peers` as `peers_detailed`.
|
|
8
|
+
*/
|
|
9
|
+
export interface PeerInfo {
|
|
10
|
+
/** Cross-PC label; undefined for a local peer. */
|
|
11
|
+
pc?: string;
|
|
12
|
+
/** Working directory (realpath). Empty string for a legacy peer (no cwd). */
|
|
13
|
+
cwd: string;
|
|
14
|
+
/** Clean leaf name (carries a `#N` only on a same-(cwd,name) collision). */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Canonical address — the broker's Map key and the `to`/`from` on the wire. */
|
|
17
|
+
address: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* THE sole encoder of a peer address (plan/38): `[<pc>:]<cwd>@<nome>`.
|
|
21
|
+
*
|
|
22
|
+
* - `cwd` present → `<cwd>@<nome>` (the `@` separates name from path so a `/`
|
|
23
|
+
* in the path never confuses lookup, which is exact-match anyway).
|
|
24
|
+
* - `cwd` empty (legacy peer that sent no cwd) → `address == name`, preserving
|
|
25
|
+
* pre-plan/38 behavior so a mixed mesh keeps routing.
|
|
26
|
+
* - `pc` present (cross-PC, Fase 2) → prefixed `<pc>:`.
|
|
27
|
+
*
|
|
28
|
+
* Does NOT sanitize — callers sanitize the `name` once (see `sanitizeMeshName`)
|
|
29
|
+
* before composing, so an already-appended `#N` collision suffix survives.
|
|
30
|
+
* Everyone else ECHOES `peer.address` verbatim; only the broker composes.
|
|
31
|
+
*/
|
|
32
|
+
export declare function composeAddress(parts: {
|
|
33
|
+
pc?: string;
|
|
34
|
+
cwd: string;
|
|
35
|
+
name: string;
|
|
36
|
+
}): string;
|
|
37
|
+
/**
|
|
38
|
+
* Sanitize a requested mesh name to a safe leaf while PRESERVING a trailing
|
|
39
|
+
* `#N` collision suffix (which the cwd-lock or a prior assignment may have
|
|
40
|
+
* added — `sanitizeSegment` alone would mangle `#`→`-`). The base is run through
|
|
41
|
+
* `sanitizeSegment` (af66d04); an unusable base (empty / reserved keyword) falls
|
|
42
|
+
* back to `"agent"`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function sanitizeMeshName(raw: string): string;
|
|
45
|
+
/**
|
|
46
|
+
* Broker hosted by the session leader. Accepts UDS connections, maintains a
|
|
47
|
+
* `name → connection` map, routes envelopes per the `to` field, and appends
|
|
48
|
+
* each routed message to an `audit.jsonl` log.
|
|
49
|
+
*
|
|
50
|
+
* Auto-suffix on name collision: when a peer registers a name already taken,
|
|
51
|
+
* the broker assigns `<name>#N` and returns it in the register ack.
|
|
52
|
+
*
|
|
53
|
+
* ## ACK protocol (plan/25 Wave 0; reliable delivery per plan/34)
|
|
54
|
+
*
|
|
55
|
+
* For **unicast non-broker** envelopes the broker synchronously emits an ACK
|
|
56
|
+
* envelope back to the sender once it has delivered:
|
|
57
|
+
*
|
|
58
|
+
* - target online → deliver envelope, ACK `received`
|
|
59
|
+
* - no such peer → silent drop (sender times out)
|
|
60
|
+
*
|
|
61
|
+
* plan/34 removed the busy-drop: a message that arrives while the target is
|
|
62
|
+
* mid-turn is **always delivered**, never dropped. The Pi harness
|
|
63
|
+
* (`sendMessage(triggerTurn:true)`) enqueues mid-turn messages and processes
|
|
64
|
+
* them in the upcoming turn, so the broker needs no busy gate or mailbox.
|
|
65
|
+
* Consequently `busy` is no longer a possible ACK status for unicast new
|
|
66
|
+
* work — the sender always gets `received`. (Turn-lifecycle / working
|
|
67
|
+
* indicators live in `index.ts` via room_meta over the relay, not here.)
|
|
68
|
+
*
|
|
69
|
+
* Broadcast/multicast/broker-addressed envelopes are not ACKed (no single
|
|
70
|
+
* authoritative recipient or no semantic match). The audit log carries the
|
|
71
|
+
* ACK status (`received | denied | none`) per envelope.
|
|
72
|
+
*/
|
|
73
|
+
export interface BrokerOptions {
|
|
74
|
+
server: Server;
|
|
75
|
+
auditPath?: string;
|
|
76
|
+
/** Optional callback invoked after each successful route (testing/observability). */
|
|
77
|
+
onRouted?: (env: Envelope, deliveredTo: string[]) => void;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Hook the broker calls before doing local routing, so cross-PC prefixes
|
|
81
|
+
* (`<pc_label>:<peer_name>`) can be handed off to a remote forwarder
|
|
82
|
+
* without baking transport knowledge into the broker. Wave C (plan/25)
|
|
83
|
+
* wires `broker_remote.ts` here.
|
|
84
|
+
*/
|
|
85
|
+
export interface RemoteRouter {
|
|
86
|
+
/**
|
|
87
|
+
* Try to claim responsibility for routing this envelope cross-PC.
|
|
88
|
+
* Returns true if claimed (broker MUST NOT also deliver locally). Returns
|
|
89
|
+
* false if the envelope should fall through to local routing — e.g., the
|
|
90
|
+
* prefix matches the local `pc_label`, the prefix is not a known remote
|
|
91
|
+
* label (backward-compat for local names containing `:`), or there's no
|
|
92
|
+
* prefix at all.
|
|
93
|
+
*/
|
|
94
|
+
tryRouteOutbound(env: Envelope): boolean;
|
|
95
|
+
/** Aggregated remote peer addresses (`<pc_label>:<cwd>@<nome>`) for the
|
|
96
|
+
* `list_peers` reply's `peers` (string) field. Empty when nothing known. */
|
|
97
|
+
listRemotePeers(): string[];
|
|
98
|
+
/** Structured remote roster (plan/38 Fase 2): one `PeerInfo` per cross-PC
|
|
99
|
+
* peer with `pc` filled (the sibling label), `cwd`/`name` from the sibling's
|
|
100
|
+
* inventory, and `address` prefixed `<pc>:<cwd>@<nome>`. Powers the
|
|
101
|
+
* `peers_detailed` half of `list_peers` so clients group by `pc`/`cwd`
|
|
102
|
+
* without parsing. Empty when nothing known. */
|
|
103
|
+
listRemotePeerInfos(): PeerInfo[];
|
|
104
|
+
}
|
|
105
|
+
export interface ConditionalRemoteRouterHost {
|
|
106
|
+
clearRemoteRouter(expected: RemoteRouter): void;
|
|
107
|
+
}
|
|
108
|
+
/** Local outcome of a cross-PC envelope injection. broker_remote uses this
|
|
109
|
+
* to construct the ACK envelope it sends back via the relay. plan/34: `busy`
|
|
110
|
+
* is gone — injection always delivers when the peer exists. */
|
|
111
|
+
export type RemoteInjectStatus = "received" | "denied";
|
|
112
|
+
export declare class Broker {
|
|
113
|
+
private readonly peers;
|
|
114
|
+
private readonly auditPath?;
|
|
115
|
+
private readonly onRouted?;
|
|
116
|
+
private readonly server;
|
|
117
|
+
/** Plan/25 Wave C: optional handoff for cross-PC routing. Null = local only. */
|
|
118
|
+
private remoteRouter;
|
|
119
|
+
constructor(opts: BrokerOptions);
|
|
120
|
+
/** Attach (or detach with null) a cross-PC router. Idempotent. */
|
|
121
|
+
setRemoteRouter(router: RemoteRouter | null): void;
|
|
122
|
+
/** Clear only when the caller still owns the active router slot. */
|
|
123
|
+
clearRemoteRouter(expected: RemoteRouter): void;
|
|
124
|
+
/**
|
|
125
|
+
* Plan/25 Wave C entry point: deliver an envelope that arrived from a
|
|
126
|
+
* remote PC (via relay forward) into the local UDS mesh. Skips the
|
|
127
|
+
* `force from = conn.name` rule (that defense is anti-spoof for local
|
|
128
|
+
* peers; cross-PC has its own defense via the relay's verified `from_pc`).
|
|
129
|
+
*
|
|
130
|
+
* Returns the ACK status so the caller (broker_remote) can pack and
|
|
131
|
+
* forward an ACK envelope back across the relay:
|
|
132
|
+
* - `received` — target exists, envelope delivered (plan/34: always
|
|
133
|
+
* delivered when the peer is online — the Pi harness enqueues mid-turn
|
|
134
|
+
* messages, so there is no busy-drop)
|
|
135
|
+
* - `denied` — no such local peer (or write failed) — caller maps to
|
|
136
|
+
* transport_error or denied ACK as it sees fit
|
|
137
|
+
*/
|
|
138
|
+
injectFromRemote(env: Envelope): RemoteInjectStatus;
|
|
139
|
+
/** Peers currently registered. Snapshot, safe to read. */
|
|
140
|
+
peerNames(): string[];
|
|
141
|
+
close(): Promise<void>;
|
|
142
|
+
private _handleConnection;
|
|
143
|
+
private _onData;
|
|
144
|
+
private _handleLine;
|
|
145
|
+
private _handleRegister;
|
|
146
|
+
/**
|
|
147
|
+
* Answer a read-only `list_peers` request from an UNREGISTERED connection
|
|
148
|
+
* (the `remote-pi peers` CLI probe). Returns true when the line was such a
|
|
149
|
+
* probe — the reply is written and the connection stays unregistered: no
|
|
150
|
+
* name assigned, no `peer_joined`/`peer_left` broadcast, no sibling push, so
|
|
151
|
+
* querying the roster from the shell never perturbs the mesh. Returns false
|
|
152
|
+
* (not a probe) so the caller falls through to the register handshake.
|
|
153
|
+
*/
|
|
154
|
+
private _tryObserverProbe;
|
|
155
|
+
/** Local UDS peer names plus cross-PC `<pc>:<peer>` entries from the remote
|
|
156
|
+
* router (empty when no bridge). Shared by the registered `list_peers`
|
|
157
|
+
* handler and the unregistered observer probe. */
|
|
158
|
+
private _allPeerNames;
|
|
159
|
+
/** Structured roster of LOCAL UDS peers (plan/38): one `PeerInfo` each, no
|
|
160
|
+
* `pc` (they're on this machine). Public so the cross-PC router
|
|
161
|
+
* (`broker_remote`) can read the authoritative local inventory directly to
|
|
162
|
+
* push to siblings — no `list_peers` round-trip, no stale cache. */
|
|
163
|
+
localPeerInfos(): PeerInfo[];
|
|
164
|
+
/** Structured roster (plan/38): local peers (no `pc`) + cross-PC peers with
|
|
165
|
+
* `pc`/`cwd`/`name` filled by the remote router (Fase 2). */
|
|
166
|
+
private _allPeerInfos;
|
|
167
|
+
/**
|
|
168
|
+
* Resolve a free `(name, address)` for a register, keyed by **(cwd, name)**
|
|
169
|
+
* (plan/38): the collision check is on the composed ADDRESS, so a name only
|
|
170
|
+
* collides with another peer in the SAME cwd. `#N` is appended to the name
|
|
171
|
+
* (matching the cwd-lock's suffix scheme) until the address is free; for a
|
|
172
|
+
* legacy peer (cwd "") the address is the name, preserving global-name `#N`.
|
|
173
|
+
*/
|
|
174
|
+
private _identityForRegister;
|
|
175
|
+
private _dropPeerAt;
|
|
176
|
+
private _onClose;
|
|
177
|
+
private _route;
|
|
178
|
+
private _resolveTargets;
|
|
179
|
+
/**
|
|
180
|
+
* Writes an ACK envelope to the original sender's socket. Synchronous —
|
|
181
|
+
* the caller is inside `_route` and must keep busy-check/busy-set atomic.
|
|
182
|
+
* Broker → sender: `from="broker"`, `to=env.from`, `re=env.id`,
|
|
183
|
+
* `body={type:"ack", status, target}`.
|
|
184
|
+
*/
|
|
185
|
+
private _sendAckToSender;
|
|
186
|
+
private _handleBrokerMessage;
|
|
187
|
+
private _broadcastSystem;
|
|
188
|
+
private _appendAudit;
|
|
189
|
+
}
|