@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
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export { emit, respond, mintId } from '@metro-labs/core/stations/station-runtime';
|
|
2
|
+
|
|
3
|
+
const UID_MAP_MAX = 5000;
|
|
4
|
+
const uidToXmtp = new Map<string, string>();
|
|
5
|
+
|
|
6
|
+
const INBOX_ETH_CACHE_MAX = 5000;
|
|
7
|
+
export const inboxEthCache = new Map<string, string>();
|
|
8
|
+
|
|
9
|
+
export function cacheInboxEth(inboxId: string, eth: string): void {
|
|
10
|
+
inboxEthCache.set(inboxId, eth);
|
|
11
|
+
if (inboxEthCache.size > INBOX_ETH_CACHE_MAX) {
|
|
12
|
+
const oldest = inboxEthCache.keys().next().value;
|
|
13
|
+
if (oldest !== undefined) inboxEthCache.delete(oldest);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function rememberUid(
|
|
18
|
+
uid: string | undefined,
|
|
19
|
+
xmtpId: string | undefined,
|
|
20
|
+
): void {
|
|
21
|
+
if (!uid || !xmtpId || !uid.startsWith('msg_')) return;
|
|
22
|
+
uidToXmtp.set(uid, xmtpId);
|
|
23
|
+
if (uidToXmtp.size > UID_MAP_MAX) {
|
|
24
|
+
const oldest = uidToXmtp.keys().next().value;
|
|
25
|
+
if (oldest !== undefined) uidToXmtp.delete(oldest);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function resolveMsgId(rawId: string): string {
|
|
30
|
+
if (!rawId.startsWith('msg_')) return rawId;
|
|
31
|
+
const mapped = uidToXmtp.get(rawId);
|
|
32
|
+
if (mapped) return mapped;
|
|
33
|
+
throw new Error(
|
|
34
|
+
`could not resolve universal id ${rawId} to an xmtp message id ` +
|
|
35
|
+
'(not seen by this train; pass the raw xmtp message_id)',
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const SENT_MAX = 5000;
|
|
40
|
+
const sentIds = new Set<string>();
|
|
41
|
+
|
|
42
|
+
export function rememberSent(xmtpId: string | undefined): void {
|
|
43
|
+
if (!xmtpId) return;
|
|
44
|
+
sentIds.add(xmtpId);
|
|
45
|
+
if (sentIds.size > SENT_MAX) {
|
|
46
|
+
const oldest = sentIds.values().next().value;
|
|
47
|
+
if (oldest !== undefined) sentIds.delete(oldest);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const sentByMe = (xmtpId: string): boolean => sentIds.has(xmtpId);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import './node_modules/@metro-labs/daemon/src/server.ts';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"core": {
|
|
3
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
4
|
+
"pino": "^9.5.0",
|
|
5
|
+
"pino-pretty": "^13.1.3",
|
|
6
|
+
"ws": "^8.18.0",
|
|
7
|
+
"zod": "^3.23.8"
|
|
8
|
+
},
|
|
9
|
+
"stations": {
|
|
10
|
+
"xmtp": {
|
|
11
|
+
"@xmtp/content-type-primitives": "^3.0.1",
|
|
12
|
+
"@xmtp/content-type-reaction": "^2.0.2",
|
|
13
|
+
"@xmtp/content-type-remote-attachment": "^2.0.4",
|
|
14
|
+
"@xmtp/content-type-reply": "^2.0.3",
|
|
15
|
+
"@xmtp/node-bindings": "1.9.1",
|
|
16
|
+
"@xmtp/node-sdk": "^6.0.0",
|
|
17
|
+
"@zerodev/ecdsa-validator": "5.4.9",
|
|
18
|
+
"@zerodev/sdk": "5.5.10",
|
|
19
|
+
"viem": "^2.52.2"
|
|
20
|
+
},
|
|
21
|
+
"telegram-bot": {},
|
|
22
|
+
"telegram": {
|
|
23
|
+
"@mtcute/bun": "0.30.1"
|
|
24
|
+
},
|
|
25
|
+
"discord-bot": {
|
|
26
|
+
"discord.js": "^14.26.4"
|
|
27
|
+
},
|
|
28
|
+
"whatsapp": {
|
|
29
|
+
"baileys": "7.0.0-rc14"
|
|
30
|
+
},
|
|
31
|
+
"threema": {
|
|
32
|
+
"tweetnacl": "^1.0.3"
|
|
33
|
+
},
|
|
34
|
+
"outlook": {},
|
|
35
|
+
"webhook": {}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
File without changes
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Stage Labs
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
package/README.md
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
# Metro
|
|
2
|
-
|
|
3
|
-
Chat with your Claude Code or Codex agent over Telegram and Discord.
|
|
4
|
-
|
|
5
|
-
## Quickstart
|
|
6
|
-
|
|
7
|
-
In your shell:
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npm install -g @stage-labs/metro@beta # or: bun add -g @stage-labs/metro@beta
|
|
11
|
-
|
|
12
|
-
metro setup telegram <token> # https://t.me/BotFather
|
|
13
|
-
metro setup discord <token> # https://discord.com/developers/applications
|
|
14
|
-
|
|
15
|
-
metro setup skill # writes SKILL.md so Claude Code + Codex auto-onboard
|
|
16
|
-
metro doctor # verify
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
> **Discord setup:** toggle **Message Content Intent** in Developer Portal → Bot → Privileged Gateway Intents.
|
|
20
|
-
|
|
21
|
-
### Run with Claude Code
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
claude
|
|
25
|
-
> Run metro in the background.
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
Then DM your bot. The bundled skill auto-triggers — the agent launches metro via Bash + Monitor, watches stdout, and replies.
|
|
29
|
-
|
|
30
|
-
### Run with Codex
|
|
31
|
-
|
|
32
|
-
Codex's `unified_exec` is poll-only ([#4751](https://github.com/openai/codex/issues/4751)) — there's no Monitor equivalent. Metro instead pushes each inbound into the agent's history via JSON-RPC. Two terminals plus a prompt — the TUI's `--remote` flag only accepts `ws://`, so daemon and TUI share one URL:
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
# Terminal 1 — daemon (must be running first)
|
|
36
|
-
codex app-server --listen ws://127.0.0.1:8421
|
|
37
|
-
|
|
38
|
-
# Terminal 2 — TUI attached to the daemon
|
|
39
|
-
codex --remote ws://127.0.0.1:8421
|
|
40
|
-
> Run metro in the background.
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
The agent launches `metro` (with `METRO_CODEX_RC=ws://127.0.0.1:8421` set) via its shell tool. Metro connects to the daemon and pushes each inbound as a `turn/start` on the active thread — the agent in terminal 2 reacts on its next turn. `codex remote-control` is stdio-only (no listener), so don't use it for this flow.
|
|
44
|
-
|
|
45
|
-
Bare `codex` (no `--remote`) can't work with metro — the agent has no daemon to push to. The TUI must be attached to a running app-server.
|
|
46
|
-
|
|
47
|
-
`METRO_CODEX_RC` accepts `ws://host:port` (required for use with the codex TUI) or `unix:///abs/path` (headless only — the daemon supports UDS but the TUI doesn't).
|
|
48
|
-
|
|
49
|
-
## Config
|
|
50
|
-
|
|
51
|
-
| Variable | Default | Description |
|
|
52
|
-
|---|---|---|
|
|
53
|
-
| `TELEGRAM_BOT_TOKEN`, `DISCORD_BOT_TOKEN` | — | Bot tokens. `metro setup` writes them here. |
|
|
54
|
-
| `METRO_CONFIG_DIR` | `~/.config/metro` | Where the global `.env` lives. |
|
|
55
|
-
| `METRO_STATE_DIR` | `~/.cache/metro` | Lockfile, attachment cache, default download dir. |
|
|
56
|
-
| `METRO_LOG_LEVEL` | `info` | `trace` / `debug` / `info` / `warn` / `error` / `fatal`. |
|
|
57
|
-
| `METRO_CODEX_RC` | — | Codex app-server URL (e.g. `ws://127.0.0.1:8421`). When set, metro pushes each inbound into the agent's history via JSON-RPC `turn/start` — the Codex equivalent of Claude Code's Monitor. Accepts `ws://host:port` (required for use with the codex TUI) or `unix:///abs/path` (headless only). See [Codex setup](#codex-setup). |
|
|
58
|
-
|
|
59
|
-
Token precedence: process env → `./.env` → `$METRO_CONFIG_DIR/.env`. Logs to stderr.
|
|
60
|
-
|
|
61
|
-
## Reference
|
|
62
|
-
|
|
63
|
-
- `metro --help` — command surface
|
|
64
|
-
- `metro doctor` — health check
|
|
65
|
-
- [SKILL.md](skills/metro/SKILL.md) — agent-facing flow
|
|
66
|
-
|
|
67
|
-
## Uninstall
|
|
68
|
-
|
|
69
|
-
```bash
|
|
70
|
-
metro setup clear; metro setup skill --clear
|
|
71
|
-
rm -rf ~/.cache/metro/
|
|
72
|
-
npm uninstall -g @stage-labs/metro
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## Caveats
|
|
76
|
-
|
|
77
|
-
- **No allowlist.** Anyone who can DM your bot or @-mention it can talk to your session. Run against bots you own.
|
|
78
|
-
- **Latency.** Inbounds surface at the next agent decision boundary — sub-second on Claude Code, longer on Codex turns.
|
package/dist/channels/discord.js
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { Client, Events, GatewayIntentBits, Partials } from 'discord.js';
|
|
2
|
-
import { errMsg, log } from '../log.js';
|
|
3
|
-
// Receive path: discord.js gateway, used by tail.ts only.
|
|
4
|
-
// Send path: raw REST against discord.com/api — no gateway login required,
|
|
5
|
-
// so cli.ts subcommands stay one-shot and fast.
|
|
6
|
-
const API_BASE = 'https://discord.com/api/v10';
|
|
7
|
-
function token() {
|
|
8
|
-
const t = process.env.DISCORD_BOT_TOKEN;
|
|
9
|
-
if (!t)
|
|
10
|
-
throw new Error('DISCORD_BOT_TOKEN is not set');
|
|
11
|
-
return t;
|
|
12
|
-
}
|
|
13
|
-
async function rest(method, path, body, timeoutMs = 30_000) {
|
|
14
|
-
const res = await fetch(`${API_BASE}${path}`, {
|
|
15
|
-
method,
|
|
16
|
-
headers: {
|
|
17
|
-
'Authorization': `Bot ${token()}`,
|
|
18
|
-
'User-Agent': 'metro (https://github.com/bonustrack/metro, dev)',
|
|
19
|
-
...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),
|
|
20
|
-
},
|
|
21
|
-
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
22
|
-
signal: AbortSignal.timeout(timeoutMs),
|
|
23
|
-
});
|
|
24
|
-
if (!res.ok) {
|
|
25
|
-
const text = await res.text().catch(() => '');
|
|
26
|
-
throw new Error(`discord ${method} ${path}: ${res.status} ${text}`);
|
|
27
|
-
}
|
|
28
|
-
// 204 No Content for typing/reactions/clear.
|
|
29
|
-
if (res.status === 204)
|
|
30
|
-
return undefined;
|
|
31
|
-
return (await res.json());
|
|
32
|
-
}
|
|
33
|
-
// ---------- Receive path (gateway, discord.js) -----------------------------
|
|
34
|
-
let client = null;
|
|
35
|
-
function getClient() {
|
|
36
|
-
if (client)
|
|
37
|
-
return client;
|
|
38
|
-
client = new Client({
|
|
39
|
-
intents: [
|
|
40
|
-
GatewayIntentBits.DirectMessages,
|
|
41
|
-
GatewayIntentBits.Guilds,
|
|
42
|
-
GatewayIntentBits.GuildMessages,
|
|
43
|
-
GatewayIntentBits.MessageContent,
|
|
44
|
-
],
|
|
45
|
-
// DM channels arrive partial; without this messageCreate never fires.
|
|
46
|
-
partials: [Partials.Channel],
|
|
47
|
-
});
|
|
48
|
-
return client;
|
|
49
|
-
}
|
|
50
|
-
let onInboundHandler = () => { };
|
|
51
|
-
export function onInbound(handler) {
|
|
52
|
-
onInboundHandler = handler;
|
|
53
|
-
}
|
|
54
|
-
export async function shutdownGateway() {
|
|
55
|
-
if (!client)
|
|
56
|
-
return;
|
|
57
|
-
await client.destroy();
|
|
58
|
-
client = null;
|
|
59
|
-
}
|
|
60
|
-
export async function startGateway() {
|
|
61
|
-
const c = getClient();
|
|
62
|
-
c.on(Events.MessageCreate, m => {
|
|
63
|
-
if (m.author.bot)
|
|
64
|
-
return;
|
|
65
|
-
// Guild messages: only forward when the bot is mentioned. DMs always pass.
|
|
66
|
-
// The bot's own @-mention is preserved in `m.content` — stripping it would
|
|
67
|
-
// lose mid-sentence position ("Wdyt @Metro is this good?" → "Wdyt is this
|
|
68
|
-
// good?") and silently drop bare-mention pings. The agent recognizes
|
|
69
|
-
// `<@bot_id>` and acts on the request as a whole.
|
|
70
|
-
if (m.guildId && c.user && !m.mentions.has(c.user.id))
|
|
71
|
-
return;
|
|
72
|
-
const tags = [...m.attachments.values()]
|
|
73
|
-
.map(a => {
|
|
74
|
-
if (a.contentType?.startsWith('image/'))
|
|
75
|
-
return '[image]';
|
|
76
|
-
if (a.contentType?.startsWith('audio/'))
|
|
77
|
-
return `[audio: ${a.name}]`;
|
|
78
|
-
return `[file: ${a.name}]`;
|
|
79
|
-
})
|
|
80
|
-
.join(' ');
|
|
81
|
-
const text = [m.content, tags].filter(Boolean).join(' ').trim();
|
|
82
|
-
if (!text)
|
|
83
|
-
return;
|
|
84
|
-
onInboundHandler({ channel_id: m.channelId, message_id: m.id, text });
|
|
85
|
-
});
|
|
86
|
-
c.on(Events.Error, err => log.error({ err: errMsg(err) }, 'discord error'));
|
|
87
|
-
await c.login(process.env.DISCORD_BOT_TOKEN);
|
|
88
|
-
await new Promise(r => c.once(Events.ClientReady, () => r()));
|
|
89
|
-
}
|
|
90
|
-
export async function getMe() {
|
|
91
|
-
const me = await rest('GET', '/users/@me');
|
|
92
|
-
return { username: me.username };
|
|
93
|
-
}
|
|
94
|
-
export async function sendMessage(channelId, text) {
|
|
95
|
-
const sent = await rest('POST', `/channels/${channelId}/messages`, { content: text });
|
|
96
|
-
return sent.id;
|
|
97
|
-
}
|
|
98
|
-
export async function replyToMessage(channelId, messageId, text) {
|
|
99
|
-
const sent = await rest('POST', `/channels/${channelId}/messages`, {
|
|
100
|
-
content: text,
|
|
101
|
-
message_reference: { message_id: messageId, fail_if_not_exists: false },
|
|
102
|
-
});
|
|
103
|
-
return sent.id;
|
|
104
|
-
}
|
|
105
|
-
export async function editMessage(channelId, messageId, text) {
|
|
106
|
-
const sent = await rest('PATCH', `/channels/${channelId}/messages/${messageId}`, { content: text });
|
|
107
|
-
return sent.id;
|
|
108
|
-
}
|
|
109
|
-
export async function sendTyping(channelId) {
|
|
110
|
-
await rest('POST', `/channels/${channelId}/typing`);
|
|
111
|
-
}
|
|
112
|
-
export async function setReaction(channelId, messageId, emoji) {
|
|
113
|
-
if (emoji) {
|
|
114
|
-
await rest('PUT', `/channels/${channelId}/messages/${messageId}/reactions/${encodeURIComponent(emoji)}/@me`);
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
// Clear only the bot's own reactions (matches Telegram's clear semantics).
|
|
118
|
-
const msg = await rest('GET', `/channels/${channelId}/messages/${messageId}`);
|
|
119
|
-
for (const r of msg.reactions ?? []) {
|
|
120
|
-
if (!r.me || !r.emoji.name)
|
|
121
|
-
continue;
|
|
122
|
-
await rest('DELETE', `/channels/${channelId}/messages/${messageId}/reactions/${encodeURIComponent(r.emoji.name)}/@me`);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
export async function fetchAttachments(channelId, messageId) {
|
|
126
|
-
const msg = await rest('GET', `/channels/${channelId}/messages/${messageId}`);
|
|
127
|
-
const out = [];
|
|
128
|
-
for (const a of msg.attachments) {
|
|
129
|
-
if (!a.content_type?.startsWith('image/'))
|
|
130
|
-
continue;
|
|
131
|
-
const res = await fetch(a.url, { signal: AbortSignal.timeout(30_000) });
|
|
132
|
-
if (!res.ok)
|
|
133
|
-
throw new Error(`discord: download ${a.url}: ${res.status}`);
|
|
134
|
-
out.push({ data: Buffer.from(await res.arrayBuffer()).toString('base64'), mime: a.content_type });
|
|
135
|
-
}
|
|
136
|
-
return out;
|
|
137
|
-
}
|
|
138
|
-
export async function fetchRecentMessages(channelId, limit) {
|
|
139
|
-
const n = Math.min(Math.max(limit, 1), 100);
|
|
140
|
-
const msgs = await rest('GET', `/channels/${channelId}/messages?limit=${n}`);
|
|
141
|
-
// Discord returns newest-first; reverse for chronological.
|
|
142
|
-
return [...msgs].reverse().map(m => ({
|
|
143
|
-
message_id: m.id,
|
|
144
|
-
author: m.author.username,
|
|
145
|
-
text: m.content,
|
|
146
|
-
timestamp: m.timestamp,
|
|
147
|
-
}));
|
|
148
|
-
}
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import { STATE_DIR } from '../paths.js';
|
|
4
|
-
import { errMsg, log } from '../log.js';
|
|
5
|
-
const API_BASE = 'https://api.telegram.org';
|
|
6
|
-
function token() {
|
|
7
|
-
const t = process.env.TELEGRAM_BOT_TOKEN;
|
|
8
|
-
if (!t)
|
|
9
|
-
throw new Error('TELEGRAM_BOT_TOKEN is not set');
|
|
10
|
-
return t;
|
|
11
|
-
}
|
|
12
|
-
export async function tg(method, body, timeoutMs = 30_000) {
|
|
13
|
-
const res = await fetch(`${API_BASE}/bot${token()}/${method}`, {
|
|
14
|
-
method: 'POST',
|
|
15
|
-
headers: { 'Content-Type': 'application/json' },
|
|
16
|
-
body: JSON.stringify(body),
|
|
17
|
-
signal: AbortSignal.timeout(timeoutMs),
|
|
18
|
-
});
|
|
19
|
-
const json = (await res.json());
|
|
20
|
-
if (!json.ok)
|
|
21
|
-
throw new Error(`telegram ${method}: ${json.description ?? 'unknown error'}`);
|
|
22
|
-
return json.result;
|
|
23
|
-
}
|
|
24
|
-
export function buildSendBody(chatId, text, opts) {
|
|
25
|
-
const body = { chat_id: chatId, text };
|
|
26
|
-
if (opts.parseMode)
|
|
27
|
-
body.parse_mode = opts.parseMode;
|
|
28
|
-
if (opts.disableLinkPreview)
|
|
29
|
-
body.link_preview_options = { is_disabled: true };
|
|
30
|
-
if (opts.buttons?.length)
|
|
31
|
-
body.reply_markup = { inline_keyboard: opts.buttons };
|
|
32
|
-
return body;
|
|
33
|
-
}
|
|
34
|
-
export async function getMe() {
|
|
35
|
-
return tg('getMe', {});
|
|
36
|
-
}
|
|
37
|
-
const CACHE_MAX = 200;
|
|
38
|
-
const cacheFile = join(STATE_DIR, 'telegram-attachments.json');
|
|
39
|
-
function readCache() {
|
|
40
|
-
try {
|
|
41
|
-
return existsSync(cacheFile) ? JSON.parse(readFileSync(cacheFile, 'utf8')) : {};
|
|
42
|
-
}
|
|
43
|
-
catch (err) {
|
|
44
|
-
log.warn({ err: errMsg(err) }, 'telegram attachment cache read failed');
|
|
45
|
-
return {};
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
function cacheAttachment(chatId, messageId, att) {
|
|
49
|
-
try {
|
|
50
|
-
const data = readCache();
|
|
51
|
-
const key = `${chatId}:${messageId}`;
|
|
52
|
-
data[key] = [...(data[key] ?? []), att];
|
|
53
|
-
const keys = Object.keys(data);
|
|
54
|
-
for (const stale of keys.slice(0, Math.max(0, keys.length - CACHE_MAX)))
|
|
55
|
-
delete data[stale];
|
|
56
|
-
writeFileSync(cacheFile, JSON.stringify(data, null, 2));
|
|
57
|
-
}
|
|
58
|
-
catch (err) {
|
|
59
|
-
log.warn({ err: errMsg(err) }, 'telegram attachment cache write failed');
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
export function getCachedAttachments(chatId, messageId) {
|
|
63
|
-
return readCache()[`${chatId}:${messageId}`] ?? [];
|
|
64
|
-
}
|
|
65
|
-
export async function downloadAttachment(fileId, mime) {
|
|
66
|
-
const file = await tg('getFile', { file_id: fileId });
|
|
67
|
-
const res = await fetch(`${API_BASE}/file/bot${token()}/${file.file_path}`, {
|
|
68
|
-
signal: AbortSignal.timeout(30_000),
|
|
69
|
-
});
|
|
70
|
-
if (!res.ok)
|
|
71
|
-
throw new Error(`download failed: ${res.status}`);
|
|
72
|
-
const buf = Buffer.from(await res.arrayBuffer());
|
|
73
|
-
// Trust the cached mime — it's the authoritative one from the message
|
|
74
|
-
// metadata (`image/jpeg` for photos, the document's mime_type for files).
|
|
75
|
-
// The Telegram CDN often returns `application/octet-stream` as Content-Type,
|
|
76
|
-
// which would otherwise wipe out our extension classification downstream.
|
|
77
|
-
return { data: buf.toString('base64'), mime };
|
|
78
|
-
}
|
|
79
|
-
async function messageToText(m, chatId) {
|
|
80
|
-
if (m.text)
|
|
81
|
-
return m.text;
|
|
82
|
-
const caption = m.caption ?? '';
|
|
83
|
-
if (m.photo?.length) {
|
|
84
|
-
const photo = m.photo[m.photo.length - 1];
|
|
85
|
-
cacheAttachment(chatId, m.message_id, { file_id: photo.file_id, mime: 'image/jpeg' });
|
|
86
|
-
return [caption, '[image]'].filter(Boolean).join(' ');
|
|
87
|
-
}
|
|
88
|
-
if (m.document?.mime_type?.startsWith('image/')) {
|
|
89
|
-
cacheAttachment(chatId, m.message_id, { file_id: m.document.file_id, mime: m.document.mime_type });
|
|
90
|
-
return [caption, '[image]'].filter(Boolean).join(' ');
|
|
91
|
-
}
|
|
92
|
-
if (m.voice)
|
|
93
|
-
return [caption, '[voice]'].filter(Boolean).join(' ');
|
|
94
|
-
if (m.audio)
|
|
95
|
-
return [caption, '[audio]'].filter(Boolean).join(' ');
|
|
96
|
-
return caption || null;
|
|
97
|
-
}
|
|
98
|
-
let onInboundHandler = () => { };
|
|
99
|
-
export function onInbound(handler) {
|
|
100
|
-
onInboundHandler = handler;
|
|
101
|
-
}
|
|
102
|
-
export async function startPolling() {
|
|
103
|
-
// A registered webhook short-circuits getUpdates — clear it defensively.
|
|
104
|
-
await tg('deleteWebhook', { drop_pending_updates: false }).catch(() => { });
|
|
105
|
-
let offset = 0;
|
|
106
|
-
const initial = await tg('getUpdates', { timeout: 0 });
|
|
107
|
-
if (initial.length)
|
|
108
|
-
offset = initial[initial.length - 1].update_id + 1;
|
|
109
|
-
while (true) {
|
|
110
|
-
try {
|
|
111
|
-
const updates = await tg('getUpdates', { offset, timeout: 50 }, 60_000);
|
|
112
|
-
for (const u of updates) {
|
|
113
|
-
offset = u.update_id + 1;
|
|
114
|
-
void dispatchUpdate(u);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
catch (err) {
|
|
118
|
-
log.error({ err: errMsg(err) }, 'telegram poll error');
|
|
119
|
-
await new Promise(r => setTimeout(r, 1000));
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
async function dispatchUpdate(u) {
|
|
124
|
-
const m = u.message;
|
|
125
|
-
if (!m?.chat?.id || typeof m.message_id !== 'number')
|
|
126
|
-
return;
|
|
127
|
-
const base = { chat_id: m.chat.id, message_id: m.message_id };
|
|
128
|
-
try {
|
|
129
|
-
const text = await messageToText(m, m.chat.id);
|
|
130
|
-
if (text === null)
|
|
131
|
-
return;
|
|
132
|
-
onInboundHandler({ ...base, text });
|
|
133
|
-
}
|
|
134
|
-
catch (err) {
|
|
135
|
-
onInboundHandler({ ...base, text: `[message processing failed: ${errMsg(err)}]` });
|
|
136
|
-
}
|
|
137
|
-
}
|
package/dist/lib/address.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// `<platform>:<chat>[/<message_id>]` — the wire format of every metro
|
|
2
|
-
// inbound `to` field, and the only address shape any subcommand accepts.
|
|
3
|
-
export function parseAddress(to, requireMessage) {
|
|
4
|
-
const colon = to.indexOf(':');
|
|
5
|
-
if (colon === -1) {
|
|
6
|
-
throw new Error(`invalid --to (expected '<platform>:<chat>[/<message_id>]'): ${to}`);
|
|
7
|
-
}
|
|
8
|
-
const platform = to.slice(0, colon);
|
|
9
|
-
if (platform !== 'telegram' && platform !== 'discord') {
|
|
10
|
-
throw new Error(`unknown platform '${platform}' in --to (expected 'telegram' or 'discord')`);
|
|
11
|
-
}
|
|
12
|
-
const rest = to.slice(colon + 1);
|
|
13
|
-
const slash = rest.indexOf('/');
|
|
14
|
-
const chat = slash === -1 ? rest : rest.slice(0, slash);
|
|
15
|
-
const messageId = slash === -1 ? undefined : rest.slice(slash + 1);
|
|
16
|
-
if (!chat)
|
|
17
|
-
throw new Error(`empty chat/channel id in --to: ${to}`);
|
|
18
|
-
if (requireMessage && !messageId)
|
|
19
|
-
throw new Error(`--to must include /<message_id>: ${to}`);
|
|
20
|
-
return { platform, chat, messageId };
|
|
21
|
-
}
|