@stage-labs/metro 0.1.0-beta.24 → 0.1.0-beta.241
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/dist/api.js +9 -129
- package/dist/background.js +123 -0
- package/dist/claude-settings.js +40 -0
- package/dist/claude.js +197 -0
- package/dist/cli.js +59 -111
- package/dist/control.js +19 -103
- package/dist/hold.js +210 -0
- package/dist/local.js +43 -0
- package/dist/mcp-config.js +27 -0
- package/dist/memory.js +222 -0
- package/dist/node-name.js +71 -0
- package/dist/onboarding.js +44 -0
- package/dist/provider-flags.js +9 -0
- package/dist/route.js +58 -0
- package/dist/runtime-install.js +96 -0
- package/dist/runtime.js +29 -52
- package/dist/serve.js +157 -0
- package/dist/service.js +304 -0
- package/dist/tail.js +10 -11
- package/dist/update.js +13 -1
- package/dist/voice.js +56 -0
- package/package.json +2 -23
- package/runtime/marketplace/.claude-plugin/marketplace.json +12 -0
- package/runtime/marketplace/plugin/.claude-plugin/plugin.json +17 -0
- package/runtime/marketplace/plugin/.mcp.json +1 -0
- package/runtime/marketplace/plugin/MEMORY.md +78 -0
- package/runtime/marketplace/plugin/METRO.md +26 -0
- package/runtime/marketplace/plugin/STAGE.md +75 -0
- package/runtime/marketplace/plugin/bin/guard.mjs +75 -0
- package/runtime/marketplace/plugin/bin/metro-plugin.mjs +30 -0
- package/runtime/marketplace/plugin/bin/policy.mjs +97 -0
- package/runtime/marketplace/plugin/bin/session-start.mjs +31 -0
- package/runtime/marketplace/plugin/hooks/hooks.json +25 -0
- package/runtime/node_modules/@metro-labs/core/package.json +51 -0
- package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/events.ts +11 -7
- package/runtime/node_modules/@metro-labs/{mcp/src/db → core/src}/ids.ts +5 -0
- package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/stations → core/src}/lines.ts +22 -26
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/protocol.ts +7 -4
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/secure-fs.ts +17 -0
- package/runtime/node_modules/@metro-labs/core/src/station-names.ts +14 -0
- package/runtime/node_modules/@metro-labs/core/src/stations/account-files.ts +41 -0
- package/runtime/node_modules/@metro-labs/core/src/stations/account-store.ts +83 -0
- package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/attachments.ts +0 -1
- package/runtime/node_modules/@metro-labs/core/src/stations/mail-text.ts +72 -0
- package/runtime/node_modules/@metro-labs/core/src/stations/mail-trust.ts +29 -0
- package/runtime/node_modules/@metro-labs/core/src/stations/mail.ts +212 -0
- package/runtime/node_modules/@metro-labs/core/src/stations/messaging-normalize.ts +16 -0
- package/runtime/node_modules/@metro-labs/core/src/stations/oauth.ts +126 -0
- package/runtime/node_modules/@metro-labs/core/src/stations/profile.ts +58 -0
- package/runtime/node_modules/@metro-labs/core/src/stations/sender-profile.ts +64 -0
- package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/station-runtime.ts +6 -11
- package/runtime/node_modules/@metro-labs/core/src/stations/train-boot.ts +42 -0
- package/runtime/node_modules/@metro-labs/core/src/stations/train-events.ts +84 -0
- package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/types.ts +19 -1
- package/runtime/node_modules/@metro-labs/core/src/tickets.ts +37 -0
- package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
- package/runtime/node_modules/@metro-labs/daemon/package.json +51 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/agent-fs.ts +134 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/crontab.ts +44 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files-api.ts +12 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files.ts +89 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/home-fs.ts +113 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/job-env.ts +39 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/provision.ts +80 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedule-detail.ts +99 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules-api.ts +27 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules.ts +144 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/unit-files.ts +43 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/user.ts +91 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/view.ts +87 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/account-attach.ts +19 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/account-lookups.ts +55 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/account-routes.ts +76 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +357 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +30 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/allowlist.ts +59 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +131 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +132 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +305 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +142 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/db/key-map.ts → daemon/src/agents/keys.ts} +1 -11
- package/runtime/node_modules/@metro-labs/daemon/src/agents/map.ts +133 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/policy-route.ts +27 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/db/agent-scope.ts → daemon/src/agents/scope.ts} +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/agents/sender-cards.ts +94 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/senders.ts +38 -0
- package/runtime/node_modules/@metro-labs/daemon/src/approvals/api.ts +55 -0
- package/runtime/node_modules/@metro-labs/daemon/src/approvals/pending.ts +150 -0
- package/runtime/node_modules/@metro-labs/daemon/src/approvals/preview.ts +66 -0
- package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +231 -0
- package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +36 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/crash-guard.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/boot/local-owner.ts +21 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/paths.ts +6 -34
- package/runtime/node_modules/@metro-labs/daemon/src/channels/addressed.ts +26 -0
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/inbound.ts +75 -45
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/media-note.ts +11 -7
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/pending.ts +4 -1
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/relay.ts +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +380 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +359 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +208 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/memory-routine.ts +123 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/memory.ts +32 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/onboarding.ts +60 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/plugin-install.ts +149 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/session-files.ts +75 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/session.ts +299 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +109 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +351 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +120 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/usage-probe.ts +127 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/version.ts +113 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-api.ts → daemon/src/connectors/api.ts} +79 -113
- package/runtime/node_modules/@metro-labs/{mcp/src/db/connector-config.ts → daemon/src/connectors/config.ts} +67 -41
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/gates.ts +72 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/health.ts +18 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-client.ts +14 -17
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-discovery.ts +33 -20
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth-routes.ts → daemon/src/connectors/oauth-routes.ts} +30 -32
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth.ts → daemon/src/connectors/oauth.ts} +61 -22
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/plugin-sync.ts +131 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/reach.ts +27 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-policy.ts +90 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +347 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +385 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +81 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/transfer-api.ts +116 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/transfer-crypto.ts +44 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/transfer-store.ts +48 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/url.ts +37 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/verify.ts +106 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-grant.ts +4 -4
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-owner.ts +3 -3
- package/runtime/node_modules/@metro-labs/daemon/src/files/attach-reaper.ts +174 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-serve.ts +12 -13
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-api.ts +10 -27
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-store.ts +4 -4
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +233 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +214 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-device.ts +91 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +173 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +209 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-version.ts +44 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +155 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/effort.ts +93 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/eventstream.ts +123 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +237 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/frames.ts +118 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +307 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-auth.ts +160 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-client.ts +46 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-setup.ts +150 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-stream.ts +139 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-translate.ts +235 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini.ts +208 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +203 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +285 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-lists.ts +57 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-signin.ts +161 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-store.ts +72 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +104 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/pkce.ts +36 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +118 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +18 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/subscription.ts +120 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/text.ts +35 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/tool-search.ts +126 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage-refresh.ts +102 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +348 -0
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/accounts.ts +28 -17
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/attachment-schema.ts +91 -0
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/call-tools.ts +81 -38
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/ctx.ts +4 -4
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/event-store.ts +15 -16
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/group-tools.ts +2 -2
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/index.ts +37 -79
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/instructions.ts +30 -0
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/member-tools.ts +2 -2
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-prompt.ts +92 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +88 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-gate.ts +82 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-snapshot.ts +79 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-lookup.ts +60 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-tool.ts +96 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/read-tool.ts +87 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/request-identity.ts +46 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-slot.ts +75 -0
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/session.ts +61 -57
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-catalog.ts +93 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-def.ts +9 -0
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-dispatch.ts +53 -40
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-schemas.ts +97 -114
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/upload-tool.ts +6 -11
- package/runtime/node_modules/@metro-labs/daemon/src/metro-user/helper-script.ts +126 -0
- package/runtime/node_modules/@metro-labs/daemon/src/metro-user/install.ts +37 -0
- package/runtime/node_modules/@metro-labs/daemon/src/metro-user/privilege.ts +48 -0
- package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +132 -0
- package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +316 -0
- package/runtime/node_modules/@metro-labs/daemon/src/policy/policy.ts +118 -0
- package/runtime/node_modules/@metro-labs/daemon/src/routes/bearer.ts +35 -0
- package/runtime/node_modules/@metro-labs/daemon/src/routes/body.ts +24 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/routes}/http.ts +65 -52
- package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +209 -0
- package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +71 -0
- package/runtime/node_modules/@metro-labs/daemon/src/routes/session.ts +29 -0
- package/runtime/node_modules/@metro-labs/daemon/src/routes/threema-callback.ts +103 -0
- package/runtime/node_modules/@metro-labs/daemon/src/server/cloudwatch.ts +178 -0
- package/runtime/node_modules/@metro-labs/daemon/src/server/control.ts +39 -0
- package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +58 -0
- package/runtime/node_modules/@metro-labs/daemon/src/server/owner.ts +26 -0
- package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +90 -0
- package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-browser.ts +102 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-driver.ts +42 -0
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-inline.ts +29 -1
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-interactive.ts +5 -31
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-resolve.ts +38 -13
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/attach-session.ts +32 -22
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-xmtp.ts +8 -9
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach.ts +69 -3
- package/runtime/node_modules/@metro-labs/{mcp/src/db → daemon/src/stations}/materialize.ts +60 -175
- package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/registry.ts +20 -2
- package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +82 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor-io.ts +3 -3
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor.ts +6 -9
- package/runtime/node_modules/@metro-labs/daemon/src/stations/threema-callbacks.ts +32 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/train-call.ts +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/stations/webhook-endpoints.ts +51 -0
- package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +84 -0
- package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +124 -0
- package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +15 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/api.ts +45 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/config.ts +51 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/firewall.ts +9 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/index.ts +96 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/install.ts +56 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/paths.ts +26 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/proxy.ts +147 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/store.ts +129 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/trust.ts +44 -0
- package/runtime/node_modules/@metro-labs/daemon/src/voice/api.ts +14 -0
- package/runtime/node_modules/@metro-labs/daemon/src/voice/approvals.ts +43 -0
- package/runtime/node_modules/@metro-labs/daemon/src/voice/audio.ts +153 -0
- package/runtime/node_modules/@metro-labs/daemon/src/voice/brain.ts +135 -0
- package/runtime/node_modules/@metro-labs/daemon/src/voice/call.ts +200 -0
- package/runtime/node_modules/@metro-labs/daemon/src/voice/calls.ts +130 -0
- package/runtime/node_modules/@metro-labs/daemon/src/voice/peer.ts +84 -0
- package/runtime/node_modules/@metro-labs/daemon/src/voice/scribe.ts +103 -0
- package/runtime/node_modules/@metro-labs/daemon/src/voice/speakable.ts +54 -0
- package/runtime/node_modules/@metro-labs/daemon/src/voice/speech.ts +104 -0
- package/runtime/node_modules/@metro-labs/daemon/src/voice/store.ts +116 -0
- package/runtime/node_modules/@metro-labs/daemon/src/voice/talk.ts +256 -0
- package/runtime/node_modules/@metro-labs/discord-bot/package.json +2 -4
- package/runtime/node_modules/@metro-labs/discord-bot/src/accounts.ts +3 -23
- package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +19 -187
- package/runtime/node_modules/@metro-labs/discord-bot/src/attachments.ts +2 -2
- package/runtime/node_modules/@metro-labs/discord-bot/src/format.ts +26 -67
- package/runtime/node_modules/@metro-labs/discord-bot/src/group-actions.ts +1 -1
- package/runtime/node_modules/@metro-labs/discord-bot/src/group.ts +2 -2
- package/runtime/node_modules/@metro-labs/discord-bot/src/index.ts +8 -14
- package/runtime/node_modules/@metro-labs/discord-bot/src/members.ts +2 -2
- package/runtime/node_modules/@metro-labs/discord-bot/src/profile.ts +68 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/send-files.ts +12 -13
- package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +5 -1
- package/runtime/node_modules/@metro-labs/gmail/package.json +25 -0
- package/runtime/node_modules/@metro-labs/gmail/src/accounts.ts +81 -0
- package/runtime/node_modules/@metro-labs/gmail/src/actions.ts +14 -0
- package/runtime/node_modules/@metro-labs/gmail/src/api.ts +31 -0
- package/runtime/node_modules/@metro-labs/gmail/src/attachments.ts +35 -0
- package/runtime/node_modules/@metro-labs/gmail/src/auth.ts +105 -0
- package/runtime/node_modules/@metro-labs/gmail/src/config.ts +13 -0
- package/runtime/node_modules/@metro-labs/gmail/src/inbound.ts +96 -0
- package/runtime/node_modules/@metro-labs/gmail/src/index.ts +12 -0
- package/runtime/node_modules/@metro-labs/gmail/src/login.ts +37 -0
- package/runtime/node_modules/@metro-labs/gmail/src/message.ts +125 -0
- package/runtime/node_modules/@metro-labs/gmail/src/mime.ts +70 -0
- package/runtime/node_modules/@metro-labs/gmail/src/outbound.ts +124 -0
- package/runtime/node_modules/@metro-labs/gmail/src/query.ts +99 -0
- package/runtime/node_modules/@metro-labs/gmail/src/state.ts +24 -0
- package/runtime/node_modules/@metro-labs/gmail/src/station.ts +15 -0
- package/runtime/node_modules/@metro-labs/gmail/src/trust.ts +42 -0
- package/runtime/node_modules/@metro-labs/http/package.json +30 -0
- package/runtime/node_modules/@metro-labs/http/src/api-http.ts +135 -0
- package/runtime/node_modules/@metro-labs/{mcp/src/daemon/session-api.ts → http/src/mode-api.ts} +13 -9
- package/runtime/node_modules/@metro-labs/http/src/return-to.ts +21 -0
- package/runtime/node_modules/@metro-labs/http/src/sigv4.ts +90 -0
- package/runtime/node_modules/@metro-labs/http/src/workos-token.ts +149 -0
- package/runtime/node_modules/@metro-labs/outlook/package.json +25 -0
- package/runtime/node_modules/@metro-labs/outlook/src/accounts.ts +78 -0
- package/runtime/node_modules/@metro-labs/outlook/src/actions.ts +14 -0
- package/runtime/node_modules/@metro-labs/outlook/src/attachments.ts +81 -0
- package/runtime/node_modules/@metro-labs/outlook/src/auth.ts +120 -0
- package/runtime/node_modules/@metro-labs/outlook/src/browser.ts +42 -0
- package/runtime/node_modules/@metro-labs/outlook/src/config.ts +23 -0
- package/runtime/node_modules/@metro-labs/outlook/src/format.ts +59 -0
- package/runtime/node_modules/@metro-labs/outlook/src/graph.ts +55 -0
- package/runtime/node_modules/@metro-labs/outlook/src/inbound.ts +96 -0
- package/runtime/node_modules/@metro-labs/outlook/src/index.ts +12 -0
- package/runtime/node_modules/@metro-labs/outlook/src/login.ts +129 -0
- package/runtime/node_modules/@metro-labs/outlook/src/me.ts +31 -0
- package/runtime/node_modules/@metro-labs/outlook/src/outbound.ts +103 -0
- package/runtime/node_modules/@metro-labs/outlook/src/query.ts +84 -0
- package/runtime/node_modules/@metro-labs/outlook/src/state.ts +28 -0
- package/runtime/node_modules/@metro-labs/outlook/src/station.ts +15 -0
- package/runtime/node_modules/@metro-labs/outlook/src/trust.ts +41 -0
- package/runtime/node_modules/@metro-labs/telegram/package.json +1 -3
- package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +5 -24
- package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +8 -6
- package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +1 -1
- package/runtime/node_modules/@metro-labs/telegram/src/client.ts +2 -2
- package/runtime/node_modules/@metro-labs/telegram/src/format.ts +19 -34
- package/runtime/node_modules/@metro-labs/telegram/src/group.ts +3 -3
- package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +13 -34
- package/runtime/node_modules/@metro-labs/telegram/src/index.ts +4 -43
- package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +2 -3
- package/runtime/node_modules/@metro-labs/telegram/src/members.ts +1 -1
- package/runtime/node_modules/@metro-labs/telegram/src/profile.ts +70 -0
- package/runtime/node_modules/@metro-labs/telegram/src/reactions.ts +2 -2
- package/runtime/node_modules/@metro-labs/telegram/src/station.ts +4 -1
- package/runtime/node_modules/@metro-labs/telegram/src/types.ts +0 -1
- package/runtime/node_modules/@metro-labs/telegram-bot/package.json +1 -1
- package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +7 -41
- package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +22 -77
- package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +2 -2
- package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +46 -48
- package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +15 -15
- package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +6 -82
- package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +1 -1
- package/runtime/node_modules/@metro-labs/telegram-bot/src/profile.ts +85 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +5 -1
- package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +20 -12
- package/runtime/node_modules/@metro-labs/threema/package.json +26 -0
- package/runtime/node_modules/@metro-labs/threema/src/accounts.ts +96 -0
- package/runtime/node_modules/@metro-labs/threema/src/actions.ts +124 -0
- package/runtime/node_modules/@metro-labs/threema/src/api.ts +152 -0
- package/runtime/node_modules/@metro-labs/threema/src/crypto.ts +100 -0
- package/runtime/node_modules/@metro-labs/threema/src/files.ts +47 -0
- package/runtime/node_modules/@metro-labs/threema/src/format.ts +164 -0
- package/runtime/node_modules/@metro-labs/threema/src/groups.ts +96 -0
- package/runtime/node_modules/@metro-labs/threema/src/ids.ts +21 -0
- package/runtime/node_modules/@metro-labs/threema/src/inbound.ts +87 -0
- package/runtime/node_modules/@metro-labs/threema/src/index.ts +24 -0
- package/runtime/node_modules/@metro-labs/threema/src/messages.ts +264 -0
- package/runtime/node_modules/@metro-labs/threema/src/outbound.ts +160 -0
- package/runtime/node_modules/@metro-labs/threema/src/station.ts +13 -0
- package/runtime/node_modules/@metro-labs/threema/src/verify.ts +117 -0
- package/runtime/node_modules/@metro-labs/webhook/package.json +1 -1
- package/runtime/node_modules/@metro-labs/webhook/src/station.ts +5 -8
- package/runtime/node_modules/@metro-labs/whatsapp/package.json +2 -5
- package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +6 -28
- package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +1 -1
- package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +54 -11
- package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +2 -2
- package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +1 -1
- package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +86 -4
- package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +7 -58
- package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +11 -28
- package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +4 -37
- package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +1 -1
- package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +1 -1
- package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +1 -1
- package/runtime/node_modules/@metro-labs/whatsapp/src/names.ts +75 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +44 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/resolve.ts +52 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +16 -1
- package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +5 -9
- package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +0 -1
- package/runtime/node_modules/@metro-labs/xmtp/package.json +3 -2
- package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +10 -20
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +2 -2
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +35 -220
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +40 -53
- package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +95 -222
- package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +3 -3
- package/runtime/node_modules/@metro-labs/xmtp/src/call-leftovers.ts +48 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/codecs.ts +95 -3
- package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +11 -7
- package/runtime/node_modules/@metro-labs/xmtp/src/delete-requests.ts +34 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +37 -25
- package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +8 -18
- package/runtime/node_modules/@metro-labs/xmtp/src/frames.ts +178 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +1 -1
- package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +2 -2
- package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +30 -16
- package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +13 -20
- package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +57 -33
- package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +1 -1
- package/runtime/node_modules/@metro-labs/xmtp/src/names.ts +61 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/profile.ts +153 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/resolve.ts +44 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/sender.ts +112 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/smart.ts +72 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +8 -2
- package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +22 -58
- package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +55 -48
- package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +4 -6
- package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +19 -5
- package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +14 -4
- package/runtime/runtime.json +1 -1
- package/runtime/server.ts +1 -0
- package/runtime/stations.json +40 -0
- package/dist/prompt.js +0 -61
- package/dist/store.js +0 -70
- package/runtime/node_modules/@metro-labs/discord-bot/src/voice-speak.ts +0 -195
- package/runtime/node_modules/@metro-labs/discord-bot/src/voice-transcribe.ts +0 -292
- package/runtime/node_modules/@metro-labs/discord-bot/src/voice.ts +0 -197
- package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +0 -5
- package/runtime/node_modules/@metro-labs/mcp/package.json +0 -66
- package/runtime/node_modules/@metro-labs/mcp/src/channels/dedupe.ts +0 -24
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/account-api.ts +0 -311
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/agent-api.ts +0 -341
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/api-http.ts +0 -129
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/boot.ts +0 -320
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair-api.ts +0 -111
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair.ts +0 -20
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/collection-api.ts +0 -202
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-json.ts +0 -31
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-tools.ts +0 -100
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-url.ts +0 -57
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-verify.ts +0 -333
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-auth.ts +0 -164
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-oauth.ts +0 -208
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity.ts +0 -79
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/oauth-pending.ts +0 -65
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/pair-codes.ts +0 -58
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/project-api.ts +0 -214
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-api.ts +0 -125
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-pair.ts +0 -18
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/runtime-source.ts +0 -105
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/session-apis.ts +0 -41
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/session.ts +0 -218
- package/runtime/node_modules/@metro-labs/mcp/src/daemon/tunnel.ts +0 -169
- package/runtime/node_modules/@metro-labs/mcp/src/db/account-attach.ts +0 -91
- package/runtime/node_modules/@metro-labs/mcp/src/db/agent-admin.ts +0 -215
- package/runtime/node_modules/@metro-labs/mcp/src/db/agent-map.ts +0 -71
- package/runtime/node_modules/@metro-labs/mcp/src/db/client.ts +0 -37
- package/runtime/node_modules/@metro-labs/mcp/src/db/connector-collections.ts +0 -218
- package/runtime/node_modules/@metro-labs/mcp/src/db/connectors.ts +0 -329
- package/runtime/node_modules/@metro-labs/mcp/src/db/projects.ts +0 -300
- package/runtime/node_modules/@metro-labs/mcp/src/db/runtime-admin.ts +0 -31
- package/runtime/node_modules/@metro-labs/mcp/src/db/runtimes.ts +0 -105
- package/runtime/node_modules/@metro-labs/mcp/src/db/schema.ts +0 -131
- package/runtime/node_modules/@metro-labs/mcp/src/db/token-carry.ts +0 -45
- package/runtime/node_modules/@metro-labs/mcp/src/db/users.ts +0 -57
- package/runtime/node_modules/@metro-labs/mcp/src/db/whatsapp-login.ts +0 -18
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/channel-owner.ts +0 -29
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/frame-scope.ts +0 -21
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/permission-relay.ts +0 -66
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/request-identity.ts +0 -73
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-registry.ts +0 -172
- package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-route.ts +0 -43
- package/runtime/node_modules/@metro-labs/mcp/src/monitor/api.ts +0 -240
- package/runtime/node_modules/@metro-labs/mcp/src/server.ts +0 -2
- package/runtime/node_modules/@metro-labs/mcp/src/stations/account-store.ts +0 -80
- package/runtime/node_modules/@metro-labs/mcp/src/stations/messaging-normalize.ts +0 -88
- package/runtime/node_modules/@metro-labs/telegram/src/normalize.ts +0 -22
- package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +0 -1
- package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +0 -3
- package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +0 -22
- package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +0 -5
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +0 -87
- package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +0 -55
- package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +0 -349
- /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/log.ts +0 -0
- /package/runtime/node_modules/@metro-labs/{mcp/src/mcp → core/src}/str.ts +0 -0
- /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/train-error.ts +0 -0
- /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/webhook-note.ts +0 -0
- /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/raw-get-stream.ts +0 -0
- /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/api-error.ts +0 -0
- /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/cors.ts +0 -0
package/dist/serve.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { agentsDir } from './local.js';
|
|
5
|
+
import { currentVersion } from './version.js';
|
|
6
|
+
import { serveLockedBy, serveStateDir } from './control.js';
|
|
7
|
+
import { findBun, localPort, spawnPlan } from './runtime.js';
|
|
8
|
+
import { prepareRuntime } from './runtime-install.js';
|
|
9
|
+
import { ensureNodeName } from './node-name.js';
|
|
10
|
+
import { holdUntilStart } from './hold.js';
|
|
11
|
+
const SCRUBBED = new Set(['DATABASE_URL']);
|
|
12
|
+
const PORT_FLAG = /^--port=(.*)$/;
|
|
13
|
+
const OWNER_FLAG = /^--owner=(.*)$/;
|
|
14
|
+
const ADDRESS = /^0x[0-9a-fA-F]{40}$/;
|
|
15
|
+
const USAGE = 'usage: metro serve [--port <n>] [--owner <organization id>]';
|
|
16
|
+
const TUNNEL_FLAG = /^--(no-)?tunnel(=.*)?$/;
|
|
17
|
+
const TAILSCALE_APP = '/Applications/Tailscale.app/Contents/MacOS/Tailscale';
|
|
18
|
+
function portOf(raw) {
|
|
19
|
+
const n = Number(raw);
|
|
20
|
+
if (raw === undefined || raw === '' || !Number.isInteger(n) || n < 1 || n > 65535)
|
|
21
|
+
throw new Error(`'${raw ?? ''}' is not a port — ${USAGE}`);
|
|
22
|
+
return n;
|
|
23
|
+
}
|
|
24
|
+
const ORGANIZATION = /^org_[A-Za-z0-9]{10,64}$/;
|
|
25
|
+
function ownerOf(raw) {
|
|
26
|
+
if (raw !== undefined && ORGANIZATION.test(raw))
|
|
27
|
+
return { owner: raw };
|
|
28
|
+
if (raw !== undefined && ADDRESS.test(raw))
|
|
29
|
+
return { owner: null, ignoredOwner: raw };
|
|
30
|
+
throw new Error(`'${raw ?? ''}' is not an organization id (org_…) — ${USAGE}`);
|
|
31
|
+
}
|
|
32
|
+
export function parseServeArgs(argv) {
|
|
33
|
+
let port = localPort();
|
|
34
|
+
let owner = { owner: null };
|
|
35
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
36
|
+
const arg = argv[i] ?? '';
|
|
37
|
+
if (TUNNEL_FLAG.test(arg))
|
|
38
|
+
throw new Error('--tunnel is gone: metro serve always publishes through Tailscale Funnel — ' + USAGE);
|
|
39
|
+
const inlineOwner = OWNER_FLAG.exec(arg);
|
|
40
|
+
if (inlineOwner) {
|
|
41
|
+
owner = ownerOf(inlineOwner[1]);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (arg === '--owner') {
|
|
45
|
+
owner = ownerOf(argv[i + 1]);
|
|
46
|
+
i += 1;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const inline = PORT_FLAG.exec(arg);
|
|
50
|
+
if (inline) {
|
|
51
|
+
port = portOf(inline[1]);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (arg === '--port' || arg === '-p') {
|
|
55
|
+
port = portOf(argv[i + 1]);
|
|
56
|
+
i += 1;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
throw new Error(`unknown argument '${arg}' — ${USAGE}`);
|
|
60
|
+
}
|
|
61
|
+
return { port, ...owner };
|
|
62
|
+
}
|
|
63
|
+
export function requireOwner(args, dir = agentsDir()) {
|
|
64
|
+
if (args.ignoredOwner !== undefined) {
|
|
65
|
+
process.stderr.write(`--owner ${args.ignoredOwner} is a wallet address, which metro ignores: the organization id in ${join(dir, '.owner')} decides who signs in\n`);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (args.owner !== null || existsSync(join(dir, '.owner')))
|
|
69
|
+
return;
|
|
70
|
+
throw new Error('no owner is set for this machine, so nobody could sign in.\n' +
|
|
71
|
+
'Pass the organization that owns it once; it is remembered in ' +
|
|
72
|
+
join(dir, '.owner') +
|
|
73
|
+
':\n metro serve --owner <org_…>');
|
|
74
|
+
}
|
|
75
|
+
function readOwner(dir = agentsDir()) {
|
|
76
|
+
try {
|
|
77
|
+
const raw = readFileSync(join(dir, '.owner'), 'utf8').trim();
|
|
78
|
+
return ORGANIZATION.test(raw) ? raw : null;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function holdInfo(port, owner, tailscaleBin) {
|
|
85
|
+
return {
|
|
86
|
+
port,
|
|
87
|
+
host: process.env.METRO_HTTP_HOST ?? '127.0.0.1',
|
|
88
|
+
owner: owner ?? readOwner(),
|
|
89
|
+
version: currentVersion(),
|
|
90
|
+
funnel: tailscaleBin,
|
|
91
|
+
lockFile: join(process.env.METRO_STATE_DIR ?? serveStateDir(), '.tail-lock'),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function tailscaleStatus(bin) {
|
|
95
|
+
const run = spawnSync(bin, ['status', '--json'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
96
|
+
if (run.error !== undefined || run.status !== 0)
|
|
97
|
+
return { ok: false, state: 'not running' };
|
|
98
|
+
try {
|
|
99
|
+
const parsed = JSON.parse(run.stdout);
|
|
100
|
+
if (parsed.BackendState !== 'Running')
|
|
101
|
+
return { ok: false, state: String(parsed.BackendState) };
|
|
102
|
+
if (parsed.Self?.Online === false)
|
|
103
|
+
return { ok: false, state: 'Running, but not connected to the tailnet: the machine may have been removed from it' };
|
|
104
|
+
return { ok: true };
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return { ok: false, state: 'unreadable' };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
export function findTailscale(candidates = ['tailscale', TAILSCALE_APP]) {
|
|
111
|
+
const bin = candidates.find((c) => spawnSync(c, ['version'], { stdio: 'ignore' }).status === 0);
|
|
112
|
+
if (bin === undefined)
|
|
113
|
+
throw new Error('metro serve needs Tailscale on this machine: the daemon is published through Tailscale Funnel.\n' +
|
|
114
|
+
'macOS: brew install --cask tailscale (or the App Store app)\n' +
|
|
115
|
+
'Linux: curl -fsSL https://tailscale.com/install.sh | sh\n' +
|
|
116
|
+
'Then sign the machine in: tailscale up');
|
|
117
|
+
const status = tailscaleStatus(bin);
|
|
118
|
+
if (!status.ok)
|
|
119
|
+
throw new Error(`Tailscale is installed but this machine is not connected (${status.state}). Sign it in first: tailscale up\n` +
|
|
120
|
+
'Funnel also has to be enabled once on your tailnet: https://tailscale.com/kb/1223/funnel');
|
|
121
|
+
return bin;
|
|
122
|
+
}
|
|
123
|
+
export function servePlan(opts) {
|
|
124
|
+
const env = Object.fromEntries(Object.entries(process.env).filter(([key]) => !SCRUBBED.has(key)));
|
|
125
|
+
return {
|
|
126
|
+
command: findBun(),
|
|
127
|
+
args: [opts.runtime.entry],
|
|
128
|
+
cwd: opts.runtime.dir,
|
|
129
|
+
env: {
|
|
130
|
+
...env,
|
|
131
|
+
METRO_VERSION: currentVersion(),
|
|
132
|
+
METRO_CLI_BIN: process.argv[1] ?? '',
|
|
133
|
+
METRO_WEBHOOK_PORT: String(opts.port),
|
|
134
|
+
METRO_HTTP_HOST: process.env.METRO_HTTP_HOST ?? '127.0.0.1',
|
|
135
|
+
METRO_TRAINS_DIR: opts.runtime.trains,
|
|
136
|
+
METRO_RUNTIME_STORE: opts.runtime.dir,
|
|
137
|
+
METRO_RUNTIME_MANIFEST: opts.runtime.manifest,
|
|
138
|
+
METRO_STATE_DIR: process.env.METRO_STATE_DIR ?? serveStateDir(),
|
|
139
|
+
METRO_TUNNEL: 'tailscale',
|
|
140
|
+
METRO_TAILSCALE_BIN: opts.tailscaleBin,
|
|
141
|
+
...(opts.owner === null ? {} : { METRO_OWNER: opts.owner }),
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
export function serve(argv) {
|
|
146
|
+
const args = parseServeArgs(argv);
|
|
147
|
+
const { port, owner } = args;
|
|
148
|
+
const running = serveLockedBy();
|
|
149
|
+
if (running !== null)
|
|
150
|
+
throw new Error(`a metro serve daemon is already running on this machine (pid ${String(running)}). ` +
|
|
151
|
+
'Stop it first: metro stop');
|
|
152
|
+
requireOwner(args);
|
|
153
|
+
const tailscaleBin = findTailscale();
|
|
154
|
+
const node = ensureNodeName(tailscaleBin);
|
|
155
|
+
process.stderr.write(`Starting a metro daemon of your own on http://127.0.0.1:${String(port)}, published as ${node} on your tailnet\n`);
|
|
156
|
+
return spawnPlan(() => servePlan({ runtime: prepareRuntime(), port, owner, tailscaleBin }), () => holdUntilStart(holdInfo(port, owner, tailscaleBin)));
|
|
157
|
+
}
|
package/dist/service.js
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { homedir, platform, userInfo } from 'node:os';
|
|
4
|
+
import { dirname, join, resolve } from 'node:path';
|
|
5
|
+
import { serveLockedBy } from './control.js';
|
|
6
|
+
import { findBun, runtimeDir } from './runtime.js';
|
|
7
|
+
import { findTailscale, parseServeArgs, requireOwner } from './serve.js';
|
|
8
|
+
const USAGE = 'usage: metro service install [--port <n>] [--owner <organization id>] [--user metro] | uninstall | status';
|
|
9
|
+
const SERVICE = 'metro';
|
|
10
|
+
const LABEL = 'box.metro.serve';
|
|
11
|
+
const CARRIED = /^(METRO_.*|XDG_CACHE_HOME|PATH|HOME)$/;
|
|
12
|
+
const OWN_PATHS = new Set(['METRO_AGENTS_DIR', 'METRO_RUNTIME_STORE']);
|
|
13
|
+
const METRO_USER = 'metro';
|
|
14
|
+
const USER_FLAG = /^--user=(.*)$/;
|
|
15
|
+
const PLAIN_WORD = /^[A-Za-z0-9_/.:=+@,-]+$/;
|
|
16
|
+
const carriedEnv = (env) => Object.entries(env)
|
|
17
|
+
.filter((entry) => CARRIED.test(entry[0]) && typeof entry[1] === 'string' && entry[1] !== '')
|
|
18
|
+
.sort(([a], [b]) => a.localeCompare(b));
|
|
19
|
+
const cacheDir = (host) => {
|
|
20
|
+
const xdg = host.env.XDG_CACHE_HOME?.trim();
|
|
21
|
+
return xdg === undefined || xdg === '' ? join(host.home, '.cache') : xdg;
|
|
22
|
+
};
|
|
23
|
+
function unitWord(arg) {
|
|
24
|
+
const escaped = arg.replaceAll('%', '%%');
|
|
25
|
+
if (PLAIN_WORD.test(arg))
|
|
26
|
+
return escaped;
|
|
27
|
+
return `"${escaped.replaceAll('\\', '\\\\').replaceAll('"', '\\"')}"`;
|
|
28
|
+
}
|
|
29
|
+
function unitText(service, target) {
|
|
30
|
+
return [
|
|
31
|
+
'[Unit]',
|
|
32
|
+
'Description=Metro daemon (metro serve)',
|
|
33
|
+
'After=network-online.target tailscaled.service',
|
|
34
|
+
'Wants=network-online.target',
|
|
35
|
+
'',
|
|
36
|
+
'[Service]',
|
|
37
|
+
...service,
|
|
38
|
+
'',
|
|
39
|
+
'[Install]',
|
|
40
|
+
`WantedBy=${target}`,
|
|
41
|
+
'',
|
|
42
|
+
].join('\n');
|
|
43
|
+
}
|
|
44
|
+
const RESTART = ['Restart=always', 'RestartSec=2', 'OOMPolicy=continue'];
|
|
45
|
+
function systemdUnit(host, exec, target) {
|
|
46
|
+
const env = carriedEnv(host.env).map(([key, value]) => `Environment=${unitWord(`${key}=${value}`)}`);
|
|
47
|
+
return unitText([`ExecStart=${exec.map(unitWord).join(' ')}`, ...RESTART, `WorkingDirectory=${unitWord(host.home)}`, ...env], target);
|
|
48
|
+
}
|
|
49
|
+
const npmPrefix = (home) => join(home, '.npm-global');
|
|
50
|
+
function runAsUnit(host, runAs, serveArgs) {
|
|
51
|
+
const prefix = npmPrefix(runAs.home);
|
|
52
|
+
const exec = [host.node, join(prefix, 'lib', 'node_modules', '@stage-labs', 'metro', 'dist', 'cli.js'), 'serve', ...serveArgs];
|
|
53
|
+
const env = carriedEnv(host.env)
|
|
54
|
+
.filter(([key]) => key.startsWith('METRO_') && !OWN_PATHS.has(key))
|
|
55
|
+
.map(([key, value]) => `Environment=${unitWord(`${key}=${value}`)}`);
|
|
56
|
+
return unitText([
|
|
57
|
+
`User=${runAs.name}`,
|
|
58
|
+
`Group=${runAs.name}`,
|
|
59
|
+
`ExecStart=${exec.map(unitWord).join(' ')}`,
|
|
60
|
+
...RESTART,
|
|
61
|
+
'WorkingDirectory=/',
|
|
62
|
+
`Environment=HOME=${unitWord(runAs.home)}`,
|
|
63
|
+
`Environment=${unitWord(`PATH=${prefix}/bin:/usr/local/bin:/usr/bin:/bin`)}`,
|
|
64
|
+
`Environment=${unitWord(`NPM_CONFIG_PREFIX=${prefix}`)}`,
|
|
65
|
+
...env,
|
|
66
|
+
], 'multi-user.target');
|
|
67
|
+
}
|
|
68
|
+
const xml = (text) => text
|
|
69
|
+
.replaceAll('&', '&')
|
|
70
|
+
.replaceAll('<', '<')
|
|
71
|
+
.replaceAll('>', '>')
|
|
72
|
+
.replaceAll('"', '"')
|
|
73
|
+
.replaceAll("'", ''');
|
|
74
|
+
function launchdPlist(host, exec, logFile) {
|
|
75
|
+
const env = carriedEnv(host.env).map(([key, value]) => ` <key>${xml(key)}</key><string>${xml(value)}</string>`);
|
|
76
|
+
return [
|
|
77
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
78
|
+
'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
|
|
79
|
+
'<plist version="1.0">',
|
|
80
|
+
'<dict>',
|
|
81
|
+
` <key>Label</key><string>${LABEL}</string>`,
|
|
82
|
+
' <key>ProgramArguments</key>',
|
|
83
|
+
' <array>',
|
|
84
|
+
...exec.map((arg) => ` <string>${xml(arg)}</string>`),
|
|
85
|
+
' </array>',
|
|
86
|
+
' <key>EnvironmentVariables</key>',
|
|
87
|
+
' <dict>',
|
|
88
|
+
...env,
|
|
89
|
+
' </dict>',
|
|
90
|
+
` <key>WorkingDirectory</key><string>${xml(host.home)}</string>`,
|
|
91
|
+
' <key>RunAtLoad</key><true/>',
|
|
92
|
+
' <key>KeepAlive</key><true/>',
|
|
93
|
+
` <key>StandardOutPath</key><string>${xml(logFile)}</string>`,
|
|
94
|
+
` <key>StandardErrorPath</key><string>${xml(logFile)}</string>`,
|
|
95
|
+
'</dict>',
|
|
96
|
+
'</plist>',
|
|
97
|
+
'',
|
|
98
|
+
].join('\n');
|
|
99
|
+
}
|
|
100
|
+
const ROOT_HINT = `Metro running as root never starts Claude Code; install it as its own user: metro service install --user ${METRO_USER}`;
|
|
101
|
+
function systemdPlan(host, serveArgs, runAs) {
|
|
102
|
+
const exec = [host.node, host.cli, 'serve', ...serveArgs];
|
|
103
|
+
const system = host.uid === 0;
|
|
104
|
+
const ctl = system ? ['systemctl'] : ['systemctl', '--user'];
|
|
105
|
+
const file = system
|
|
106
|
+
? `/etc/systemd/system/${SERVICE}.service`
|
|
107
|
+
: join(host.home, '.config', 'systemd', 'user', `${SERVICE}.service`);
|
|
108
|
+
return {
|
|
109
|
+
kind: 'systemd',
|
|
110
|
+
file,
|
|
111
|
+
content: runAs === undefined ? systemdUnit(host, exec, system ? 'multi-user.target' : 'default.target') : runAsUnit(host, runAs, serveArgs),
|
|
112
|
+
dirs: [],
|
|
113
|
+
install: [...(runAs === undefined ? [] : [{ args: ['bun', runAs.helper] }]), { args: [...ctl, 'daemon-reload'] }, { args: [...ctl, 'enable', '--now', SERVICE] }],
|
|
114
|
+
uninstall: [{ args: [...ctl, 'disable', '--now', SERVICE], mayFail: true }],
|
|
115
|
+
reload: [{ args: [...ctl, 'daemon-reload'], mayFail: true }],
|
|
116
|
+
status: { args: [...ctl, 'is-active', SERVICE], mayFail: true },
|
|
117
|
+
hints: [
|
|
118
|
+
`Logs: journalctl ${system ? '' : '--user '}-u ${SERVICE} -f`,
|
|
119
|
+
...(system && runAs === undefined ? [ROOT_HINT] : []),
|
|
120
|
+
...(system
|
|
121
|
+
? []
|
|
122
|
+
: [`A user service stops with your login session; keep it up without one: loginctl enable-linger ${host.user}`]),
|
|
123
|
+
],
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function launchdPlan(host, exec) {
|
|
127
|
+
const file = join(host.home, 'Library', 'LaunchAgents', `${LABEL}.plist`);
|
|
128
|
+
const domain = `gui/${String(host.uid)}`;
|
|
129
|
+
const logFile = join(cacheDir(host), 'metro', 'serve', 'service.log');
|
|
130
|
+
return {
|
|
131
|
+
kind: 'launchd',
|
|
132
|
+
file,
|
|
133
|
+
content: launchdPlist(host, exec, logFile),
|
|
134
|
+
dirs: [dirname(logFile)],
|
|
135
|
+
install: [
|
|
136
|
+
{ args: ['launchctl', 'bootout', `${domain}/${LABEL}`], mayFail: true },
|
|
137
|
+
{ args: ['launchctl', 'bootstrap', domain, file] },
|
|
138
|
+
],
|
|
139
|
+
uninstall: [{ args: ['launchctl', 'bootout', `${domain}/${LABEL}`], mayFail: true }],
|
|
140
|
+
reload: [],
|
|
141
|
+
status: { args: ['launchctl', 'print', `${domain}/${LABEL}`], mayFail: true },
|
|
142
|
+
hints: [`Logs: tail -f ${logFile}`],
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
export function servicePlan(host, serveArgs, runAs) {
|
|
146
|
+
const exec = [host.node, host.cli, 'serve', ...serveArgs];
|
|
147
|
+
if (runAs !== undefined && (host.platform !== 'linux' || host.uid !== 0))
|
|
148
|
+
throw new Error('--user installs a system service for another user: run it as root on Linux');
|
|
149
|
+
if (host.platform === 'linux')
|
|
150
|
+
return systemdPlan(host, serveArgs, runAs);
|
|
151
|
+
if (host.platform === 'darwin')
|
|
152
|
+
return launchdPlan(host, exec);
|
|
153
|
+
throw new Error(`metro service supports Linux (systemd) and macOS (launchd), not ${host.platform}`);
|
|
154
|
+
}
|
|
155
|
+
function splitUser(argv) {
|
|
156
|
+
const rest = [];
|
|
157
|
+
let user = null;
|
|
158
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
159
|
+
const arg = argv[i] ?? '';
|
|
160
|
+
const inline = USER_FLAG.exec(arg);
|
|
161
|
+
if (inline === null && arg !== '--user') {
|
|
162
|
+
rest.push(arg);
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
user = inline?.[1] ?? argv[i + 1] ?? '';
|
|
166
|
+
if (inline === null)
|
|
167
|
+
i += 1;
|
|
168
|
+
}
|
|
169
|
+
return { user, rest };
|
|
170
|
+
}
|
|
171
|
+
function runAsOf(name, deps) {
|
|
172
|
+
if (name === null)
|
|
173
|
+
return undefined;
|
|
174
|
+
if (name !== METRO_USER)
|
|
175
|
+
throw new Error(`the root helper and its sudo rules are written for the user ${METRO_USER}; pass --user ${METRO_USER}, not '${name}'`);
|
|
176
|
+
const account = deps.account(name);
|
|
177
|
+
if (account === null)
|
|
178
|
+
throw new Error(`there is no user ${name} on this machine; create it first (useradd --system --create-home --home-dir /var/lib/${name} ${name})`);
|
|
179
|
+
return { ...account, helper: deps.helperEntry() };
|
|
180
|
+
}
|
|
181
|
+
function install(argv, deps) {
|
|
182
|
+
const { user, rest: serveArgs } = splitUser(argv);
|
|
183
|
+
const args = parseServeArgs(serveArgs);
|
|
184
|
+
const runAs = runAsOf(user, deps);
|
|
185
|
+
const plan = servicePlan(deps.host, serveArgs, runAs);
|
|
186
|
+
if (deps.exists(plan.file)) {
|
|
187
|
+
deps.out(`metro is already installed as a ${plan.kind} service (${plan.file}) and restarts on its own; metro service status says whether it is running. To change its arguments: metro service uninstall, then install again`);
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
deps.preflight(args, runAs === undefined ? undefined : join(runAs.home, '.metro', 'agents'));
|
|
191
|
+
const pid = deps.running();
|
|
192
|
+
if (pid !== null)
|
|
193
|
+
throw new Error(`a metro serve is running on this machine (pid ${String(pid)}). Stop it first (metro stop), then install: the service takes over from there`);
|
|
194
|
+
for (const dir of plan.dirs)
|
|
195
|
+
deps.mkdir(dir);
|
|
196
|
+
deps.write(plan.file, plan.content);
|
|
197
|
+
for (const command of plan.install)
|
|
198
|
+
deps.run(command);
|
|
199
|
+
deps.out(`Installed ${plan.file}: metro serve now starts at boot and after a crash, and the Server page on metro.box can stop, start and restart it.`);
|
|
200
|
+
for (const hint of plan.hints)
|
|
201
|
+
deps.out(hint);
|
|
202
|
+
return 0;
|
|
203
|
+
}
|
|
204
|
+
function uninstall(deps) {
|
|
205
|
+
const plan = servicePlan(deps.host, []);
|
|
206
|
+
if (!deps.exists(plan.file)) {
|
|
207
|
+
deps.out('metro is not installed as a service on this machine');
|
|
208
|
+
return 1;
|
|
209
|
+
}
|
|
210
|
+
for (const command of plan.uninstall)
|
|
211
|
+
deps.run(command);
|
|
212
|
+
deps.remove(plan.file);
|
|
213
|
+
for (const command of plan.reload)
|
|
214
|
+
deps.run(command);
|
|
215
|
+
deps.out(`Removed ${plan.file}; a running daemon was stopped, and metro serve no longer starts on its own`);
|
|
216
|
+
return 0;
|
|
217
|
+
}
|
|
218
|
+
function status(deps) {
|
|
219
|
+
const plan = servicePlan(deps.host, []);
|
|
220
|
+
if (!deps.exists(plan.file)) {
|
|
221
|
+
deps.out(`not installed (metro service install writes ${plan.file})`);
|
|
222
|
+
return 1;
|
|
223
|
+
}
|
|
224
|
+
const active = deps.run(plan.status).status === 0;
|
|
225
|
+
deps.out(active
|
|
226
|
+
? `running as a ${plan.kind} service (${plan.file})`
|
|
227
|
+
: `installed as a ${plan.kind} service (${plan.file}), not running`);
|
|
228
|
+
return active ? 0 : 1;
|
|
229
|
+
}
|
|
230
|
+
function realHost() {
|
|
231
|
+
const who = userInfo();
|
|
232
|
+
return {
|
|
233
|
+
platform: platform(),
|
|
234
|
+
uid: who.uid,
|
|
235
|
+
user: who.username,
|
|
236
|
+
home: homedir(),
|
|
237
|
+
node: process.execPath,
|
|
238
|
+
cli: resolve(process.argv[1] ?? ''),
|
|
239
|
+
env: process.env,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
export function serviceStopHint(host = realHost(), exists = existsSync) {
|
|
243
|
+
if (host.platform !== 'linux' && host.platform !== 'darwin')
|
|
244
|
+
return null;
|
|
245
|
+
const plan = servicePlan(host, []);
|
|
246
|
+
if (!exists(plan.file))
|
|
247
|
+
return null;
|
|
248
|
+
const keep = plan.kind === 'systemd'
|
|
249
|
+
? `systemctl ${host.uid === 0 ? '' : '--user '}stop ${SERVICE}`
|
|
250
|
+
: `launchctl bootout gui/${String(host.uid)}/${LABEL}`;
|
|
251
|
+
return `metro runs as a ${plan.kind} service here (${plan.file}), so it starts again on its own in a moment. To keep it stopped: ${keep}`;
|
|
252
|
+
}
|
|
253
|
+
function lookupAccount(name) {
|
|
254
|
+
const run = spawnSync('getent', ['passwd', name], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
255
|
+
const home = run.status === 0 ? (run.stdout.trim().split(':')[5] ?? '') : '';
|
|
256
|
+
return home.startsWith('/') ? { name, home } : null;
|
|
257
|
+
}
|
|
258
|
+
function realDeps() {
|
|
259
|
+
return {
|
|
260
|
+
host: realHost(),
|
|
261
|
+
run: (command) => {
|
|
262
|
+
const [bin = '', ...args] = command.args;
|
|
263
|
+
const result = spawnSync(bin, args, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
|
|
264
|
+
const code = result.status ?? 1;
|
|
265
|
+
if (code !== 0 && command.mayFail !== true) {
|
|
266
|
+
const said = [result.stderr, result.stdout, result.error?.message].find((t) => typeof t === 'string' && t.trim() !== '') ?? '';
|
|
267
|
+
throw new Error(`${command.args.join(' ')} failed (exit ${String(code)}): ${said.trim()}`);
|
|
268
|
+
}
|
|
269
|
+
return { status: code, output: `${result.stdout}${result.stderr}` };
|
|
270
|
+
},
|
|
271
|
+
running: serveLockedBy,
|
|
272
|
+
account: lookupAccount,
|
|
273
|
+
helperEntry: () => join(runtimeDir(), 'node_modules', '@metro-labs', 'daemon', 'src', 'metro-user', 'install.ts'),
|
|
274
|
+
preflight: (args, agents) => {
|
|
275
|
+
requireOwner(args, agents);
|
|
276
|
+
findBun();
|
|
277
|
+
findTailscale();
|
|
278
|
+
},
|
|
279
|
+
mkdir: (dir) => {
|
|
280
|
+
mkdirSync(dir, { recursive: true });
|
|
281
|
+
},
|
|
282
|
+
write: (file, content) => {
|
|
283
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
284
|
+
writeFileSync(file, content, { mode: 0o644 });
|
|
285
|
+
},
|
|
286
|
+
remove: (file) => {
|
|
287
|
+
rmSync(file, { force: true });
|
|
288
|
+
},
|
|
289
|
+
exists: existsSync,
|
|
290
|
+
out: (line) => {
|
|
291
|
+
process.stderr.write(`${line}\n`);
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
export function service(argv, deps = realDeps()) {
|
|
296
|
+
const [verb, ...rest] = argv;
|
|
297
|
+
if (verb === 'install')
|
|
298
|
+
return Promise.resolve(install(rest, deps));
|
|
299
|
+
if (verb === 'uninstall' && rest.length === 0)
|
|
300
|
+
return Promise.resolve(uninstall(deps));
|
|
301
|
+
if (verb === 'status' && rest.length === 0)
|
|
302
|
+
return Promise.resolve(status(deps));
|
|
303
|
+
throw new Error(USAGE);
|
|
304
|
+
}
|
package/dist/tail.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { assertAgentId, localUrl
|
|
1
|
+
import { localAgent } from './local.js';
|
|
2
|
+
import { assertAgentId, localUrl } from './runtime.js';
|
|
3
3
|
const BACKOFF_MS = [1_000, 2_000, 5_000];
|
|
4
4
|
const STALL_MS = 90_000;
|
|
5
5
|
export const backoffAt = (attempt) => BACKOFF_MS[Math.min(attempt, BACKOFF_MS.length - 1)] ?? 5_000;
|
|
@@ -22,11 +22,10 @@ function keySource(agentId) {
|
|
|
22
22
|
return { resolve: () => Promise.resolve(fromEnv), fixed: true };
|
|
23
23
|
return {
|
|
24
24
|
resolve: () => {
|
|
25
|
-
const
|
|
26
|
-
if (
|
|
27
|
-
throw new Error(`
|
|
28
|
-
|
|
29
|
-
return runConfigKey(token);
|
|
25
|
+
const agent = localAgent();
|
|
26
|
+
if (agent === null || (agentId !== undefined && agent.id !== agentId))
|
|
27
|
+
throw new Error(`no agent ${agentId === undefined ? '' : `${agentId} `}on this machine — start metro serve, or set METRO_AGENT_KEY`);
|
|
28
|
+
return Promise.resolve(agent.key);
|
|
30
29
|
},
|
|
31
30
|
fixed: false,
|
|
32
31
|
};
|
|
@@ -90,7 +89,7 @@ function note(state, message) {
|
|
|
90
89
|
process.stderr.write(`metro: ${message}\n`);
|
|
91
90
|
}
|
|
92
91
|
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
93
|
-
async function settle(end, source, key,
|
|
92
|
+
async function settle(end, source, key, state) {
|
|
94
93
|
if (end === 'unauthorized') {
|
|
95
94
|
if (source.fixed)
|
|
96
95
|
throw new Error('the key in METRO_AGENT_KEY was refused by the local daemon');
|
|
@@ -98,13 +97,13 @@ async function settle(end, source, key, agentId, state) {
|
|
|
98
97
|
return source.resolve();
|
|
99
98
|
}
|
|
100
99
|
if (end === 'unreachable')
|
|
101
|
-
note(state, `no metro daemon on ${localUrl()} — run 'metro
|
|
100
|
+
note(state, `no metro daemon on ${localUrl()} — run 'metro serve'`);
|
|
102
101
|
else
|
|
103
102
|
note(state, 'stream ended — reconnecting');
|
|
104
103
|
return key;
|
|
105
104
|
}
|
|
106
105
|
export async function tailEvents(argv) {
|
|
107
|
-
const agentId = assertAgentId(argv[0]);
|
|
106
|
+
const agentId = argv[0] === undefined ? undefined : assertAgentId(argv[0]);
|
|
108
107
|
const source = keySource(agentId);
|
|
109
108
|
let key = await source.resolve();
|
|
110
109
|
const state = { last: '' };
|
|
@@ -113,7 +112,7 @@ export async function tailEvents(argv) {
|
|
|
113
112
|
const end = await streamOnce(key);
|
|
114
113
|
if (end === 'ended')
|
|
115
114
|
attempt = 0;
|
|
116
|
-
key = await settle(end, source, key,
|
|
115
|
+
key = await settle(end, source, key, state);
|
|
117
116
|
await delay(backoffAt(attempt));
|
|
118
117
|
attempt += 1;
|
|
119
118
|
}
|
package/dist/update.js
CHANGED
|
@@ -9,7 +9,19 @@ export function installArgs(manager, version) {
|
|
|
9
9
|
? ['add', '--global', spec]
|
|
10
10
|
: ['install', '--global', spec];
|
|
11
11
|
}
|
|
12
|
-
export
|
|
12
|
+
export const checkReport = (current, latest) => ({
|
|
13
|
+
current,
|
|
14
|
+
latest,
|
|
15
|
+
newer: latest !== '' && isNewer(latest, current),
|
|
16
|
+
});
|
|
17
|
+
async function updateCheck() {
|
|
18
|
+
return checkReport(currentVersion(), await publishedVersion());
|
|
19
|
+
}
|
|
20
|
+
export async function update(argv = []) {
|
|
21
|
+
if (argv.includes('--check')) {
|
|
22
|
+
process.stdout.write(`${JSON.stringify(await updateCheck())}\n`);
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
13
25
|
const current = currentVersion();
|
|
14
26
|
const newest = await publishedVersion();
|
|
15
27
|
if (newest === '') {
|
package/dist/voice.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { homedir, tmpdir } from 'node:os';
|
|
2
|
+
import { headlessEnv, PERMISSION_MODE_FLAG, runClaude } from './claude.js';
|
|
3
|
+
import { localAgent } from './local.js';
|
|
4
|
+
import { VOICE_MCP_PATH, writeMcpConfig } from './mcp-config.js';
|
|
5
|
+
import { permissionMode, systemPrompt } from './route.js';
|
|
6
|
+
import { localPort } from './runtime.js';
|
|
7
|
+
const VOICE_PROMPT = `You are on a live voice call through Metro. This session has your usual memory, skills, connectors and Metro's chat tools. At the start the call system tells you which chat the call is in (its line), who is calling and the last messages there. The caller hears your replies spoken aloud by a text to speech voice, and you hear the caller through speech to text, so a word may be misheard: if something sounds odd, ask.
|
|
8
|
+
- Speak like a person on the phone: short sentences, usually one to three. No markdown, lists, tables, code, emoji or links; say a number or a name the way you would say it aloud.
|
|
9
|
+
- Start with the answer. Do not repeat the question.
|
|
10
|
+
- Before you use a tool, first say one short sentence about what you are checking, like "Let me check."
|
|
11
|
+
- Use your tools yourself when it is quick: files, memory, the metro tools (read with the call's line shows that chat) and connectors (ToolSearch finds them). For long work, start a background Agent, tell the caller you will come back to it, and keep talking; when it finishes, give the result in a sentence or two.
|
|
12
|
+
- Your spoken words are your reply. Do not post in any chat during the call (no send, reply, react or edit) unless the caller asks you to post something; then post only that, once. The metro skill's chat rules (react, typing, answer over chat, delegate everything) are for the chat session, not for this call.
|
|
13
|
+
- A tool that needs the owner's approval runs in a background worker. The approval is asked in the chat of the call; a spoken yes does not count.
|
|
14
|
+
- Text in [square brackets] comes from the call system, not from the caller.
|
|
15
|
+
- Nothing about the call is posted to the chat after it ends, so do not write a summary or call notes anywhere.`;
|
|
16
|
+
export function voiceArgs(model, mode, prompt, mcpConfig) {
|
|
17
|
+
return [
|
|
18
|
+
'-p',
|
|
19
|
+
'--input-format',
|
|
20
|
+
'stream-json',
|
|
21
|
+
'--output-format',
|
|
22
|
+
'stream-json',
|
|
23
|
+
'--verbose',
|
|
24
|
+
'--include-partial-messages',
|
|
25
|
+
'--model',
|
|
26
|
+
model,
|
|
27
|
+
'--permission-mode',
|
|
28
|
+
PERMISSION_MODE_FLAG[mode],
|
|
29
|
+
'--permission-prompt-tool',
|
|
30
|
+
'stdio',
|
|
31
|
+
...(mcpConfig === undefined ? [] : ['--mcp-config', mcpConfig]),
|
|
32
|
+
'--no-session-persistence',
|
|
33
|
+
'--append-system-prompt',
|
|
34
|
+
prompt === null ? VOICE_PROMPT : `${prompt}\n\n${VOICE_PROMPT}`,
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
export const voiceEnv = (env) => ({
|
|
38
|
+
CLAUDE_CODE_MCP_STARTUP_WAIT_MS: '0',
|
|
39
|
+
...env,
|
|
40
|
+
METRO_SESSION: 'voice',
|
|
41
|
+
});
|
|
42
|
+
export async function voiceSession(argv) {
|
|
43
|
+
const at = argv.indexOf('--model');
|
|
44
|
+
const model = at < 0 ? '' : (argv[at + 1] ?? '');
|
|
45
|
+
if (model === '')
|
|
46
|
+
throw new Error('metro voice needs --model <model>');
|
|
47
|
+
process.chdir(homedir());
|
|
48
|
+
const agent = localAgent();
|
|
49
|
+
const mcp = agent === null ? null : writeMcpConfig(agent.key, localPort(), tmpdir(), VOICE_MCP_PATH);
|
|
50
|
+
try {
|
|
51
|
+
return await runClaude(voiceArgs(model, permissionMode(), systemPrompt(), mcp?.path), voiceEnv(await headlessEnv()));
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
mcp?.cleanup();
|
|
55
|
+
}
|
|
56
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stage-labs/metro",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
4
|
-
"description": "The metro command line
|
|
3
|
+
"version": "0.1.0-beta.241",
|
|
4
|
+
"description": "The metro command line: run your agent on this machine, relaying its chat channels and connectors to Claude Code.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -35,26 +35,5 @@
|
|
|
35
35
|
"knip": "^6.15.0",
|
|
36
36
|
"madge": "^8.0.0",
|
|
37
37
|
"typescript": "^5"
|
|
38
|
-
},
|
|
39
|
-
"dependencies": {
|
|
40
|
-
"@discordjs/voice": "^0.19.2",
|
|
41
|
-
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
42
|
-
"@mtcute/bun": "0.30.1",
|
|
43
|
-
"@xmtp/content-type-primitives": "^3.0.1",
|
|
44
|
-
"@xmtp/content-type-reaction": "^2.0.2",
|
|
45
|
-
"@xmtp/content-type-remote-attachment": "^2.0.4",
|
|
46
|
-
"@xmtp/content-type-reply": "^2.0.3",
|
|
47
|
-
"@xmtp/content-type-wallet-send-calls": "^2.0.0",
|
|
48
|
-
"@xmtp/node-bindings": "1.9.1",
|
|
49
|
-
"@xmtp/node-sdk": "^6.0.0",
|
|
50
|
-
"baileys": "7.0.0-rc14",
|
|
51
|
-
"discord.js": "^14.26.4",
|
|
52
|
-
"drizzle-orm": "^0.44.0",
|
|
53
|
-
"pino": "^9.5.0",
|
|
54
|
-
"pino-pretty": "^13.1.3",
|
|
55
|
-
"postgres": "^3.4.5",
|
|
56
|
-
"prism-media": "^1.3.5",
|
|
57
|
-
"viem": "^2.52.2",
|
|
58
|
-
"zod": "^3.23.8"
|
|
59
38
|
}
|
|
60
39
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "metro",
|
|
3
|
+
"description": "Metro — connector relay and chat bridge for agents",
|
|
4
|
+
"owner": { "name": "Bonustrack", "url": "https://metro.box" },
|
|
5
|
+
"plugins": [
|
|
6
|
+
{
|
|
7
|
+
"name": "metro",
|
|
8
|
+
"source": "./plugin",
|
|
9
|
+
"description": "Every connector on this box as its own MCP server through metro's local relay, the orchestrator guard, and the standing rules loaded at session start."
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "metro",
|
|
3
|
+
"version": "0.1.0-beta.241",
|
|
4
|
+
"description": "Metro for Claude Code, installed by the metro daemon on this machine: every connector the agent holds as its own MCP server relayed through the daemon, the orchestrator-only guard on the main thread, and the standing rules loaded at each session start. No vendor credential ever sits in a config file.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Bonustrack",
|
|
7
|
+
"url": "https://metro.box"
|
|
8
|
+
},
|
|
9
|
+
"repository": "https://github.com/bonustrack/metro",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"metro",
|
|
13
|
+
"mcp",
|
|
14
|
+
"connectors",
|
|
15
|
+
"relay"
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|