@stage-labs/metro 0.1.0-beta.15 → 0.1.0-beta.151
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +9 -0
- package/dist/claude-settings.js +40 -0
- package/dist/claude.js +182 -0
- package/dist/cli.js +86 -0
- package/dist/control.js +74 -0
- package/dist/hold.js +211 -0
- package/dist/local.js +77 -0
- package/dist/mcp-config.js +25 -0
- package/dist/node-name.js +71 -0
- package/dist/onboarding.js +43 -0
- package/dist/provider-flags.js +9 -0
- package/dist/route.js +50 -0
- package/dist/runtime-install.js +97 -0
- package/dist/runtime.js +74 -0
- package/dist/serve.js +155 -0
- package/dist/service.js +242 -0
- package/dist/tail.js +119 -0
- package/dist/update.js +45 -0
- package/dist/version.js +97 -0
- package/package.json +14 -28
- package/runtime/marketplace/.claude-plugin/marketplace.json +12 -0
- package/runtime/marketplace/plugin/.claude-plugin/plugin.json +18 -0
- package/runtime/marketplace/plugin/.mcp.json +1 -0
- package/runtime/marketplace/plugin/bin/guard.mjs +55 -0
- package/runtime/marketplace/plugin/bin/metro-plugin.mjs +40 -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 +16 -0
- package/runtime/node_modules/@metro-labs/core/package.json +43 -0
- package/runtime/node_modules/@metro-labs/core/src/address.ts +6 -0
- package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
- package/runtime/node_modules/@metro-labs/core/src/events.ts +120 -0
- package/runtime/node_modules/@metro-labs/core/src/identity.ts +7 -0
- package/runtime/node_modules/@metro-labs/core/src/ids.ts +21 -0
- package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
- package/runtime/node_modules/@metro-labs/core/src/lines.ts +87 -0
- package/runtime/node_modules/@metro-labs/core/src/log.ts +42 -0
- package/runtime/node_modules/@metro-labs/core/src/protocol.ts +226 -0
- package/runtime/node_modules/@metro-labs/core/src/secure-fs.ts +57 -0
- package/runtime/node_modules/@metro-labs/core/src/station-names.ts +13 -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/station-runtime.ts +64 -0
- package/runtime/node_modules/@metro-labs/core/src/stations/types.ts +108 -0
- package/runtime/node_modules/@metro-labs/core/src/str.ts +5 -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 +47 -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-routes.ts +70 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +365 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +39 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/allowlist.ts +37 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +225 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +122 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +364 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +185 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/keys.ts +40 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/map.ts +95 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/scope.ts +64 -0
- package/runtime/node_modules/@metro-labs/daemon/src/agents/senders.ts +38 -0
- package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +200 -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 +30 -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 +25 -0
- package/runtime/node_modules/@metro-labs/daemon/src/channels/dedupe.ts +24 -0
- package/runtime/node_modules/@metro-labs/daemon/src/channels/inbound.ts +380 -0
- package/runtime/node_modules/@metro-labs/daemon/src/channels/media-note.ts +85 -0
- package/runtime/node_modules/@metro-labs/daemon/src/channels/pending.ts +75 -0
- package/runtime/node_modules/@metro-labs/daemon/src/channels/relay.ts +129 -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 +354 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +358 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +169 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/onboarding.ts +56 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/plugin-install.ts +140 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/session-files.ts +90 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/session.ts +253 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +117 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +263 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +118 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/version.ts +109 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/api.ts +313 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/config.ts +157 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/health.ts +18 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/model.ts +69 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-client.ts +166 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-discovery.ts +139 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-pending.ts +65 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-routes.ts +171 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth.ts +155 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/plugin-sync.ts +122 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/reach.ts +27 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-target.ts +39 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +304 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +299 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +108 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/url.ts +59 -0
- package/runtime/node_modules/@metro-labs/daemon/src/connectors/verify.ts +101 -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-serve.ts +121 -0
- package/runtime/node_modules/@metro-labs/daemon/src/files/upload-api.ts +294 -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 +259 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +231 -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 +288 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +203 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +231 -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 +187 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +247 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-auth.ts +182 -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 +148 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-translate.ts +201 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini.ts +257 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +353 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +232 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +90 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +65 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +17 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +242 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/accounts.ts +151 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/call-tools.ts +216 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/channel-owner.ts +29 -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 +91 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/frame-scope.ts +21 -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 +186 -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-relay.ts +66 -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/request-identity.ts +47 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-registry.ts +172 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-route.ts +43 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/session.ts +215 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-dispatch.ts +215 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-schemas.ts +400 -0
- package/runtime/node_modules/@metro-labs/daemon/src/mcp/upload-tool.ts +66 -0
- package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +237 -0
- package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +389 -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 +370 -0
- package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +210 -0
- package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +58 -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 +65 -0
- package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +80 -0
- package/runtime/node_modules/@metro-labs/daemon/src/server/owner.ts +48 -0
- package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +117 -0
- package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-inline.ts +100 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-interactive.ts +161 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-resolve.ts +202 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-session.ts +280 -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 +261 -0
- package/runtime/node_modules/@metro-labs/daemon/src/stations/registry.ts +37 -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/terminal/api.ts +97 -0
- package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +123 -0
- package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +40 -0
- package/runtime/node_modules/@metro-labs/discord-bot/package.json +28 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/accounts.ts +118 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +388 -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 +220 -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 +127 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/members.ts +215 -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 +19 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/verify.ts +82 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/voice-speak.ts +195 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/voice-transcribe.ts +292 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/voice.ts +197 -0
- package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +5 -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 +106 -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 +150 -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 +254 -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 +156 -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 +78 -0
- package/runtime/node_modules/@metro-labs/telegram/src/index.ts +46 -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/reactions.ts +167 -0
- package/runtime/node_modules/@metro-labs/telegram/src/station.ts +24 -0
- package/runtime/node_modules/@metro-labs/telegram/src/types.ts +7 -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 +120 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +295 -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 +201 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +109 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +166 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +47 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +17 -0
- package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +58 -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 +3 -0
- package/runtime/node_modules/@metro-labs/threema/package.json +26 -0
- package/runtime/node_modules/@metro-labs/threema/src/accounts.ts +100 -0
- package/runtime/node_modules/@metro-labs/threema/src/actions.ts +223 -0
- package/runtime/node_modules/@metro-labs/threema/src/api.ts +130 -0
- package/runtime/node_modules/@metro-labs/threema/src/crypto.ts +132 -0
- package/runtime/node_modules/@metro-labs/threema/src/format.ts +123 -0
- package/runtime/node_modules/@metro-labs/threema/src/ids.ts +21 -0
- package/runtime/node_modules/@metro-labs/threema/src/index.ts +29 -0
- package/runtime/node_modules/@metro-labs/threema/src/station.ts +10 -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 +190 -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 +347 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/delivery.ts +49 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +138 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +57 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +40 -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/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 +18 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +98 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +6 -0
- package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +5 -0
- package/runtime/node_modules/@metro-labs/xmtp/package.json +33 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +112 -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 +299 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +157 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +87 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +375 -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-core.ts +55 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +335 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +80 -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 +33 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +125 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +157 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +40 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +349 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +13 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +126 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +212 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +90 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +84 -0
- package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +53 -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 -139
- package/dist/broker/claims.js +0 -144
- package/dist/broker/history-stream.js +0 -149
- package/dist/cli/config.js +0 -179
- package/dist/cli/index.js +0 -175
- package/dist/cli/messenger-api.js +0 -214
- package/dist/cli/messenger-transcribe.js +0 -43
- package/dist/cli/messenger-uploads.js +0 -116
- package/dist/cli/monitor-api.js +0 -205
- package/dist/cli/tail.js +0 -95
- package/dist/cli/util.js +0 -72
- package/dist/cli/webhook.js +0 -181
- package/dist/codex-rc/client.js +0 -225
- package/dist/codex-rc/protocol.js +0 -38
- package/dist/dispatcher/server.js +0 -122
- package/dist/dispatcher.js +0 -97
- package/dist/history.js +0 -143
- package/dist/ipc.js +0 -90
- package/dist/lines.js +0 -54
- package/dist/local-identity.js +0 -80
- package/dist/log.js +0 -15
- package/dist/paths.js +0 -114
- package/dist/trains/protocol.js +0 -99
- package/dist/trains/supervisor.js +0 -210
- package/dist/tunnel.js +0 -102
- package/docs/broker.md +0 -166
- package/docs/monitor.md +0 -241
- package/docs/uri-scheme.md +0 -127
- package/examples/README.md +0 -32
- package/examples/telegram.ts +0 -121
- package/skills/metro/SKILL.md +0 -110
package/dist/service.js
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { homedir, platform, userInfo } from 'node:os';
|
|
4
|
+
import { dirname, join, resolve } from 'node:path';
|
|
5
|
+
import { serveLockedBy } from './control.js';
|
|
6
|
+
import { findBun } from './runtime.js';
|
|
7
|
+
import { findTailscale, parseServeArgs, requireOwner } from './serve.js';
|
|
8
|
+
const USAGE = 'usage: metro service install [--port <n>] [--owner <address>] | uninstall | status';
|
|
9
|
+
const SERVICE = 'metro';
|
|
10
|
+
const LABEL = 'box.metro.serve';
|
|
11
|
+
const CARRIED = /^(METRO_.*|XDG_CACHE_HOME|PATH|HOME)$/;
|
|
12
|
+
const PLAIN_WORD = /^[A-Za-z0-9_/.:=+@,-]+$/;
|
|
13
|
+
const carriedEnv = (env) => Object.entries(env)
|
|
14
|
+
.filter((entry) => CARRIED.test(entry[0]) && typeof entry[1] === 'string' && entry[1] !== '')
|
|
15
|
+
.sort(([a], [b]) => a.localeCompare(b));
|
|
16
|
+
const cacheDir = (host) => {
|
|
17
|
+
const xdg = host.env.XDG_CACHE_HOME?.trim();
|
|
18
|
+
return xdg === undefined || xdg === '' ? join(host.home, '.cache') : xdg;
|
|
19
|
+
};
|
|
20
|
+
function unitWord(arg) {
|
|
21
|
+
const escaped = arg.replaceAll('%', '%%');
|
|
22
|
+
if (PLAIN_WORD.test(arg))
|
|
23
|
+
return escaped;
|
|
24
|
+
return `"${escaped.replaceAll('\\', '\\\\').replaceAll('"', '\\"')}"`;
|
|
25
|
+
}
|
|
26
|
+
export function systemdUnit(host, exec, target) {
|
|
27
|
+
const env = carriedEnv(host.env).map(([key, value]) => `Environment=${unitWord(`${key}=${value}`)}`);
|
|
28
|
+
return [
|
|
29
|
+
'[Unit]',
|
|
30
|
+
'Description=Metro daemon (metro serve)',
|
|
31
|
+
'After=network-online.target tailscaled.service',
|
|
32
|
+
'Wants=network-online.target',
|
|
33
|
+
'',
|
|
34
|
+
'[Service]',
|
|
35
|
+
`ExecStart=${exec.map(unitWord).join(' ')}`,
|
|
36
|
+
'Restart=always',
|
|
37
|
+
'RestartSec=2',
|
|
38
|
+
`WorkingDirectory=${unitWord(host.home)}`,
|
|
39
|
+
...env,
|
|
40
|
+
'',
|
|
41
|
+
'[Install]',
|
|
42
|
+
`WantedBy=${target}`,
|
|
43
|
+
'',
|
|
44
|
+
].join('\n');
|
|
45
|
+
}
|
|
46
|
+
const xml = (text) => text
|
|
47
|
+
.replaceAll('&', '&')
|
|
48
|
+
.replaceAll('<', '<')
|
|
49
|
+
.replaceAll('>', '>')
|
|
50
|
+
.replaceAll('"', '"')
|
|
51
|
+
.replaceAll("'", ''');
|
|
52
|
+
export function launchdPlist(host, exec, logFile) {
|
|
53
|
+
const env = carriedEnv(host.env).map(([key, value]) => ` <key>${xml(key)}</key><string>${xml(value)}</string>`);
|
|
54
|
+
return [
|
|
55
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
56
|
+
'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">',
|
|
57
|
+
'<plist version="1.0">',
|
|
58
|
+
'<dict>',
|
|
59
|
+
` <key>Label</key><string>${LABEL}</string>`,
|
|
60
|
+
' <key>ProgramArguments</key>',
|
|
61
|
+
' <array>',
|
|
62
|
+
...exec.map((arg) => ` <string>${xml(arg)}</string>`),
|
|
63
|
+
' </array>',
|
|
64
|
+
' <key>EnvironmentVariables</key>',
|
|
65
|
+
' <dict>',
|
|
66
|
+
...env,
|
|
67
|
+
' </dict>',
|
|
68
|
+
` <key>WorkingDirectory</key><string>${xml(host.home)}</string>`,
|
|
69
|
+
' <key>RunAtLoad</key><true/>',
|
|
70
|
+
' <key>KeepAlive</key><true/>',
|
|
71
|
+
` <key>StandardOutPath</key><string>${xml(logFile)}</string>`,
|
|
72
|
+
` <key>StandardErrorPath</key><string>${xml(logFile)}</string>`,
|
|
73
|
+
'</dict>',
|
|
74
|
+
'</plist>',
|
|
75
|
+
'',
|
|
76
|
+
].join('\n');
|
|
77
|
+
}
|
|
78
|
+
function systemdPlan(host, exec) {
|
|
79
|
+
const system = host.uid === 0;
|
|
80
|
+
const ctl = system ? ['systemctl'] : ['systemctl', '--user'];
|
|
81
|
+
const file = system
|
|
82
|
+
? `/etc/systemd/system/${SERVICE}.service`
|
|
83
|
+
: join(host.home, '.config', 'systemd', 'user', `${SERVICE}.service`);
|
|
84
|
+
return {
|
|
85
|
+
kind: 'systemd',
|
|
86
|
+
file,
|
|
87
|
+
content: systemdUnit(host, exec, system ? 'multi-user.target' : 'default.target'),
|
|
88
|
+
dirs: [],
|
|
89
|
+
install: [{ args: [...ctl, 'daemon-reload'] }, { args: [...ctl, 'enable', '--now', SERVICE] }],
|
|
90
|
+
uninstall: [{ args: [...ctl, 'disable', '--now', SERVICE], mayFail: true }],
|
|
91
|
+
reload: [{ args: [...ctl, 'daemon-reload'], mayFail: true }],
|
|
92
|
+
status: { args: [...ctl, 'is-active', SERVICE], mayFail: true },
|
|
93
|
+
hints: [
|
|
94
|
+
`Logs: journalctl ${system ? '' : '--user '}-u ${SERVICE} -f`,
|
|
95
|
+
...(system
|
|
96
|
+
? []
|
|
97
|
+
: [`A user service stops with your login session; keep it up without one: loginctl enable-linger ${host.user}`]),
|
|
98
|
+
],
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function launchdPlan(host, exec) {
|
|
102
|
+
const file = join(host.home, 'Library', 'LaunchAgents', `${LABEL}.plist`);
|
|
103
|
+
const domain = `gui/${String(host.uid)}`;
|
|
104
|
+
const logFile = join(cacheDir(host), 'metro', 'serve', 'service.log');
|
|
105
|
+
return {
|
|
106
|
+
kind: 'launchd',
|
|
107
|
+
file,
|
|
108
|
+
content: launchdPlist(host, exec, logFile),
|
|
109
|
+
dirs: [dirname(logFile)],
|
|
110
|
+
install: [
|
|
111
|
+
{ args: ['launchctl', 'bootout', `${domain}/${LABEL}`], mayFail: true },
|
|
112
|
+
{ args: ['launchctl', 'bootstrap', domain, file] },
|
|
113
|
+
],
|
|
114
|
+
uninstall: [{ args: ['launchctl', 'bootout', `${domain}/${LABEL}`], mayFail: true }],
|
|
115
|
+
reload: [],
|
|
116
|
+
status: { args: ['launchctl', 'print', `${domain}/${LABEL}`], mayFail: true },
|
|
117
|
+
hints: [`Logs: tail -f ${logFile}`],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
export function servicePlan(host, serveArgs) {
|
|
121
|
+
const exec = [host.node, host.cli, 'serve', ...serveArgs];
|
|
122
|
+
if (host.platform === 'linux')
|
|
123
|
+
return systemdPlan(host, exec);
|
|
124
|
+
if (host.platform === 'darwin')
|
|
125
|
+
return launchdPlan(host, exec);
|
|
126
|
+
throw new Error(`metro service supports Linux (systemd) and macOS (launchd), not ${host.platform}`);
|
|
127
|
+
}
|
|
128
|
+
function install(serveArgs, deps) {
|
|
129
|
+
const { owner } = parseServeArgs(serveArgs);
|
|
130
|
+
const plan = servicePlan(deps.host, serveArgs);
|
|
131
|
+
if (deps.exists(plan.file)) {
|
|
132
|
+
deps.out(`metro is already installed as a ${plan.kind} service (${plan.file}) and restarts on its own; metro service status says whether it is running. To change its arguments: metro service uninstall, then install again`);
|
|
133
|
+
return 0;
|
|
134
|
+
}
|
|
135
|
+
deps.preflight(owner);
|
|
136
|
+
const pid = deps.running();
|
|
137
|
+
if (pid !== null)
|
|
138
|
+
throw new Error(`a metro serve is running on this machine (pid ${String(pid)}). Stop it first (metro stop), then install: the service takes over from there`);
|
|
139
|
+
for (const dir of plan.dirs)
|
|
140
|
+
deps.mkdir(dir);
|
|
141
|
+
deps.write(plan.file, plan.content);
|
|
142
|
+
for (const command of plan.install)
|
|
143
|
+
deps.run(command);
|
|
144
|
+
deps.out(`Installed ${plan.file}: metro serve now starts at boot and after a crash, and the Server page on metro.box can stop, start and restart it.`);
|
|
145
|
+
for (const hint of plan.hints)
|
|
146
|
+
deps.out(hint);
|
|
147
|
+
return 0;
|
|
148
|
+
}
|
|
149
|
+
function uninstall(deps) {
|
|
150
|
+
const plan = servicePlan(deps.host, []);
|
|
151
|
+
if (!deps.exists(plan.file)) {
|
|
152
|
+
deps.out('metro is not installed as a service on this machine');
|
|
153
|
+
return 1;
|
|
154
|
+
}
|
|
155
|
+
for (const command of plan.uninstall)
|
|
156
|
+
deps.run(command);
|
|
157
|
+
deps.remove(plan.file);
|
|
158
|
+
for (const command of plan.reload)
|
|
159
|
+
deps.run(command);
|
|
160
|
+
deps.out(`Removed ${plan.file}; a running daemon was stopped, and metro serve no longer starts on its own`);
|
|
161
|
+
return 0;
|
|
162
|
+
}
|
|
163
|
+
function status(deps) {
|
|
164
|
+
const plan = servicePlan(deps.host, []);
|
|
165
|
+
if (!deps.exists(plan.file)) {
|
|
166
|
+
deps.out(`not installed (metro service install writes ${plan.file})`);
|
|
167
|
+
return 1;
|
|
168
|
+
}
|
|
169
|
+
const active = deps.run(plan.status).status === 0;
|
|
170
|
+
deps.out(active
|
|
171
|
+
? `running as a ${plan.kind} service (${plan.file})`
|
|
172
|
+
: `installed as a ${plan.kind} service (${plan.file}), not running`);
|
|
173
|
+
return active ? 0 : 1;
|
|
174
|
+
}
|
|
175
|
+
function realHost() {
|
|
176
|
+
const who = userInfo();
|
|
177
|
+
return {
|
|
178
|
+
platform: platform(),
|
|
179
|
+
uid: who.uid,
|
|
180
|
+
user: who.username,
|
|
181
|
+
home: homedir(),
|
|
182
|
+
node: process.execPath,
|
|
183
|
+
cli: resolve(process.argv[1] ?? ''),
|
|
184
|
+
env: process.env,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
export function serviceStopHint(host = realHost(), exists = existsSync) {
|
|
188
|
+
if (host.platform !== 'linux' && host.platform !== 'darwin')
|
|
189
|
+
return null;
|
|
190
|
+
const plan = servicePlan(host, []);
|
|
191
|
+
if (!exists(plan.file))
|
|
192
|
+
return null;
|
|
193
|
+
const keep = plan.kind === 'systemd'
|
|
194
|
+
? `systemctl ${host.uid === 0 ? '' : '--user '}stop ${SERVICE}`
|
|
195
|
+
: `launchctl bootout gui/${String(host.uid)}/${LABEL}`;
|
|
196
|
+
return `metro runs as a ${plan.kind} service here (${plan.file}), so it starts again on its own in a moment. To keep it stopped: ${keep}`;
|
|
197
|
+
}
|
|
198
|
+
function realDeps() {
|
|
199
|
+
return {
|
|
200
|
+
host: realHost(),
|
|
201
|
+
run: (command) => {
|
|
202
|
+
const [bin = '', ...args] = command.args;
|
|
203
|
+
const result = spawnSync(bin, args, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
|
|
204
|
+
const code = result.status ?? 1;
|
|
205
|
+
if (code !== 0 && command.mayFail !== true) {
|
|
206
|
+
const said = [result.stderr, result.stdout, result.error?.message].find((t) => typeof t === 'string' && t.trim() !== '') ?? '';
|
|
207
|
+
throw new Error(`${command.args.join(' ')} failed (exit ${String(code)}): ${said.trim()}`);
|
|
208
|
+
}
|
|
209
|
+
return { status: code, output: `${result.stdout}${result.stderr}` };
|
|
210
|
+
},
|
|
211
|
+
running: serveLockedBy,
|
|
212
|
+
preflight: (owner) => {
|
|
213
|
+
requireOwner(owner);
|
|
214
|
+
findBun();
|
|
215
|
+
findTailscale();
|
|
216
|
+
},
|
|
217
|
+
mkdir: (dir) => {
|
|
218
|
+
mkdirSync(dir, { recursive: true });
|
|
219
|
+
},
|
|
220
|
+
write: (file, content) => {
|
|
221
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
222
|
+
writeFileSync(file, content, { mode: 0o644 });
|
|
223
|
+
},
|
|
224
|
+
remove: (file) => {
|
|
225
|
+
rmSync(file, { force: true });
|
|
226
|
+
},
|
|
227
|
+
exists: existsSync,
|
|
228
|
+
out: (line) => {
|
|
229
|
+
process.stderr.write(`${line}\n`);
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
export function service(argv, deps = realDeps()) {
|
|
234
|
+
const [verb, ...rest] = argv;
|
|
235
|
+
if (verb === 'install')
|
|
236
|
+
return Promise.resolve(install(rest, deps));
|
|
237
|
+
if (verb === 'uninstall' && rest.length === 0)
|
|
238
|
+
return Promise.resolve(uninstall(deps));
|
|
239
|
+
if (verb === 'status' && rest.length === 0)
|
|
240
|
+
return Promise.resolve(status(deps));
|
|
241
|
+
throw new Error(USAGE);
|
|
242
|
+
}
|
package/dist/tail.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { localAgents } from './local.js';
|
|
2
|
+
import { assertAgentId, localUrl } from './runtime.js';
|
|
3
|
+
const BACKOFF_MS = [1_000, 2_000, 5_000];
|
|
4
|
+
const STALL_MS = 90_000;
|
|
5
|
+
export const backoffAt = (attempt) => BACKOFF_MS[Math.min(attempt, BACKOFF_MS.length - 1)] ?? 5_000;
|
|
6
|
+
export function sseDataLines(buffer, chunk) {
|
|
7
|
+
const lines = (buffer + chunk).split('\n');
|
|
8
|
+
const rest = lines.pop() ?? '';
|
|
9
|
+
const events = [];
|
|
10
|
+
for (const raw of lines) {
|
|
11
|
+
const line = raw.endsWith('\r') ? raw.slice(0, -1) : raw;
|
|
12
|
+
if (!line.startsWith('data:'))
|
|
13
|
+
continue;
|
|
14
|
+
const value = line.slice(5);
|
|
15
|
+
events.push(value.startsWith(' ') ? value.slice(1) : value);
|
|
16
|
+
}
|
|
17
|
+
return { rest, events };
|
|
18
|
+
}
|
|
19
|
+
function keySource(agentId) {
|
|
20
|
+
const fromEnv = process.env.METRO_AGENT_KEY?.trim();
|
|
21
|
+
if (fromEnv !== undefined && fromEnv !== '')
|
|
22
|
+
return { resolve: () => Promise.resolve(fromEnv), fixed: true };
|
|
23
|
+
return {
|
|
24
|
+
resolve: () => {
|
|
25
|
+
const agent = localAgents().find((a) => a.id === agentId);
|
|
26
|
+
if (agent === undefined)
|
|
27
|
+
throw new Error(`no agent ${agentId} on this machine — create or restore it in the web UI of metro serve, or set METRO_AGENT_KEY`);
|
|
28
|
+
return Promise.resolve(agent.key);
|
|
29
|
+
},
|
|
30
|
+
fixed: false,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const armStall = (control) => setTimeout(() => {
|
|
34
|
+
control.abort();
|
|
35
|
+
}, STALL_MS);
|
|
36
|
+
async function connect(key, signal) {
|
|
37
|
+
try {
|
|
38
|
+
return await fetch(`${localUrl()}/api/tail`, {
|
|
39
|
+
headers: { authorization: `Bearer ${key}` },
|
|
40
|
+
signal,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function pump(body, control, stall) {
|
|
48
|
+
const reader = body.getReader();
|
|
49
|
+
const decoder = new TextDecoder();
|
|
50
|
+
let buffer = '';
|
|
51
|
+
try {
|
|
52
|
+
for (;;) {
|
|
53
|
+
const { done, value } = await reader.read();
|
|
54
|
+
if (done)
|
|
55
|
+
return 'ended';
|
|
56
|
+
clearTimeout(stall.timer);
|
|
57
|
+
stall.timer = armStall(control);
|
|
58
|
+
const out = sseDataLines(buffer, decoder.decode(value, { stream: true }));
|
|
59
|
+
buffer = out.rest;
|
|
60
|
+
for (const event of out.events)
|
|
61
|
+
process.stdout.write(`${event}\n`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return 'ended';
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function streamOnce(key) {
|
|
69
|
+
const control = new AbortController();
|
|
70
|
+
const stall = { timer: armStall(control) };
|
|
71
|
+
try {
|
|
72
|
+
const res = await connect(key, control.signal);
|
|
73
|
+
if (res === null)
|
|
74
|
+
return 'unreachable';
|
|
75
|
+
if (res.status === 401)
|
|
76
|
+
return 'unauthorized';
|
|
77
|
+
if (!res.ok || res.body === null)
|
|
78
|
+
return 'unreachable';
|
|
79
|
+
return await pump(res.body, control, stall);
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
clearTimeout(stall.timer);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function note(state, message) {
|
|
86
|
+
if (state.last === message)
|
|
87
|
+
return;
|
|
88
|
+
state.last = message;
|
|
89
|
+
process.stderr.write(`metro: ${message}\n`);
|
|
90
|
+
}
|
|
91
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
92
|
+
async function settle(end, source, key, agentId, state) {
|
|
93
|
+
if (end === 'unauthorized') {
|
|
94
|
+
if (source.fixed)
|
|
95
|
+
throw new Error('the key in METRO_AGENT_KEY was refused by the local daemon');
|
|
96
|
+
note(state, 'key refused — fetching the current one');
|
|
97
|
+
return source.resolve();
|
|
98
|
+
}
|
|
99
|
+
if (end === 'unreachable')
|
|
100
|
+
note(state, `no metro daemon on ${localUrl()} — run 'metro serve' (agent ${agentId})`);
|
|
101
|
+
else
|
|
102
|
+
note(state, 'stream ended — reconnecting');
|
|
103
|
+
return key;
|
|
104
|
+
}
|
|
105
|
+
export async function tailEvents(argv) {
|
|
106
|
+
const agentId = assertAgentId(argv[0]);
|
|
107
|
+
const source = keySource(agentId);
|
|
108
|
+
let key = await source.resolve();
|
|
109
|
+
const state = { last: '' };
|
|
110
|
+
let attempt = 0;
|
|
111
|
+
for (;;) {
|
|
112
|
+
const end = await streamOnce(key);
|
|
113
|
+
if (end === 'ended')
|
|
114
|
+
attempt = 0;
|
|
115
|
+
key = await settle(end, source, key, agentId, state);
|
|
116
|
+
await delay(backoffAt(attempt));
|
|
117
|
+
attempt += 1;
|
|
118
|
+
}
|
|
119
|
+
}
|
package/dist/update.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { currentVersion, isNewer, PACKAGE_NAME, publishedVersion, } from './version.js';
|
|
3
|
+
export function managerFor(location) {
|
|
4
|
+
return location.includes('/.bun/') ? 'bun' : 'npm';
|
|
5
|
+
}
|
|
6
|
+
export function installArgs(manager, version) {
|
|
7
|
+
const spec = `${PACKAGE_NAME}@${version}`;
|
|
8
|
+
return manager === 'bun'
|
|
9
|
+
? ['add', '--global', spec]
|
|
10
|
+
: ['install', '--global', spec];
|
|
11
|
+
}
|
|
12
|
+
export const checkReport = (current, latest) => ({
|
|
13
|
+
current,
|
|
14
|
+
latest,
|
|
15
|
+
newer: latest !== '' && isNewer(latest, current),
|
|
16
|
+
});
|
|
17
|
+
export async function updateCheck() {
|
|
18
|
+
return checkReport(currentVersion(), await publishedVersion());
|
|
19
|
+
}
|
|
20
|
+
export async function update(argv = []) {
|
|
21
|
+
if (argv.includes('--check')) {
|
|
22
|
+
process.stdout.write(`${JSON.stringify(await updateCheck())}\n`);
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
const current = currentVersion();
|
|
26
|
+
const newest = await publishedVersion();
|
|
27
|
+
if (newest === '') {
|
|
28
|
+
process.stderr.write('npm published no version this CLI understands\n');
|
|
29
|
+
return 1;
|
|
30
|
+
}
|
|
31
|
+
if (!isNewer(newest, current)) {
|
|
32
|
+
process.stderr.write(`metro ${current} is the newest published version\n`);
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
const manager = managerFor(import.meta.url);
|
|
36
|
+
const args = installArgs(manager, newest);
|
|
37
|
+
process.stderr.write(`Updating metro ${current} to ${newest} with ${manager}\n`);
|
|
38
|
+
const run = spawnSync(manager, args, { stdio: 'inherit' });
|
|
39
|
+
if (run.error !== undefined || run.status !== 0) {
|
|
40
|
+
process.stderr.write(`That did not work. Run it yourself:\n ${manager} ${args.join(' ')}\n`);
|
|
41
|
+
return 1;
|
|
42
|
+
}
|
|
43
|
+
process.stderr.write(`metro is now ${newest}\n`);
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
export const PACKAGE_NAME = '@stage-labs/metro';
|
|
3
|
+
const REGISTRY = 'https://registry.npmjs.org';
|
|
4
|
+
const TIMEOUT_MS = 15_000;
|
|
5
|
+
export function parseVersion(raw) {
|
|
6
|
+
const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(raw.trim());
|
|
7
|
+
if (match === null)
|
|
8
|
+
return null;
|
|
9
|
+
const core = [match[1], match[2], match[3]].map((n) => Number(n));
|
|
10
|
+
const pre = match[4] === undefined
|
|
11
|
+
? []
|
|
12
|
+
: match[4]
|
|
13
|
+
.split('.')
|
|
14
|
+
.map((part) => (/^\d+$/.test(part) ? Number(part) : part));
|
|
15
|
+
return { core, pre };
|
|
16
|
+
}
|
|
17
|
+
function comparePart(left, right) {
|
|
18
|
+
if (left === undefined)
|
|
19
|
+
return -1;
|
|
20
|
+
if (right === undefined)
|
|
21
|
+
return 1;
|
|
22
|
+
if (left === right)
|
|
23
|
+
return 0;
|
|
24
|
+
if (typeof left === 'number' && typeof right === 'number')
|
|
25
|
+
return left < right ? -1 : 1;
|
|
26
|
+
if (typeof left === 'number')
|
|
27
|
+
return -1;
|
|
28
|
+
if (typeof right === 'number')
|
|
29
|
+
return 1;
|
|
30
|
+
return left < right ? -1 : 1;
|
|
31
|
+
}
|
|
32
|
+
function comparePre(a, b) {
|
|
33
|
+
if (a.length === 0 && b.length === 0)
|
|
34
|
+
return 0;
|
|
35
|
+
if (a.length === 0)
|
|
36
|
+
return 1;
|
|
37
|
+
if (b.length === 0)
|
|
38
|
+
return -1;
|
|
39
|
+
for (let i = 0; i < Math.max(a.length, b.length); i += 1) {
|
|
40
|
+
const cmp = comparePart(a[i], b[i]);
|
|
41
|
+
if (cmp !== 0)
|
|
42
|
+
return cmp;
|
|
43
|
+
}
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
export function compareVersions(a, b) {
|
|
47
|
+
const left = parseVersion(a);
|
|
48
|
+
const right = parseVersion(b);
|
|
49
|
+
if (left === null || right === null)
|
|
50
|
+
return 0;
|
|
51
|
+
for (let i = 0; i < 3; i += 1) {
|
|
52
|
+
const l = left.core[i] ?? 0;
|
|
53
|
+
const r = right.core[i] ?? 0;
|
|
54
|
+
if (l !== r)
|
|
55
|
+
return l < r ? -1 : 1;
|
|
56
|
+
}
|
|
57
|
+
return comparePre(left.pre, right.pre);
|
|
58
|
+
}
|
|
59
|
+
export function isNewer(candidate, current) {
|
|
60
|
+
return compareVersions(candidate, current) > 0;
|
|
61
|
+
}
|
|
62
|
+
export function currentVersion() {
|
|
63
|
+
const path = new URL('../package.json', import.meta.url);
|
|
64
|
+
const raw = JSON.parse(readFileSync(path, 'utf8'));
|
|
65
|
+
return typeof raw.version === 'string' ? raw.version : '0.0.0';
|
|
66
|
+
}
|
|
67
|
+
export function newestOf(tags) {
|
|
68
|
+
let best = '';
|
|
69
|
+
for (const value of Object.values(tags)) {
|
|
70
|
+
if (typeof value !== 'string' || parseVersion(value) === null)
|
|
71
|
+
continue;
|
|
72
|
+
if (best === '' || isNewer(value, best))
|
|
73
|
+
best = value;
|
|
74
|
+
}
|
|
75
|
+
return best;
|
|
76
|
+
}
|
|
77
|
+
export async function publishedVersion() {
|
|
78
|
+
let res;
|
|
79
|
+
try {
|
|
80
|
+
res = await fetch(`${REGISTRY}/${PACKAGE_NAME.replace('/', '%2F')}`, {
|
|
81
|
+
headers: { accept: 'application/json' },
|
|
82
|
+
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
throw new Error('could not reach the npm registry');
|
|
87
|
+
}
|
|
88
|
+
if (!res.ok)
|
|
89
|
+
throw new Error(`npm answered ${String(res.status)}`);
|
|
90
|
+
const body = await res.json();
|
|
91
|
+
if (typeof body !== 'object' || body === null)
|
|
92
|
+
throw new Error('npm returned an unexpected response');
|
|
93
|
+
const tags = body['dist-tags'];
|
|
94
|
+
if (typeof tags !== 'object' || tags === null)
|
|
95
|
+
throw new Error('npm returned no dist-tags');
|
|
96
|
+
return newestOf(tags);
|
|
97
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stage-labs/metro",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
4
|
-
"
|
|
5
|
-
"description": "Event-interception wire. Supervises train subprocesses in ~/.metro/trains/, multiplexes their JSON event stream onto stdout, and routes outbound action calls back via stdin. Per-platform code is written by the agent (or user) as train scripts — metro core is pure transport.",
|
|
3
|
+
"version": "0.1.0-beta.151",
|
|
4
|
+
"description": "The metro command line. Sign in once per machine, then hand your MCP connector list to Claude Code without the credentials touching disk, argv or shell history.",
|
|
6
5
|
"license": "MIT",
|
|
7
6
|
"repository": {
|
|
8
7
|
"type": "git",
|
|
@@ -15,39 +14,26 @@
|
|
|
15
14
|
"node": ">=22"
|
|
16
15
|
},
|
|
17
16
|
"bin": {
|
|
18
|
-
"metro": "
|
|
17
|
+
"metro": "dist/cli.js"
|
|
19
18
|
},
|
|
20
19
|
"files": [
|
|
21
20
|
"dist",
|
|
22
|
-
"
|
|
23
|
-
"examples",
|
|
24
|
-
"skills",
|
|
25
|
-
"README.md",
|
|
26
|
-
"LICENSE"
|
|
21
|
+
"runtime"
|
|
27
22
|
],
|
|
28
23
|
"publishConfig": {
|
|
29
|
-
"access": "public"
|
|
24
|
+
"access": "public",
|
|
25
|
+
"tag": "beta"
|
|
30
26
|
},
|
|
31
27
|
"scripts": {
|
|
32
|
-
"build": "tsc",
|
|
33
|
-
"prepublishOnly": "tsc",
|
|
34
|
-
"
|
|
35
|
-
"lint:fix": "eslint src/ examples/ --fix",
|
|
36
|
-
"typecheck": "tsc --noEmit",
|
|
37
|
-
"test": "METRO_STATE_DIR=\"$(mktemp -d /tmp/metro-test.XXXXXX)\" bun test test/"
|
|
38
|
-
},
|
|
39
|
-
"dependencies": {
|
|
40
|
-
"pino": "^9.5.0",
|
|
41
|
-
"pino-pretty": "^13.1.3",
|
|
42
|
-
"ws": "^8.20.0"
|
|
28
|
+
"build": "tsc && node scripts/stage-runtime.mjs",
|
|
29
|
+
"prepublishOnly": "tsc && node scripts/stage-runtime.mjs",
|
|
30
|
+
"test": "tsc --noEmit && node scripts/stage-runtime.mjs && bun test test/"
|
|
43
31
|
},
|
|
44
32
|
"devDependencies": {
|
|
45
|
-
"@
|
|
46
|
-
"@types/node": "^22.10.0",
|
|
47
|
-
"@types/ws": "^8.18.1",
|
|
33
|
+
"@stage-labs/config": "0.1.0-beta.2",
|
|
48
34
|
"eslint": "^10.3.0",
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
35
|
+
"knip": "^6.15.0",
|
|
36
|
+
"madge": "^8.0.0",
|
|
37
|
+
"typescript": "^5"
|
|
38
|
+
}
|
|
53
39
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "metro",
|
|
3
|
+
"description": "Metro — connector relay and chat bridge for agents",
|
|
4
|
+
"owner": { "name": "Bonustrack", "url": "https://metro.box" },
|
|
5
|
+
"plugins": [
|
|
6
|
+
{
|
|
7
|
+
"name": "metro",
|
|
8
|
+
"source": "./plugin",
|
|
9
|
+
"description": "Sign in as one metro agent and use the connectors it holds as MCP servers through metro's relay, credentials injected server-side."
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "metro",
|
|
3
|
+
"version": "0.1.0-beta.151",
|
|
4
|
+
"description": "Metro for Claude Code, installed by the metro daemon on this machine: every connector the agent holds as its own MCP server relayed through the daemon, the orchestrator-only guard on the main thread, and the standing rules loaded at each session start. No vendor credential ever sits in a config file.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Bonustrack",
|
|
7
|
+
"url": "https://metro.box"
|
|
8
|
+
},
|
|
9
|
+
"repository": "https://github.com/bonustrack/metro",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"metro",
|
|
13
|
+
"mcp",
|
|
14
|
+
"connectors",
|
|
15
|
+
"relay"
|
|
16
|
+
],
|
|
17
|
+
"skills": "./skills/"
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
|
|
4
|
+
const BLOCKING = new Set(['AskUserQuestion', 'ExitPlanMode', 'EnterPlanMode']);
|
|
5
|
+
const ORCHESTRATION = new Set([
|
|
6
|
+
'Agent',
|
|
7
|
+
'Workflow',
|
|
8
|
+
'ToolSearch',
|
|
9
|
+
'Skill',
|
|
10
|
+
'ScheduleWakeup',
|
|
11
|
+
'Monitor',
|
|
12
|
+
'CronCreate',
|
|
13
|
+
'CronList',
|
|
14
|
+
'CronDelete',
|
|
15
|
+
'TaskCreate',
|
|
16
|
+
'TaskGet',
|
|
17
|
+
'TaskList',
|
|
18
|
+
'TaskOutput',
|
|
19
|
+
'TaskStop',
|
|
20
|
+
'TaskUpdate',
|
|
21
|
+
]);
|
|
22
|
+
const IMAGE = /\.(png|jpe?g|gif|webp|bmp)$/i;
|
|
23
|
+
const MCP = /^mcp__/;
|
|
24
|
+
const METRO_MCP = /^mcp__metro__/;
|
|
25
|
+
|
|
26
|
+
function deny(reason) {
|
|
27
|
+
process.stdout.write(
|
|
28
|
+
`${JSON.stringify({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: reason } })}\n`,
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function verdict(payload) {
|
|
33
|
+
const tool = typeof payload.tool_name === 'string' ? payload.tool_name : '';
|
|
34
|
+
const input = payload.tool_input !== null && typeof payload.tool_input === 'object' ? payload.tool_input : {};
|
|
35
|
+
if (BLOCKING.has(tool))
|
|
36
|
+
return `${tool} blocks the session waiting on the terminal, and nobody is watching it. Decide with your best judgement and state the assumption, or ask over chat with the metro tools and keep working in the meantime.`;
|
|
37
|
+
if (typeof payload.agent_id === 'string' && payload.agent_id !== '') return null;
|
|
38
|
+
if (tool === 'Agent' && input.run_in_background === false)
|
|
39
|
+
return 'A foreground subagent blinds the main thread: it cannot see or acknowledge inbound metro messages until the agent finishes. Re-issue the identical Agent call with run_in_background: true, then wait for the task notification.';
|
|
40
|
+
if (ORCHESTRATION.has(tool)) return null;
|
|
41
|
+
if (METRO_MCP.test(tool)) return null;
|
|
42
|
+
if (MCP.test(tool))
|
|
43
|
+
return `A connector call is work, not orchestration: ${tool} reads somebody's files, mail or records, and its answer can be long enough to crowd out the chat you are here to follow. Only metro's own tools run on this thread. Delegate it to a subagent with the Agent tool (run_in_background: true; the worker reaches every connector) and relay what it finds.`;
|
|
44
|
+
if (tool === 'Read' && typeof input.file_path === 'string' && IMAGE.test(input.file_path)) return null;
|
|
45
|
+
return `The main thread is orchestrator-only, so ${tool === '' ? 'this tool' : tool} is not available here. Delegate the work to a subagent with the Agent tool (run_in_background: true; the worker agent has full tool access) or to a Workflow, and report the result over metro.`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let payload = {};
|
|
49
|
+
try {
|
|
50
|
+
payload = JSON.parse(readFileSync(0, 'utf8'));
|
|
51
|
+
} catch {
|
|
52
|
+
payload = {};
|
|
53
|
+
}
|
|
54
|
+
const reason = verdict(payload !== null && typeof payload === 'object' ? payload : {});
|
|
55
|
+
if (reason !== null) deny(reason);
|