@stage-labs/metro 0.1.0-beta.2 → 0.1.0-beta.200
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 +11 -0
- package/dist/claude-settings.js +40 -0
- package/dist/claude.js +163 -0
- package/dist/cli.js +77 -567
- package/dist/control.js +74 -0
- package/dist/hold.js +211 -0
- package/dist/local.js +43 -0
- package/dist/mcp-config.js +25 -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 +97 -0
- package/dist/runtime.js +74 -0
- package/dist/serve.js +158 -0
- package/dist/service.js +243 -0
- package/dist/tail.js +102 -144
- package/dist/update.js +45 -0
- package/dist/version.js +97 -0
- package/package.json +14 -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/bin/guard.mjs +71 -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/marketplace/plugin/orchestrator.md +24 -0
- package/runtime/node_modules/@metro-labs/core/package.json +47 -0
- package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
- package/runtime/node_modules/@metro-labs/core/src/events.ts +119 -0
- package/runtime/node_modules/@metro-labs/core/src/identity.ts +7 -0
- package/runtime/node_modules/@metro-labs/core/src/ids.ts +24 -0
- package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
- package/runtime/node_modules/@metro-labs/core/src/lines.ts +91 -0
- package/runtime/node_modules/@metro-labs/core/src/log.ts +42 -0
- package/runtime/node_modules/@metro-labs/core/src/protocol.ts +227 -0
- package/runtime/node_modules/@metro-labs/core/src/secure-fs.ts +74 -0
- package/runtime/node_modules/@metro-labs/core/src/station-names.ts +13 -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 +60 -0
- package/runtime/node_modules/@metro-labs/core/src/stations/attachments.ts +196 -0
- package/runtime/node_modules/@metro-labs/core/src/stations/messaging-normalize.ts +88 -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/core/src/stations/station-runtime.ts +61 -0
- 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 +89 -0
- package/runtime/node_modules/@metro-labs/core/src/stations/types.ts +123 -0
- package/runtime/node_modules/@metro-labs/core/src/str.ts +5 -0
- package/runtime/node_modules/@metro-labs/core/src/tickets.ts +37 -0
- package/runtime/node_modules/@metro-labs/core/src/train-error.ts +53 -0
- package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
- package/runtime/node_modules/@metro-labs/daemon/package.json +48 -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/files-api.ts +12 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files.ts +119 -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 +51 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/provision.ts +91 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedule-detail.ts +100 -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 +252 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agent-user/unit-files.ts +61 -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 +168 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/keys.ts +35 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/map.ts +128 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/policy-route.ts +27 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/scope.ts +64 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/sender-cards.ts +86 -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/needs.ts +2 -0
- package/runtime/node_modules/@metro-labs/daemon/src/approvals/pending.ts +149 -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 +221 -0
- package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +39 -0
- package/runtime/node_modules/@metro-labs/daemon/src/boot/crash-guard.ts +49 -0
- package/runtime/node_modules/@metro-labs/daemon/src/boot/local-owner.ts +21 -0
- package/runtime/node_modules/@metro-labs/daemon/src/boot/paths.ts +106 -0
- package/runtime/node_modules/@metro-labs/daemon/src/channels/addressed.ts +26 -0
- package/runtime/node_modules/@metro-labs/daemon/src/channels/dedupe.ts +12 -0
- package/runtime/node_modules/@metro-labs/daemon/src/channels/inbound.ts +370 -0
- package/runtime/node_modules/@metro-labs/daemon/src/channels/media-note.ts +90 -0
- package/runtime/node_modules/@metro-labs/daemon/src/channels/pending.ts +78 -0
- package/runtime/node_modules/@metro-labs/daemon/src/channels/react-note.ts +13 -0
- package/runtime/node_modules/@metro-labs/daemon/src/channels/relay.ts +129 -0
- package/runtime/node_modules/@metro-labs/daemon/src/channels/reply-id.ts +1 -0
- package/runtime/node_modules/@metro-labs/daemon/src/channels/webhook-note.ts +51 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +355 -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.ts +82 -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 +283 -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 +271 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +120 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/version.ts +113 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/api.ts +306 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/config.ts +176 -0
- 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/daemon/src/connectors/oauth-client.ts +159 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-discovery.ts +135 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-routes.ts +158 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth.ts +166 -0
- 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-target.ts +29 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +348 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +358 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +81 -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/daemon/src/files/attach-grant.ts +99 -0
- package/runtime/node_modules/@metro-labs/daemon/src/files/attach-owner.ts +32 -0
- package/runtime/node_modules/@metro-labs/daemon/src/files/attach-reaper.ts +174 -0
- package/runtime/node_modules/@metro-labs/daemon/src/files/attach-serve.ts +123 -0
- package/runtime/node_modules/@metro-labs/daemon/src/files/upload-api.ts +278 -0
- package/runtime/node_modules/@metro-labs/daemon/src/files/upload-store.ts +181 -0
- 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 +208 -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 +194 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +137 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/effort.ts +77 -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 +274 -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 +223 -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 +199 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +299 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-signin.ts +193 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-store.ts +70 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +90 -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 +66 -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 +15 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +244 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/accounts.ts +156 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/attachment-schema.ts +91 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/call-tools.ts +226 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/ctx.ts +62 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/event-store.ts +90 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/group-tools.ts +129 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/index.ts +137 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/instructions.ts +19 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/member-tools.ts +72 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-prompt.ts +87 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +79 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-gate.ts +83 -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/raw-get-stream.ts +207 -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 +48 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/session.ts +202 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-catalog.ts +88 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-def.ts +9 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-dispatch.ts +225 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-schemas.ts +333 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/upload-tool.ts +61 -0
- package/runtime/node_modules/@metro-labs/daemon/src/metro-user/api.ts +43 -0
- 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/move.ts +165 -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/daemon/src/routes/http.ts +365 -0
- package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +208 -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/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-driver.ts +42 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-inline.ts +128 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-interactive.ts +134 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-outlook.ts +63 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-resolve.ts +225 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-session.ts +288 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-xmtp.ts +111 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/attach.ts +248 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/materialize.ts +265 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/registry.ts +51 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +82 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/supervisor-io.ts +97 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/supervisor.ts +320 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/threema-callbacks.ts +32 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/train-call.ts +22 -0
- 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 +48 -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 +148 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/store.ts +130 -0
- package/runtime/node_modules/@metro-labs/daemon/src/vault/trust.ts +61 -0
- package/runtime/node_modules/@metro-labs/discord-bot/package.json +26 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/accounts.ts +117 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +240 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/api-base.ts +1 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/attachments.ts +29 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/format.ts +174 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/group-actions.ts +50 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/group.ts +115 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/index.ts +122 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/members.ts +215 -0
- 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 +43 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +22 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/verify.ts +82 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +1 -0
- package/runtime/node_modules/@metro-labs/http/package.json +29 -0
- package/runtime/node_modules/@metro-labs/http/src/api-error.ts +8 -0
- package/runtime/node_modules/@metro-labs/http/src/api-http.ts +138 -0
- package/runtime/node_modules/@metro-labs/http/src/cors.ts +29 -0
- package/runtime/node_modules/@metro-labs/http/src/mode-api.ts +32 -0
- package/runtime/node_modules/@metro-labs/http/src/return-to.ts +21 -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 +107 -0
- package/runtime/node_modules/@metro-labs/outlook/src/actions.ts +20 -0
- package/runtime/node_modules/@metro-labs/outlook/src/attachments.ts +97 -0
- package/runtime/node_modules/@metro-labs/outlook/src/auth.ts +150 -0
- package/runtime/node_modules/@metro-labs/outlook/src/browser.ts +53 -0
- package/runtime/node_modules/@metro-labs/outlook/src/config.ts +36 -0
- package/runtime/node_modules/@metro-labs/outlook/src/format.ts +141 -0
- package/runtime/node_modules/@metro-labs/outlook/src/graph.ts +60 -0
- package/runtime/node_modules/@metro-labs/outlook/src/html.ts +72 -0
- package/runtime/node_modules/@metro-labs/outlook/src/inbound.ts +104 -0
- package/runtime/node_modules/@metro-labs/outlook/src/index.ts +12 -0
- package/runtime/node_modules/@metro-labs/outlook/src/login.ts +150 -0
- package/runtime/node_modules/@metro-labs/outlook/src/me.ts +41 -0
- package/runtime/node_modules/@metro-labs/outlook/src/outbound.ts +116 -0
- package/runtime/node_modules/@metro-labs/outlook/src/query.ts +119 -0
- package/runtime/node_modules/@metro-labs/outlook/src/state.ts +43 -0
- package/runtime/node_modules/@metro-labs/outlook/src/station.ts +15 -0
- package/runtime/node_modules/@metro-labs/outlook/src/trust.ts +70 -0
- package/runtime/node_modules/@metro-labs/telegram/package.json +26 -0
- package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +80 -0
- package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +256 -0
- package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +87 -0
- package/runtime/node_modules/@metro-labs/telegram/src/client.ts +77 -0
- package/runtime/node_modules/@metro-labs/telegram/src/format.ts +128 -0
- package/runtime/node_modules/@metro-labs/telegram/src/group.ts +261 -0
- package/runtime/node_modules/@metro-labs/telegram/src/history.ts +52 -0
- package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +57 -0
- package/runtime/node_modules/@metro-labs/telegram/src/index.ts +7 -0
- package/runtime/node_modules/@metro-labs/telegram/src/login.ts +166 -0
- package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +80 -0
- package/runtime/node_modules/@metro-labs/telegram/src/members.ts +75 -0
- package/runtime/node_modules/@metro-labs/telegram/src/normalize.ts +22 -0
- package/runtime/node_modules/@metro-labs/telegram/src/profile.ts +70 -0
- package/runtime/node_modules/@metro-labs/telegram/src/reactions.ts +167 -0
- package/runtime/node_modules/@metro-labs/telegram/src/station.ts +27 -0
- package/runtime/node_modules/@metro-labs/telegram/src/types.ts +6 -0
- package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +1 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/package.json +25 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +119 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +246 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +128 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +173 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +103 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +95 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +47 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/profile.ts +65 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +20 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +56 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/verify.ts +38 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +1 -0
- package/runtime/node_modules/@metro-labs/threema/package.json +26 -0
- package/runtime/node_modules/@metro-labs/threema/src/accounts.ts +106 -0
- package/runtime/node_modules/@metro-labs/threema/src/actions.ts +134 -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 +58 -0
- package/runtime/node_modules/@metro-labs/threema/src/format.ts +169 -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 +89 -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 +23 -0
- package/runtime/node_modules/@metro-labs/webhook/src/station.ts +37 -0
- package/runtime/node_modules/@metro-labs/whatsapp/package.json +27 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +66 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +101 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +213 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +72 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +129 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +388 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/delivery.ts +49 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +83 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +40 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +7 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +59 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/logger.ts +60 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +176 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +84 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/names.ts +28 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +22 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/outbox.ts +38 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +185 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/resolve.ts +52 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +24 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +94 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +5 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +1 -0
- package/runtime/node_modules/@metro-labs/xmtp/package.json +34 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +114 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +110 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +101 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +118 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +244 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +107 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/codecs.ts +171 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +239 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +316 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +69 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +34 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +56 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +47 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +122 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +139 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +40 -0
- 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/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 +17 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +79 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +198 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +88 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +98 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +51 -0
- package/runtime/runtime.json +3 -0
- package/runtime/server.ts +1 -0
- package/runtime/stations.json +37 -0
- package/runtime/trains/.keep +0 -0
- package/LICENSE +0 -21
- package/README.md +0 -78
- package/dist/channels/discord.js +0 -148
- package/dist/channels/telegram.js +0 -137
- package/dist/lib/address.js +0 -21
- package/dist/lib/codex-rc.js +0 -274
- package/dist/lib/dotenv.js +0 -31
- package/dist/log.js +0 -12
- package/dist/paths.js +0 -45
- package/skills/metro/SKILL.md +0 -122
package/dist/cli.js
CHANGED
|
@@ -1,573 +1,83 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
import { readDotenv, writeDotenv } from './lib/dotenv.js';
|
|
12
|
-
import { errMsg, log } from './log.js';
|
|
13
|
-
import { CONFIG_ENV_FILE, configuredPlatforms, loadMetroEnv, STATE_DIR, skillDir, } from './paths.js';
|
|
14
|
-
// ---------------- USAGE ----------------------------------------------------
|
|
15
|
-
const USAGE = `metro — Telegram + Discord bridge for your agent
|
|
2
|
+
import { whoisAuthorized } from './api.js';
|
|
3
|
+
import { stopAll } from './control.js';
|
|
4
|
+
import { tailEvents } from './tail.js';
|
|
5
|
+
import { launchClaude } from './claude.js';
|
|
6
|
+
import { update } from './update.js';
|
|
7
|
+
import { serve } from './serve.js';
|
|
8
|
+
import { service, serviceStopHint } from './service.js';
|
|
9
|
+
import { currentVersion } from './version.js';
|
|
10
|
+
const USAGE = `metro — run your agent on this machine
|
|
16
11
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
12
|
+
metro serve [--port <n>] [--owner <organization id>]
|
|
13
|
+
run the daemon: the agent, its channels and its connectors live in
|
|
14
|
+
~/.metro/agents here, and it is published through Tailscale Funnel at a
|
|
15
|
+
permanent https://<machine>.<tailnet>.ts.net (Tailscale installed and
|
|
16
|
+
signed in on this machine); the page at metro.box manages it through the
|
|
17
|
+
link it prints; --owner names the organization whose members may sign
|
|
18
|
+
in, needed on the first start only; Stop on the page parks the daemon and keeps the
|
|
19
|
+
address, so Start works from the page too
|
|
20
|
+
metro service install [--port <n>] [--owner <organization id>]
|
|
21
|
+
run metro serve as a service (systemd on Linux, launchd on macOS): it
|
|
22
|
+
starts at boot and after a crash, so the page can stop, start and
|
|
23
|
+
restart it with no shell; metro service uninstall and status as well
|
|
24
|
+
metro stop stop metro on this machine, metro serve included
|
|
25
|
+
metro tail [agent-id]
|
|
26
|
+
follow this machine's inbound events, one JSON line each
|
|
27
|
+
metro whoami print the agent this machine runs
|
|
28
|
+
metro claude [args...]
|
|
29
|
+
open Claude Code with the metro channel and the metro MCP server, its
|
|
30
|
+
inference routed through the daemon's model gateway (the Model page);
|
|
31
|
+
every argument is passed through the same
|
|
32
|
+
metro update update to the newest published version (--check only reports)
|
|
33
|
+
metro version print this CLI's version
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
metro setup clear [telegram|discord|all] Remove tokens.
|
|
35
|
-
metro setup skill [--project] [--clear] Install (or remove) the agent skill.
|
|
36
|
-
|
|
37
|
-
Address format:
|
|
38
|
-
telegram:<chat_id>/<message_id> e.g. telegram:-100123456789/4567
|
|
39
|
-
discord:<channel_id>/<message_id> e.g. discord:1234567890/9876543210
|
|
40
|
-
discord:<channel_id> fetch only (no message id)
|
|
41
|
-
|
|
42
|
-
Common flags:
|
|
43
|
-
--json machine-parseable output (single JSON line/array)
|
|
44
|
-
--version, -v print the metro version
|
|
45
|
-
--help, -h print this help
|
|
46
|
-
|
|
47
|
-
reply / edit Telegram extras:
|
|
48
|
-
--parse-mode=HTML|MarkdownV2 --no-link-preview --buttons-json='[[{"text":"…","url":"…"}]]'
|
|
49
|
-
|
|
50
|
-
Exit codes:
|
|
51
|
-
0 success
|
|
52
|
-
1 usage error (bad flags, unknown subcommand)
|
|
53
|
-
2 configuration error (no tokens — run \`metro setup\`)
|
|
54
|
-
3 upstream error (rate limit, auth, network — retry once, then surface)
|
|
55
|
-
|
|
56
|
-
Codex push (opt-in):
|
|
57
|
-
Set METRO_CODEX_RC to the codex app-server URL — metro will push each
|
|
58
|
-
inbound into the agent's history via JSON-RPC \`turn/start\`, the Codex
|
|
59
|
-
equivalent of Claude Code's Monitor.
|
|
60
|
-
|
|
61
|
-
Three terminals share the same URL (codex 0.130's TUI --remote only
|
|
62
|
-
accepts ws://):
|
|
63
|
-
|
|
64
|
-
codex app-server --listen ws://127.0.0.1:8421 # daemon
|
|
65
|
-
METRO_CODEX_RC=ws://127.0.0.1:8421 metro # bridge
|
|
66
|
-
codex --remote ws://127.0.0.1:8421 # TUI
|
|
35
|
+
METRO_WEBHOOK_PORT the daemon's port (default 8420)
|
|
36
|
+
METRO_AGENTS_DIR where the agents live (default ~/.metro/agents)
|
|
37
|
+
METRO_AGENT_KEY the key metro tail presents, instead of the agent file's
|
|
38
|
+
METRO_RUNTIME_DIR run the daemon from this directory instead of the bundled one
|
|
67
39
|
`;
|
|
68
|
-
function
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
for (
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
flags[a.slice(2, eq)] = a.slice(eq + 1);
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
const key = a.slice(2);
|
|
86
|
-
const next = argv[i + 1];
|
|
87
|
-
if (next !== undefined && !next.startsWith('--')) {
|
|
88
|
-
flags[key] = next;
|
|
89
|
-
i++;
|
|
90
|
-
}
|
|
91
|
-
else
|
|
92
|
-
flags[key] = true;
|
|
93
|
-
}
|
|
94
|
-
return { positional, flags };
|
|
95
|
-
}
|
|
96
|
-
const isJson = (flags) => flags.json === true;
|
|
97
|
-
function emitResult(flags, human, structured) {
|
|
98
|
-
process.stdout.write(isJson(flags) ? JSON.stringify(structured) + '\n' : human + '\n');
|
|
99
|
-
}
|
|
100
|
-
function resolveAddr(flags, requireMessage) {
|
|
101
|
-
const addr = parseAddress(String(flags.to), requireMessage);
|
|
102
|
-
if (!configuredPlatforms()[addr.platform]) {
|
|
103
|
-
throw exitErr(`platform '${addr.platform}' is not configured (missing token)`, 2);
|
|
104
|
-
}
|
|
105
|
-
return addr;
|
|
106
|
-
}
|
|
107
|
-
function tgMessageId(addr) {
|
|
108
|
-
const n = Number(addr.messageId);
|
|
109
|
-
if (!Number.isInteger(n))
|
|
110
|
-
throw new Error(`telegram message_id must be an integer: ${addr.messageId}`);
|
|
111
|
-
return n;
|
|
112
|
-
}
|
|
113
|
-
// Tell tail.ts to stop refreshing the typing indicator (the agent has replied).
|
|
114
|
-
function signalReplyComplete(platform, chat) {
|
|
115
|
-
const dir = join(STATE_DIR, '.typing-stop');
|
|
116
|
-
try {
|
|
117
|
-
mkdirSync(dir, { recursive: true });
|
|
118
|
-
writeFileSync(join(dir, `${platform}_${chat}`), '');
|
|
119
|
-
}
|
|
120
|
-
catch (err) {
|
|
121
|
-
log.warn({ err: errMsg(err) }, 'typing stop-signal write failed');
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
async function clearReaction(addr) {
|
|
125
|
-
if (addr.platform === 'telegram') {
|
|
126
|
-
await tg('setMessageReaction', { chat_id: addr.chat, message_id: tgMessageId(addr), reaction: [] });
|
|
127
|
-
}
|
|
128
|
-
else {
|
|
129
|
-
await discord.setReaction(addr.chat, addr.messageId, '');
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
async function readStdinText() {
|
|
133
|
-
if (process.stdin.isTTY)
|
|
134
|
-
return '';
|
|
135
|
-
const chunks = [];
|
|
136
|
-
for await (const c of process.stdin)
|
|
137
|
-
chunks.push(c);
|
|
138
|
-
return Buffer.concat(chunks).toString('utf8');
|
|
139
|
-
}
|
|
140
|
-
async function resolveText(flags) {
|
|
141
|
-
if (typeof flags.text === 'string')
|
|
142
|
-
return flags.text;
|
|
143
|
-
const stdin = (await readStdinText()).replace(/\n$/, '');
|
|
144
|
-
if (!stdin)
|
|
145
|
-
throw new Error('--text is required (or pipe text on stdin)');
|
|
146
|
-
return stdin;
|
|
147
|
-
}
|
|
148
|
-
function readTelegramOpts(flags) {
|
|
149
|
-
const opts = {};
|
|
150
|
-
if (flags['parse-mode']) {
|
|
151
|
-
const v = String(flags['parse-mode']);
|
|
152
|
-
if (v !== 'HTML' && v !== 'MarkdownV2')
|
|
153
|
-
throw new Error("--parse-mode must be 'HTML' or 'MarkdownV2'");
|
|
154
|
-
opts.parseMode = v;
|
|
155
|
-
}
|
|
156
|
-
if (flags['no-link-preview'])
|
|
157
|
-
opts.disableLinkPreview = true;
|
|
158
|
-
if (flags['buttons-json'])
|
|
159
|
-
opts.buttons = JSON.parse(String(flags['buttons-json']));
|
|
160
|
-
return opts;
|
|
161
|
-
}
|
|
162
|
-
function maskToken(token) {
|
|
163
|
-
if (!token)
|
|
164
|
-
return '';
|
|
165
|
-
if (token.length <= 8)
|
|
166
|
-
return '••••';
|
|
167
|
-
return `${token.slice(0, 6)}…${token.slice(-2)}`;
|
|
168
|
-
}
|
|
169
|
-
const EXT_FROM_MIME = {
|
|
170
|
-
'image/png': 'png',
|
|
171
|
-
'image/jpeg': 'jpg',
|
|
172
|
-
'image/gif': 'gif',
|
|
173
|
-
'image/webp': 'webp',
|
|
174
|
-
};
|
|
175
|
-
// Path to the SKILL.md bundled with the npm package. dist/cli.js → ../skills/metro/SKILL.md.
|
|
176
|
-
const BUNDLED_SKILL = join(dirname(fileURLToPath(import.meta.url)), '..', 'skills', 'metro', 'SKILL.md');
|
|
177
|
-
const SKILL_RUNTIMES = ['claude-code', 'codex'];
|
|
178
|
-
const SKILL_SCOPES = ['user', 'project'];
|
|
179
|
-
const skillFile = (runtime, scope) => join(skillDir(runtime, scope), 'SKILL.md');
|
|
180
|
-
// ---------------- setup ----------------------------------------------------
|
|
181
|
-
const TOKEN_KEYS = { telegram: 'TELEGRAM_BOT_TOKEN', discord: 'DISCORD_BOT_TOKEN' };
|
|
182
|
-
async function cmdSetup(positional, flags) {
|
|
183
|
-
const [sub, value] = positional;
|
|
184
|
-
if (!sub)
|
|
185
|
-
return cmdSetupStatus(flags);
|
|
186
|
-
if (sub === 'telegram' || sub === 'discord') {
|
|
187
|
-
if (!value)
|
|
188
|
-
throw new Error(`metro setup ${sub} <token> — token is required`);
|
|
189
|
-
const trimmed = value.trim();
|
|
190
|
-
let identity;
|
|
191
|
-
if (!flags['no-validate']) {
|
|
192
|
-
// Validate against the platform before persisting — catches typos /
|
|
193
|
-
// wrong-token-from-portal / rotated tokens at the earliest moment.
|
|
194
|
-
process.env[TOKEN_KEYS[sub]] = trimmed;
|
|
195
|
-
try {
|
|
196
|
-
identity = sub === 'telegram'
|
|
197
|
-
? `@${(await telegram.getMe()).username}`
|
|
198
|
-
: (await discord.getMe()).username;
|
|
199
|
-
}
|
|
200
|
-
catch (err) {
|
|
201
|
-
delete process.env[TOKEN_KEYS[sub]];
|
|
202
|
-
throw exitErr(`token rejected by ${sub}: ${errMsg(err)} (re-run with --no-validate to save anyway)`, 3);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
const env = readDotenv(CONFIG_ENV_FILE);
|
|
206
|
-
env[TOKEN_KEYS[sub]] = trimmed;
|
|
207
|
-
writeDotenv(CONFIG_ENV_FILE, env);
|
|
208
|
-
const human = identity
|
|
209
|
-
? `saved ${TOKEN_KEYS[sub]} (verified as ${identity}) to ${CONFIG_ENV_FILE} (chmod 0600)`
|
|
210
|
-
: `saved ${TOKEN_KEYS[sub]} to ${CONFIG_ENV_FILE} (chmod 0600)`;
|
|
211
|
-
emitResult(flags, human, { ok: true, saved: TOKEN_KEYS[sub], path: CONFIG_ENV_FILE, verified_as: identity ?? null });
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
if (sub === 'clear') {
|
|
215
|
-
const target = value ?? 'all';
|
|
216
|
-
const env = readDotenv(CONFIG_ENV_FILE);
|
|
217
|
-
if (target === 'all') {
|
|
218
|
-
delete env.TELEGRAM_BOT_TOKEN;
|
|
219
|
-
delete env.DISCORD_BOT_TOKEN;
|
|
220
|
-
}
|
|
221
|
-
else if (target === 'telegram' || target === 'discord') {
|
|
222
|
-
delete env[TOKEN_KEYS[target]];
|
|
223
|
-
}
|
|
224
|
-
else {
|
|
225
|
-
throw new Error(`metro setup clear <telegram|discord|all> — got '${target}'`);
|
|
226
|
-
}
|
|
227
|
-
writeDotenv(CONFIG_ENV_FILE, env);
|
|
228
|
-
const human = `cleared ${target === 'all' ? 'all metro tokens' : TOKEN_KEYS[target]} from ${CONFIG_ENV_FILE}`;
|
|
229
|
-
emitResult(flags, human, { ok: true, cleared: target, path: CONFIG_ENV_FILE });
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
if (sub === 'skill')
|
|
233
|
-
return cmdSetupSkill(flags);
|
|
234
|
-
throw new Error(`unknown setup subcommand '${sub}' (try: telegram, discord, clear, skill)`);
|
|
235
|
-
}
|
|
236
|
-
function readSkillState() {
|
|
237
|
-
return Object.fromEntries(SKILL_RUNTIMES.map(r => [r, Object.fromEntries(SKILL_SCOPES.map(s => [s, existsSync(skillFile(r, s))]))]));
|
|
238
|
-
}
|
|
239
|
-
async function cmdSetupStatus(flags) {
|
|
240
|
-
loadMetroEnv();
|
|
241
|
-
const tg = process.env.TELEGRAM_BOT_TOKEN ?? '';
|
|
242
|
-
const dc = process.env.DISCORD_BOT_TOKEN ?? '';
|
|
243
|
-
const skills = readSkillState();
|
|
244
|
-
const anySkill = SKILL_RUNTIMES.some(r => SKILL_SCOPES.some(s => skills[r][s]));
|
|
245
|
-
if (isJson(flags)) {
|
|
246
|
-
process.stdout.write(JSON.stringify({
|
|
247
|
-
version: pkg.version,
|
|
248
|
-
config_env_file: CONFIG_ENV_FILE,
|
|
249
|
-
tokens: {
|
|
250
|
-
telegram: { set: !!tg, masked: maskToken(tg) },
|
|
251
|
-
discord: { set: !!dc, masked: maskToken(dc) },
|
|
252
|
-
},
|
|
253
|
-
skills,
|
|
254
|
-
}) + '\n');
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
const fmtSkill = (s) => {
|
|
258
|
-
const set = SKILL_SCOPES.filter(k => s[k]);
|
|
259
|
-
return set.length ? `installed (${set.join(' + ')})` : 'not installed';
|
|
260
|
-
};
|
|
261
|
-
process.stdout.write(`metro ${pkg.version}\n\n` +
|
|
262
|
-
`config: ${CONFIG_ENV_FILE}${existsSync(CONFIG_ENV_FILE) ? '' : ' (not yet written)'}\n\n` +
|
|
263
|
-
` TELEGRAM_BOT_TOKEN ${tg ? `set (${maskToken(tg)})` : 'not set'}\n` +
|
|
264
|
-
` DISCORD_BOT_TOKEN ${dc ? `set (${maskToken(dc)})` : 'not set'}\n\n` +
|
|
265
|
-
'Skills:\n' +
|
|
266
|
-
` claude-code ${fmtSkill(skills['claude-code'])}\n` +
|
|
267
|
-
` codex ${fmtSkill(skills.codex)}\n\n`);
|
|
268
|
-
if (!tg && !dc) {
|
|
269
|
-
process.stdout.write('Get started:\n' +
|
|
270
|
-
' 1. metro setup telegram <token> # https://t.me/BotFather\n' +
|
|
271
|
-
' metro setup discord <token> # https://discord.com/developers/applications\n' +
|
|
272
|
-
' 2. metro setup skill # auto-onboard your agent (writes to both runtimes)\n' +
|
|
273
|
-
' 3. metro doctor # verify everything works\n' +
|
|
274
|
-
' 4. metro # start the inbound stream\n');
|
|
275
|
-
}
|
|
276
|
-
else if (!anySkill) {
|
|
277
|
-
process.stdout.write('Next: `metro setup skill` to auto-onboard your agent. Then `metro doctor`, then `metro`.\n');
|
|
278
|
-
}
|
|
279
|
-
else {
|
|
280
|
-
process.stdout.write('Run `metro` to start the inbound stream, or `metro doctor` to verify.\n');
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
async function cmdSetupSkill(flags) {
|
|
284
|
-
const scope = flags.project ? 'project' : 'user';
|
|
285
|
-
if (flags.clear) {
|
|
286
|
-
const removed = [];
|
|
287
|
-
for (const runtime of SKILL_RUNTIMES) {
|
|
288
|
-
const dir = skillDir(runtime, scope);
|
|
289
|
-
if (existsSync(dir)) {
|
|
290
|
-
rmSync(dir, { recursive: true, force: true });
|
|
291
|
-
removed.push(dir);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
emitResult(flags, removed.length ? `removed:\n ${removed.join('\n ')}` : '(no skills installed at this scope)', { ok: true, cleared: removed });
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
if (!existsSync(BUNDLED_SKILL))
|
|
298
|
-
throw new Error(`bundled SKILL.md missing at ${BUNDLED_SKILL} (broken install?)`);
|
|
299
|
-
const written = SKILL_RUNTIMES.map(r => {
|
|
300
|
-
const dest = skillFile(r, scope);
|
|
301
|
-
mkdirSync(dirname(dest), { recursive: true });
|
|
302
|
-
copyFileSync(BUNDLED_SKILL, dest);
|
|
303
|
-
return dest;
|
|
304
|
-
});
|
|
305
|
-
emitResult(flags, `wrote skill (${scope}) to:\n ${written.join('\n ')}\n\nThe agent will pick it up on its next session start.`, { ok: true, scope, paths: written });
|
|
306
|
-
}
|
|
307
|
-
async function cmdDoctor(flags) {
|
|
308
|
-
loadMetroEnv();
|
|
309
|
-
const checks = [];
|
|
310
|
-
// tokens
|
|
311
|
-
const cfg = configuredPlatforms();
|
|
312
|
-
checks.push({
|
|
313
|
-
name: 'tokens',
|
|
314
|
-
ok: cfg.telegram || cfg.discord,
|
|
315
|
-
detail: cfg.telegram || cfg.discord
|
|
316
|
-
? `loaded from ${existsSync(CONFIG_ENV_FILE) ? CONFIG_ENV_FILE : 'process env'}`
|
|
317
|
-
: 'no platform configured — run `metro setup telegram|discord <token>`',
|
|
318
|
-
});
|
|
319
|
-
// gateway / API healthcheck per configured platform
|
|
320
|
-
for (const [platform, getMe] of [['telegram', telegram.getMe], ['discord', discord.getMe]]) {
|
|
321
|
-
if (!cfg[platform]) {
|
|
322
|
-
checks.push({ name: platform, ok: null, detail: 'not configured' });
|
|
323
|
-
continue;
|
|
324
|
-
}
|
|
325
|
-
try {
|
|
326
|
-
const me = await getMe();
|
|
327
|
-
checks.push({ name: platform, ok: true, detail: `getMe → ${platform === 'telegram' ? '@' : ''}${me.username}` });
|
|
328
|
-
}
|
|
329
|
-
catch (err) {
|
|
330
|
-
checks.push({ name: platform, ok: false, detail: errMsg(err) });
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
// tail process state. A stale lockfile (process gone) is informational —
|
|
334
|
-
// the next `metro` start auto-reclaims it, so we don't fail the doctor on it.
|
|
335
|
-
const lockFile = join(STATE_DIR, '.tail-lock');
|
|
336
|
-
if (!existsSync(lockFile)) {
|
|
337
|
-
checks.push({ name: 'stream', ok: null, detail: 'not running' });
|
|
338
|
-
}
|
|
339
|
-
else {
|
|
340
|
-
try {
|
|
341
|
-
const pid = Number(readFileSync(lockFile, 'utf8').trim());
|
|
342
|
-
if (!Number.isInteger(pid) || pid <= 0)
|
|
343
|
-
throw new Error('invalid pid');
|
|
344
|
-
process.kill(pid, 0);
|
|
345
|
-
checks.push({ name: 'stream', ok: true, detail: `running (pid ${pid})` });
|
|
346
|
-
}
|
|
347
|
-
catch {
|
|
348
|
-
checks.push({ name: 'stream', ok: null, detail: 'stale lockfile (will auto-reclaim on next start)' });
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
// skill install + freshness vs bundled
|
|
352
|
-
for (const runtime of SKILL_RUNTIMES) {
|
|
353
|
-
const present = SKILL_SCOPES.filter(s => existsSync(skillFile(runtime, s)));
|
|
354
|
-
if (present.length === 0) {
|
|
355
|
-
checks.push({ name: `skill: ${runtime}`, ok: null, detail: 'not installed — run `metro setup skill` (writes both runtimes)' });
|
|
356
|
-
continue;
|
|
357
|
-
}
|
|
358
|
-
const bundled = existsSync(BUNDLED_SKILL) ? readFileSync(BUNDLED_SKILL) : null;
|
|
359
|
-
const stale = bundled
|
|
360
|
-
? present.filter(s => !readFileSync(skillFile(runtime, s)).equals(bundled))
|
|
361
|
-
: [];
|
|
362
|
-
checks.push(stale.length === 0
|
|
363
|
-
? { name: `skill: ${runtime}`, ok: true, detail: present.join(' + ') }
|
|
364
|
-
: { name: `skill: ${runtime}`, ok: false, detail: `stale at ${stale.join(' + ')} — re-run \`metro setup skill${stale.includes('project') ? ' --project' : ''}\`` });
|
|
365
|
-
}
|
|
366
|
-
if (isJson(flags)) {
|
|
367
|
-
process.stdout.write(JSON.stringify({ checks }) + '\n');
|
|
368
|
-
}
|
|
369
|
-
else {
|
|
370
|
-
process.stdout.write('metro doctor\n\n');
|
|
371
|
-
for (const c of checks) {
|
|
372
|
-
const icon = c.ok === true ? '✓' : c.ok === false ? '✗' : '–';
|
|
373
|
-
process.stdout.write(` ${icon} ${c.name.padEnd(20)} ${c.detail}\n`);
|
|
374
|
-
}
|
|
375
|
-
process.stdout.write('\n');
|
|
376
|
-
}
|
|
377
|
-
if (checks.some(c => c.ok === false))
|
|
378
|
-
throw exitErr('one or more checks failed', 3);
|
|
379
|
-
}
|
|
380
|
-
// ---------------- update ---------------------------------------------------
|
|
381
|
-
async function cmdUpdate(flags) {
|
|
382
|
-
// While metro is in prerelease, the @beta dist-tag is what we publish.
|
|
383
|
-
// After GA, swap to 'latest' (or auto-pick from current version's prerelease tag).
|
|
384
|
-
const tag = pkg.version.includes('-') ? 'beta' : 'latest';
|
|
385
|
-
const res = await fetch('https://registry.npmjs.org/@stage-labs/metro', { signal: AbortSignal.timeout(15_000) });
|
|
386
|
-
if (!res.ok)
|
|
387
|
-
throw new Error(`npm registry: ${res.status}`);
|
|
388
|
-
const data = (await res.json());
|
|
389
|
-
const latest = data['dist-tags']?.[tag];
|
|
390
|
-
if (!latest)
|
|
391
|
-
throw new Error(`no '${tag}' dist-tag for @stage-labs/metro`);
|
|
392
|
-
if (latest === pkg.version) {
|
|
393
|
-
emitResult(flags, `already on ${pkg.version} (latest ${tag})`, { ok: true, current: pkg.version, latest, upgraded: false });
|
|
394
|
-
return;
|
|
395
|
-
}
|
|
396
|
-
const argv1 = process.argv[1] ?? '';
|
|
397
|
-
const spec = `@stage-labs/metro@${tag}`;
|
|
398
|
-
const argv = argv1.includes('/.bun/') || argv1.includes('\\bun\\') ? ['bun', 'add', '-g', spec]
|
|
399
|
-
: argv1.includes('/pnpm/') || argv1.includes('\\pnpm\\') ? ['pnpm', 'add', '-g', spec]
|
|
400
|
-
: ['npm', 'install', '-g', spec];
|
|
401
|
-
if (isJson(flags)) {
|
|
402
|
-
process.stdout.write(JSON.stringify({ ok: true, current: pkg.version, latest, command: argv.join(' '), upgraded: 'pending' }) + '\n');
|
|
403
|
-
}
|
|
404
|
-
else {
|
|
405
|
-
process.stdout.write(`metro ${pkg.version} → ${latest}\n$ ${argv.join(' ')}\n`);
|
|
406
|
-
}
|
|
407
|
-
// Snapshot which skill destinations are installed BEFORE the package
|
|
408
|
-
// manager replaces our binary — after the spawn, BUNDLED_SKILL on disk
|
|
409
|
-
// points at the new content (npm install -g overwrites in place), so a
|
|
410
|
-
// fresh copyFileSync picks it up automatically.
|
|
411
|
-
const refreshTargets = SKILL_RUNTIMES.flatMap(r => SKILL_SCOPES.filter(s => existsSync(skillFile(r, s))).map(s => skillFile(r, s)));
|
|
412
|
-
await new Promise((resolve, reject) => {
|
|
413
|
-
const child = spawn(argv[0], argv.slice(1), { stdio: isJson(flags) ? 'ignore' : 'inherit' });
|
|
414
|
-
child.on('exit', code => (code === 0 ? resolve() : reject(new Error(`${argv[0]} exited with code ${code}`))));
|
|
415
|
-
child.on('error', reject);
|
|
416
|
-
});
|
|
417
|
-
// Refresh installed skills from the (now-updated) bundled SKILL.md.
|
|
418
|
-
if (existsSync(BUNDLED_SKILL)) {
|
|
419
|
-
for (const dest of refreshTargets) {
|
|
420
|
-
mkdirSync(dirname(dest), { recursive: true });
|
|
421
|
-
copyFileSync(BUNDLED_SKILL, dest);
|
|
422
|
-
}
|
|
423
|
-
if (refreshTargets.length > 0 && !isJson(flags)) {
|
|
424
|
-
process.stdout.write(`\nrefreshed installed skills:\n ${refreshTargets.join('\n ')}\n`);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
// ---------------- inbound action commands ----------------------------------
|
|
429
|
-
async function cmdSend(flags) {
|
|
430
|
-
const addr = resolveAddr(flags, false);
|
|
431
|
-
const text = await resolveText(flags);
|
|
432
|
-
const sentMessageId = addr.platform === 'telegram'
|
|
433
|
-
? String((await tg('sendMessage', buildSendBody(addr.chat, text, readTelegramOpts(flags)))).message_id)
|
|
434
|
-
: await discord.sendMessage(addr.chat, text);
|
|
435
|
-
emitResult(flags, 'sent', { ok: true, platform: addr.platform, to: String(flags.to), sent_message_id: sentMessageId });
|
|
436
|
-
}
|
|
437
|
-
async function cmdReply(flags) {
|
|
438
|
-
const addr = resolveAddr(flags, true);
|
|
439
|
-
const text = await resolveText(flags);
|
|
440
|
-
let sentMessageId;
|
|
441
|
-
if (addr.platform === 'telegram') {
|
|
442
|
-
const body = buildSendBody(addr.chat, text, readTelegramOpts(flags));
|
|
443
|
-
body.reply_parameters = { message_id: tgMessageId(addr), allow_sending_without_reply: true };
|
|
444
|
-
sentMessageId = String((await tg('sendMessage', body)).message_id);
|
|
445
|
-
}
|
|
446
|
-
else {
|
|
447
|
-
sentMessageId = await discord.replyToMessage(addr.chat, addr.messageId, text);
|
|
448
|
-
}
|
|
449
|
-
signalReplyComplete(addr.platform, addr.chat);
|
|
450
|
-
await clearReaction(addr).catch(err => log.warn({ err: errMsg(err) }, 'clear-reaction failed'));
|
|
451
|
-
emitResult(flags, 'sent', { ok: true, platform: addr.platform, to: String(flags.to), sent_message_id: sentMessageId });
|
|
452
|
-
}
|
|
453
|
-
async function cmdReact(flags) {
|
|
454
|
-
const addr = resolveAddr(flags, true);
|
|
455
|
-
const emoji = typeof flags.emoji === 'string' ? flags.emoji : '';
|
|
456
|
-
if (addr.platform === 'telegram') {
|
|
457
|
-
await tg('setMessageReaction', { chat_id: addr.chat, message_id: tgMessageId(addr), reaction: emoji ? [{ type: 'emoji', emoji }] : [] });
|
|
458
|
-
}
|
|
459
|
-
else {
|
|
460
|
-
await discord.setReaction(addr.chat, addr.messageId, emoji);
|
|
461
|
-
}
|
|
462
|
-
emitResult(flags, emoji ? 'reacted' : 'cleared', { ok: true, to: String(flags.to), emoji, action: emoji ? 'reacted' : 'cleared' });
|
|
463
|
-
}
|
|
464
|
-
async function cmdEdit(flags) {
|
|
465
|
-
const addr = resolveAddr(flags, true);
|
|
466
|
-
const text = await resolveText(flags);
|
|
467
|
-
if (addr.platform === 'telegram') {
|
|
468
|
-
const body = buildSendBody(addr.chat, text, readTelegramOpts(flags));
|
|
469
|
-
body.message_id = tgMessageId(addr);
|
|
470
|
-
await tg('editMessageText', body);
|
|
471
|
-
}
|
|
472
|
-
else {
|
|
473
|
-
await discord.editMessage(addr.chat, addr.messageId, text);
|
|
474
|
-
}
|
|
475
|
-
emitResult(flags, 'edited', { ok: true, to: String(flags.to) });
|
|
476
|
-
}
|
|
477
|
-
async function cmdDownload(flags) {
|
|
478
|
-
const addr = resolveAddr(flags, true);
|
|
479
|
-
const outDir = typeof flags.out === 'string' ? flags.out : join(STATE_DIR, 'attachments');
|
|
480
|
-
mkdirSync(outDir, { recursive: true });
|
|
481
|
-
const images = addr.platform === 'telegram'
|
|
482
|
-
? await Promise.all(telegram.getCachedAttachments(addr.chat, tgMessageId(addr)).map(a => telegram.downloadAttachment(a.file_id, a.mime)))
|
|
483
|
-
: await discord.fetchAttachments(addr.chat, addr.messageId);
|
|
484
|
-
if (images.length === 0) {
|
|
485
|
-
if (isJson(flags))
|
|
486
|
-
process.stdout.write(JSON.stringify({ ok: true, images: [] }) + '\n');
|
|
487
|
-
else
|
|
488
|
-
process.stderr.write('no image attachments found\n');
|
|
489
|
-
return;
|
|
490
|
-
}
|
|
491
|
-
const safeChat = addr.chat.replace(/[^\w-]/g, '_');
|
|
492
|
-
const safeMsg = (addr.messageId ?? '').replace(/[^\w-]/g, '_');
|
|
493
|
-
const out = images.map((img, i) => {
|
|
494
|
-
const ext = EXT_FROM_MIME[img.mime] ?? 'bin';
|
|
495
|
-
const path = join(outDir, `${addr.platform}_${safeChat}_${safeMsg}_${i}.${ext}`);
|
|
496
|
-
writeFileSync(path, Buffer.from(img.data, 'base64'));
|
|
497
|
-
return { path, mime: img.mime };
|
|
498
|
-
});
|
|
499
|
-
if (isJson(flags))
|
|
500
|
-
process.stdout.write(JSON.stringify({ ok: true, images: out }) + '\n');
|
|
501
|
-
else
|
|
502
|
-
process.stdout.write(out.map(o => o.path).join('\n') + '\n');
|
|
503
|
-
}
|
|
504
|
-
async function cmdFetch(flags) {
|
|
505
|
-
const addr = resolveAddr(flags, false);
|
|
506
|
-
if (addr.platform !== 'discord') {
|
|
507
|
-
throw new Error('metro fetch is Discord-only — Telegram has no recent-messages API for bots');
|
|
508
|
-
}
|
|
509
|
-
const limit = Number(flags.limit ?? 10);
|
|
510
|
-
if (!Number.isInteger(limit) || limit < 1 || limit > 100)
|
|
511
|
-
throw new Error('--limit must be an integer 1–100');
|
|
512
|
-
const msgs = await discord.fetchRecentMessages(addr.chat, limit);
|
|
513
|
-
if (isJson(flags)) {
|
|
514
|
-
process.stdout.write(JSON.stringify(msgs) + '\n');
|
|
515
|
-
}
|
|
516
|
-
else {
|
|
517
|
-
const text = msgs.map(m => `[message_id=${m.message_id} ${m.timestamp}] ${m.author}: ${m.text}`).join('\n');
|
|
518
|
-
process.stdout.write((text || '(channel is empty)') + '\n');
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
// ---------------- main dispatcher ------------------------------------------
|
|
40
|
+
async function stopDaemon() {
|
|
41
|
+
const stopped = await stopAll();
|
|
42
|
+
if (stopped.length === 0) {
|
|
43
|
+
process.stderr.write('no metro daemon is running on this machine\n');
|
|
44
|
+
return 1;
|
|
45
|
+
}
|
|
46
|
+
for (const d of stopped)
|
|
47
|
+
process.stderr.write(`Stopped metro (pid ${String(d.pid)}, via ${d.via})\n`);
|
|
48
|
+
const hint = serviceStopHint();
|
|
49
|
+
if (hint !== null)
|
|
50
|
+
process.stderr.write(`${hint}\n`);
|
|
51
|
+
return 0;
|
|
52
|
+
}
|
|
53
|
+
const HELP = new Set([undefined, 'help', '--help', '-h']);
|
|
522
54
|
const COMMANDS = {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
55
|
+
whoami: async () => {
|
|
56
|
+
const { agent, where } = await whoisAuthorized();
|
|
57
|
+
process.stdout.write(`agent ${agent} on ${where}\n`);
|
|
58
|
+
return 0;
|
|
59
|
+
},
|
|
60
|
+
serve: () => serve(process.argv.slice(3)),
|
|
61
|
+
service: () => service(process.argv.slice(3)),
|
|
62
|
+
stop: stopDaemon,
|
|
63
|
+
tail: () => tailEvents(process.argv.slice(3)),
|
|
64
|
+
claude: () => launchClaude(process.argv.slice(3)),
|
|
65
|
+
update: () => update(process.argv.slice(3)),
|
|
66
|
+
version: async () => {
|
|
67
|
+
process.stdout.write(`${currentVersion()}\n`);
|
|
68
|
+
return Promise.resolve(0);
|
|
69
|
+
},
|
|
532
70
|
};
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
// nginx convention where the daemon's the default).
|
|
547
|
-
if (!cmd) {
|
|
548
|
-
await import('./tail.js');
|
|
549
|
-
return;
|
|
550
|
-
}
|
|
551
|
-
const handler = COMMANDS[cmd];
|
|
552
|
-
if (!handler) {
|
|
553
|
-
process.stderr.write(`unknown command '${cmd}'\n\n${USAGE}`);
|
|
554
|
-
process.exit(1);
|
|
555
|
-
}
|
|
556
|
-
const { positional, flags } = parseArgs(process.argv.slice(3));
|
|
557
|
-
if (NEEDS_ENV.has(cmd))
|
|
558
|
-
loadMetroEnv();
|
|
559
|
-
try {
|
|
560
|
-
await handler(positional, flags);
|
|
561
|
-
}
|
|
562
|
-
catch (err) {
|
|
563
|
-
const code = err.code;
|
|
564
|
-
if (isJson(flags)) {
|
|
565
|
-
process.stdout.write(JSON.stringify({ ok: false, error: errMsg(err), code: code ?? 1 }) + '\n');
|
|
566
|
-
}
|
|
567
|
-
else {
|
|
568
|
-
process.stderr.write(`error: ${errMsg(err)}\n`);
|
|
569
|
-
}
|
|
570
|
-
process.exit(typeof code === 'number' ? code : 1);
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
await main();
|
|
71
|
+
async function run(command) {
|
|
72
|
+
const handler = command === undefined ? undefined : COMMANDS[command];
|
|
73
|
+
if (handler !== undefined)
|
|
74
|
+
return handler();
|
|
75
|
+
process.stderr.write(USAGE);
|
|
76
|
+
return Promise.resolve(HELP.has(command) ? 0 : 1);
|
|
77
|
+
}
|
|
78
|
+
const code = await run(process.argv[2]).catch((err) => {
|
|
79
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
80
|
+
process.stderr.write(`metro: ${message}\n`);
|
|
81
|
+
return 1;
|
|
82
|
+
});
|
|
83
|
+
process.exit(code);
|