@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/cli/util.js
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
/** Shared CLI primitives consumed by index.ts + config.ts. */
|
|
2
|
-
export const exitErr = (msg, code) => Object.assign(new Error(msg), { code });
|
|
3
|
-
export const isJson = (f) => f.json === true;
|
|
4
|
-
export const writeJson = (obj) => void process.stdout.write(JSON.stringify(obj) + '\n');
|
|
5
|
-
export const emit = (f, human, structured) => isJson(f) ? writeJson(structured) : void process.stdout.write(human + '\n');
|
|
6
|
-
export const need = (positional, min, usage) => {
|
|
7
|
-
if (positional.length < min)
|
|
8
|
-
throw exitErr(`usage: ${usage}`, 1);
|
|
9
|
-
};
|
|
10
|
-
/** Return the last string value for `key` (or undefined). */
|
|
11
|
-
export function flagOne(f, key) {
|
|
12
|
-
const v = f[key];
|
|
13
|
-
if (typeof v === 'string')
|
|
14
|
-
return v;
|
|
15
|
-
if (Array.isArray(v) && v.length)
|
|
16
|
-
return v[v.length - 1];
|
|
17
|
-
return undefined;
|
|
18
|
-
}
|
|
19
|
-
/** Return all string values for `key`, also splitting comma-separated entries. */
|
|
20
|
-
export function flagList(f, key) {
|
|
21
|
-
const v = f[key];
|
|
22
|
-
const raw = typeof v === 'string' ? [v] : Array.isArray(v) ? v : [];
|
|
23
|
-
return raw.flatMap(s => s.split(',').map(p => p.trim()).filter(Boolean));
|
|
24
|
-
}
|
|
25
|
-
export function parseArgs(argv) {
|
|
26
|
-
const positional = [], flags = {};
|
|
27
|
-
const add = (k, val) => {
|
|
28
|
-
const cur = flags[k];
|
|
29
|
-
if (cur === undefined) {
|
|
30
|
-
flags[k] = val;
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
if (typeof val === 'boolean') {
|
|
34
|
-
flags[k] = val;
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
flags[k] = Array.isArray(cur) ? [...cur, val] : [cur, val];
|
|
38
|
-
};
|
|
39
|
-
for (let i = 0; i < argv.length; i++) {
|
|
40
|
-
const a = argv[i];
|
|
41
|
-
if (!a.startsWith('--')) {
|
|
42
|
-
positional.push(a);
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
const eq = a.indexOf('=');
|
|
46
|
-
if (eq !== -1) {
|
|
47
|
-
add(a.slice(2, eq), a.slice(eq + 1));
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
const next = argv[i + 1];
|
|
51
|
-
if (next !== undefined && !next.startsWith('--')) {
|
|
52
|
-
add(a.slice(2), next);
|
|
53
|
-
i++;
|
|
54
|
-
}
|
|
55
|
-
else
|
|
56
|
-
add(a.slice(2), true);
|
|
57
|
-
}
|
|
58
|
-
return { positional, flags };
|
|
59
|
-
}
|
|
60
|
-
export async function resolveText(positional, from) {
|
|
61
|
-
if (positional.length > from)
|
|
62
|
-
return positional.slice(from).join(' ');
|
|
63
|
-
if (process.stdin.isTTY)
|
|
64
|
-
throw exitErr('text is required (or pipe text on stdin)', 1);
|
|
65
|
-
const chunks = [];
|
|
66
|
-
for await (const c of process.stdin)
|
|
67
|
-
chunks.push(c);
|
|
68
|
-
const stdin = Buffer.concat(chunks).toString('utf8').replace(/\n$/, '');
|
|
69
|
-
if (!stdin)
|
|
70
|
-
throw exitErr('text is required (or pipe text on stdin)', 1);
|
|
71
|
-
return stdin;
|
|
72
|
-
}
|
package/dist/cli/webhook.js
DELETED
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
/** CLI subcommands: `metro call`, `metro trains list`, `metro webhook ...`, `metro tunnel ...`. */
|
|
2
|
-
import { copyFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
3
|
-
import { homedir } from 'node:os';
|
|
4
|
-
import { dirname, join } from 'node:path';
|
|
5
|
-
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import { spawnSync } from 'node:child_process';
|
|
7
|
-
import { ipcCall } from '../ipc.js';
|
|
8
|
-
import { loadMetroEnv } from '../paths.js';
|
|
9
|
-
import { TRAINS_DIR } from '../trains/supervisor.js';
|
|
10
|
-
import { addEndpoint, listEndpoints, loadTunnelConfig, removeEndpoint, saveTunnelConfig, webhookPort, } from '../tunnel.js';
|
|
11
|
-
import { emit, exitErr, flagOne, isJson, need, writeJson } from './util.js';
|
|
12
|
-
function urlFor(endpointId) {
|
|
13
|
-
const t = loadTunnelConfig();
|
|
14
|
-
return t ? `https://${t.hostname}/wh/${endpointId}` : `http://127.0.0.1:${webhookPort()}/wh/${endpointId}`;
|
|
15
|
-
}
|
|
16
|
-
export async function cmdWebhook(p, f) {
|
|
17
|
-
const sub = p[0];
|
|
18
|
-
if (sub === 'add')
|
|
19
|
-
return cmdWebhookAdd(p.slice(1), f);
|
|
20
|
-
if (sub === 'list' || sub === undefined)
|
|
21
|
-
return cmdWebhookList(f);
|
|
22
|
-
if (sub === 'remove' || sub === 'rm')
|
|
23
|
-
return cmdWebhookRemove(p.slice(1), f);
|
|
24
|
-
throw exitErr('usage: metro webhook [add <label> [--secret=…] | list | remove <id>]', 1);
|
|
25
|
-
}
|
|
26
|
-
async function cmdWebhookAdd(p, f) {
|
|
27
|
-
need(p, 1, 'metro webhook add <label> [--secret=<shared-secret>]');
|
|
28
|
-
const ep = addEndpoint(p[0], flagOne(f, 'secret'));
|
|
29
|
-
const url = urlFor(ep.id);
|
|
30
|
-
emit(f, `webhook ${ep.id} (${ep.label}) → ${url}${ep.secret ? `\nshared secret: ${ep.secret}` : ''}`, { ok: true, endpoint: ep, url });
|
|
31
|
-
}
|
|
32
|
-
async function cmdWebhookList(f) {
|
|
33
|
-
const eps = listEndpoints().map(ep => ({ ...ep, url: urlFor(ep.id) }));
|
|
34
|
-
if (isJson(f))
|
|
35
|
-
return writeJson({ endpoints: eps });
|
|
36
|
-
if (!eps.length)
|
|
37
|
-
return void process.stdout.write('metro webhooks\n\n (none — run `metro webhook add <label>`)\n\n');
|
|
38
|
-
process.stdout.write('metro webhooks\n\n');
|
|
39
|
-
for (const ep of eps) {
|
|
40
|
-
process.stdout.write(` ${ep.id} ${ep.label}${ep.secret ? ' (signed)' : ''}\n ${ep.url}\n`);
|
|
41
|
-
}
|
|
42
|
-
process.stdout.write('\n');
|
|
43
|
-
}
|
|
44
|
-
async function cmdWebhookRemove(p, f) {
|
|
45
|
-
need(p, 1, 'metro webhook remove <id>');
|
|
46
|
-
const ok = removeEndpoint(p[0]);
|
|
47
|
-
if (!ok)
|
|
48
|
-
throw exitErr(`no webhook with id "${p[0]}"`, 1);
|
|
49
|
-
emit(f, `removed webhook ${p[0]}`, { ok: true, id: p[0] });
|
|
50
|
-
}
|
|
51
|
-
export async function cmdTunnel(p, f) {
|
|
52
|
-
const sub = p[0];
|
|
53
|
-
if (sub === 'setup')
|
|
54
|
-
return cmdTunnelSetup(p.slice(1), f);
|
|
55
|
-
if (sub === 'status' || sub === undefined)
|
|
56
|
-
return cmdTunnelStatus(f);
|
|
57
|
-
throw exitErr('usage: metro tunnel [setup <name> <hostname> | status]', 1);
|
|
58
|
-
}
|
|
59
|
-
async function cmdTunnelSetup(p, f) {
|
|
60
|
-
need(p, 2, 'metro tunnel setup <tunnel-name> <hostname> (e.g. `metro tunnel setup metro webhook.example.com`)');
|
|
61
|
-
const [name, hostname] = p;
|
|
62
|
-
if (!hasCloudflared()) {
|
|
63
|
-
throw exitErr('cloudflared not on PATH — install with `brew install cloudflared` (or see https://developers.cloudflare.com/cloudflared/)', 2);
|
|
64
|
-
}
|
|
65
|
-
/** Idempotent: if tunnel exists, `tunnel create` errors with "already exists" — that's fine, continue. */
|
|
66
|
-
run('cloudflared', ['tunnel', 'create', name], { allowFail: true });
|
|
67
|
-
/** DNS route is also idempotent in newer cloudflared; older versions error if the CNAME exists. Same handling. */
|
|
68
|
-
run('cloudflared', ['tunnel', 'route', 'dns', name, hostname], { allowFail: true });
|
|
69
|
-
saveTunnelConfig({ name, hostname });
|
|
70
|
-
emit(f, `tunnel saved: ${name} → ${hostname}\n` +
|
|
71
|
-
'first run: `cloudflared tunnel login` if you haven\'t (browser OAuth).\n' +
|
|
72
|
-
'then start metro — the daemon will spawn `cloudflared tunnel run` for you.', { ok: true, name, hostname });
|
|
73
|
-
}
|
|
74
|
-
async function cmdTunnelStatus(f) {
|
|
75
|
-
const cfg = loadTunnelConfig();
|
|
76
|
-
if (isJson(f))
|
|
77
|
-
return writeJson({ configured: !!cfg, tunnel: cfg });
|
|
78
|
-
if (!cfg)
|
|
79
|
-
return void process.stdout.write('metro tunnel\n\n (not configured — run `metro tunnel setup <name> <hostname>`)\n\n');
|
|
80
|
-
process.stdout.write(`metro tunnel\n\n name: ${cfg.name}\n hostname: ${cfg.hostname}\n\n`);
|
|
81
|
-
}
|
|
82
|
-
const hasCloudflared = () => spawnSync('cloudflared', ['--version'], { stdio: 'ignore' }).status === 0;
|
|
83
|
-
function run(cmd, args, opts = {}) {
|
|
84
|
-
const r = spawnSync(cmd, args, { stdio: 'inherit' });
|
|
85
|
-
if (r.status !== 0 && !opts.allowFail)
|
|
86
|
-
throw exitErr(`${cmd} ${args.join(' ')} exited ${r.status}`, 2);
|
|
87
|
-
}
|
|
88
|
-
/* ──────────── metro call <train> <action> [args] + metro trains list ──────────── */
|
|
89
|
-
async function readArgs(raw) {
|
|
90
|
-
if (raw === undefined)
|
|
91
|
-
return {};
|
|
92
|
-
if (raw === '-') {
|
|
93
|
-
const chunks = [];
|
|
94
|
-
for await (const c of process.stdin)
|
|
95
|
-
chunks.push(c);
|
|
96
|
-
const s = Buffer.concat(chunks).toString('utf8').trim();
|
|
97
|
-
return s ? JSON.parse(s) : {};
|
|
98
|
-
}
|
|
99
|
-
if (raw.startsWith('@'))
|
|
100
|
-
return JSON.parse(readFileSync(raw.slice(1), 'utf8'));
|
|
101
|
-
/** Bare string allowed (handed to the train as-is). */
|
|
102
|
-
try {
|
|
103
|
-
return JSON.parse(raw);
|
|
104
|
-
}
|
|
105
|
-
catch {
|
|
106
|
-
return raw;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
export async function cmdCall(p, f) {
|
|
110
|
-
need(p, 2, 'metro call <train> <action> [args-json | @file | -]');
|
|
111
|
-
loadMetroEnv();
|
|
112
|
-
const [train, action, rawArgs] = p;
|
|
113
|
-
const resp = await ipcCall({ op: 'forward-call', train, action, args: await readArgs(rawArgs) });
|
|
114
|
-
if (!resp.ok)
|
|
115
|
-
throw new Error(resp.error);
|
|
116
|
-
if (!('response' in resp))
|
|
117
|
-
throw new Error('daemon returned malformed forward-call response');
|
|
118
|
-
if (resp.response.error)
|
|
119
|
-
throw new Error(`train '${train}': ${resp.response.error}`);
|
|
120
|
-
if (isJson(f))
|
|
121
|
-
writeJson(resp.response.result ?? null);
|
|
122
|
-
else
|
|
123
|
-
process.stdout.write(JSON.stringify(resp.response.result ?? null) + '\n');
|
|
124
|
-
}
|
|
125
|
-
export async function cmdTrains(p, f) {
|
|
126
|
-
const sub = p[0] ?? 'list';
|
|
127
|
-
if (sub === 'restart')
|
|
128
|
-
return cmdTrainsRestart(p.slice(1), f);
|
|
129
|
-
if (sub === 'new')
|
|
130
|
-
return cmdTrainsNew(p.slice(1), f);
|
|
131
|
-
if (sub !== 'list')
|
|
132
|
-
throw new Error(`metro trains <list|restart|new> (got '${sub}')`);
|
|
133
|
-
loadMetroEnv();
|
|
134
|
-
const resp = await ipcCall({ op: 'trains-list' });
|
|
135
|
-
if (!resp.ok)
|
|
136
|
-
throw new Error(resp.error);
|
|
137
|
-
if (!('trains' in resp))
|
|
138
|
-
throw new Error('daemon returned malformed trains-list response');
|
|
139
|
-
if (isJson(f))
|
|
140
|
-
return writeJson({ trains: resp.trains });
|
|
141
|
-
if (!resp.trains.length) {
|
|
142
|
-
process.stdout.write('metro trains\n\n (no trains in ~/.metro/trains/)\n');
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
process.stdout.write('metro trains\n\n');
|
|
146
|
-
for (const t of resp.trains) {
|
|
147
|
-
const mark = t.running ? '●' : '○';
|
|
148
|
-
const pid = t.pid ? ` pid ${t.pid}` : '';
|
|
149
|
-
const started = t.startedAt ? ` since ${t.startedAt.slice(11, 19)}` : '';
|
|
150
|
-
const fails = t.failCount ? ` · ${t.failCount} fail${t.failCount === 1 ? '' : 's'}` : '';
|
|
151
|
-
process.stdout.write(` ${mark} ${t.name.padEnd(16)}${pid}${started}${fails}\n ${t.path}\n`);
|
|
152
|
-
}
|
|
153
|
-
process.stdout.write('\n');
|
|
154
|
-
}
|
|
155
|
-
async function cmdTrainsRestart(p, f) {
|
|
156
|
-
need(p, 1, 'metro trains restart <name>');
|
|
157
|
-
loadMetroEnv();
|
|
158
|
-
const resp = await ipcCall({ op: 'train-restart', name: p[0] });
|
|
159
|
-
if (!resp.ok)
|
|
160
|
-
throw new Error(resp.error);
|
|
161
|
-
emit(f, `restarted train '${p[0]}'`, { ok: true, name: p[0] });
|
|
162
|
-
}
|
|
163
|
-
/** dist/cli/webhook.js → <package-root>/examples/telegram.ts */
|
|
164
|
-
const bundledExample = () => join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'examples', 'telegram.ts');
|
|
165
|
-
async function cmdTrainsNew(p, f) {
|
|
166
|
-
need(p, 1, 'metro trains new <name>');
|
|
167
|
-
const name = p[0];
|
|
168
|
-
if (!/^[A-Za-z0-9_-]+$/.test(name))
|
|
169
|
-
throw exitErr(`bad train name '${name}' (use [A-Za-z0-9_-])`, 1);
|
|
170
|
-
const src = bundledExample();
|
|
171
|
-
if (!existsSync(src))
|
|
172
|
-
throw exitErr(`bundled example missing at ${src} (broken install?)`, 2);
|
|
173
|
-
mkdirSync(TRAINS_DIR, { recursive: true });
|
|
174
|
-
const dest = join(TRAINS_DIR, `${name}.ts`);
|
|
175
|
-
if (existsSync(dest))
|
|
176
|
-
throw exitErr(`train already exists: ${dest}`, 1);
|
|
177
|
-
copyFileSync(src, dest);
|
|
178
|
-
const metroPkg = join(homedir(), '.metro', 'package.json');
|
|
179
|
-
const pkgHint = existsSync(metroPkg) ? '' : '\n (run `cd ~/.metro && bun init` first if your train needs deps)';
|
|
180
|
-
emit(f, `created ${dest}${pkgHint}\n next: edit the file, then \`metro trains restart ${name}\``, { ok: true, path: dest, pkgInitialized: existsSync(metroPkg) });
|
|
181
|
-
}
|
package/dist/codex-rc/client.js
DELETED
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
/** JSON-RPC/WS client for codex app-server: each event → `turn/start`. */
|
|
2
|
-
import { errMsg, log } from '../log.js';
|
|
3
|
-
import { buildTurnInput, encodeRpc, extractThreadStartedId, isStatusActive, openSocket, parseUrl, } from './protocol.js';
|
|
4
|
-
const RECONNECT_DELAY_MS = 2_000;
|
|
5
|
-
const MAX_QUEUE = 100;
|
|
6
|
-
/** Backstop in case `turn/completed` never arrives — unstick the single-flight gate. */
|
|
7
|
-
const TURN_TIMEOUT_MS = 120_000;
|
|
8
|
-
export class CodexRC {
|
|
9
|
-
url;
|
|
10
|
-
clientVersion;
|
|
11
|
-
ws = null;
|
|
12
|
-
nextId = 1;
|
|
13
|
-
pending = new Map();
|
|
14
|
-
threadId = null;
|
|
15
|
-
threadListener = null;
|
|
16
|
-
queue = [];
|
|
17
|
-
connected = false;
|
|
18
|
-
connecting = false;
|
|
19
|
-
turnInFlight = false;
|
|
20
|
-
turnTimeout = null;
|
|
21
|
-
closed = false;
|
|
22
|
-
endpoint;
|
|
23
|
-
constructor(url, clientVersion) {
|
|
24
|
-
this.url = url;
|
|
25
|
-
this.clientVersion = clientVersion;
|
|
26
|
-
this.endpoint = parseUrl(url);
|
|
27
|
-
}
|
|
28
|
-
start() { void this.connect(); }
|
|
29
|
-
getThreadId() { return this.threadId; }
|
|
30
|
-
onThread(listener) { this.threadListener = listener; }
|
|
31
|
-
setThreadId(id) {
|
|
32
|
-
if (this.threadId === id)
|
|
33
|
-
return;
|
|
34
|
-
this.threadId = id;
|
|
35
|
-
this.threadListener?.(id);
|
|
36
|
-
}
|
|
37
|
-
stop() {
|
|
38
|
-
this.closed = true;
|
|
39
|
-
this.clearTurnTimeout();
|
|
40
|
-
this.ws?.close();
|
|
41
|
-
this.ws = null;
|
|
42
|
-
}
|
|
43
|
-
push(line) {
|
|
44
|
-
if (this.queue.length >= MAX_QUEUE) {
|
|
45
|
-
log.warn({ url: this.url }, 'codex-rc queue full, dropping oldest');
|
|
46
|
-
this.queue.shift();
|
|
47
|
-
}
|
|
48
|
-
this.queue.push(line);
|
|
49
|
-
void this.drainQueue();
|
|
50
|
-
}
|
|
51
|
-
async connect() {
|
|
52
|
-
if (this.closed || this.connected || this.connecting)
|
|
53
|
-
return;
|
|
54
|
-
this.connecting = true;
|
|
55
|
-
try {
|
|
56
|
-
const ws = openSocket(this.endpoint);
|
|
57
|
-
this.ws = ws;
|
|
58
|
-
ws.on('error', err => log.warn({ err: errMsg(err) }, 'codex-rc websocket error'));
|
|
59
|
-
await new Promise((resolve, reject) => {
|
|
60
|
-
ws.once('open', () => resolve());
|
|
61
|
-
ws.once('error', err => reject(err));
|
|
62
|
-
});
|
|
63
|
-
ws.on('message', data => this.onMessage(data));
|
|
64
|
-
ws.on('close', () => this.onClose());
|
|
65
|
-
const clientInfo = { name: 'metro', version: this.clientVersion, title: null };
|
|
66
|
-
await this.call('initialize', { clientInfo });
|
|
67
|
-
this.setThreadId(await this.pickOrCreateThread());
|
|
68
|
-
this.connected = true;
|
|
69
|
-
log.info({ url: this.url, thread: this.threadId ?? '(none yet)' }, 'codex-rc connected');
|
|
70
|
-
void this.drainQueue();
|
|
71
|
-
}
|
|
72
|
-
catch (err) {
|
|
73
|
-
log.warn({ err: errMsg(err), url: this.url }, 'codex-rc connect failed; retrying');
|
|
74
|
-
this.scheduleReconnect();
|
|
75
|
-
}
|
|
76
|
-
finally {
|
|
77
|
-
this.connecting = false;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
onMessage(raw) {
|
|
81
|
-
let msg;
|
|
82
|
-
try {
|
|
83
|
-
msg = JSON.parse(raw.toString());
|
|
84
|
-
}
|
|
85
|
-
catch (err) {
|
|
86
|
-
log.warn({ err: errMsg(err) }, 'codex-rc malformed message');
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
if (msg.id !== undefined && this.pending.has(msg.id)) {
|
|
90
|
-
const p = this.pending.get(msg.id);
|
|
91
|
-
this.pending.delete(msg.id);
|
|
92
|
-
if (msg.error)
|
|
93
|
-
p.reject(new Error(msg.error.message ?? 'rpc error'));
|
|
94
|
-
else
|
|
95
|
-
p.resolve(msg.result);
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
this.handleNotification(msg);
|
|
99
|
-
}
|
|
100
|
-
handleNotification(msg) {
|
|
101
|
-
switch (msg.method) {
|
|
102
|
-
case 'thread/started': {
|
|
103
|
-
const id = extractThreadStartedId(msg.params);
|
|
104
|
-
if (id) {
|
|
105
|
-
this.setThreadId(id);
|
|
106
|
-
log.info({ thread: id }, 'codex-rc thread started');
|
|
107
|
-
void this.drainQueue();
|
|
108
|
-
}
|
|
109
|
-
break;
|
|
110
|
-
}
|
|
111
|
-
case 'thread/status/changed': {
|
|
112
|
-
const s = isStatusActive(msg.params, this.threadId);
|
|
113
|
-
if (!s.match)
|
|
114
|
-
break;
|
|
115
|
-
if (s.active)
|
|
116
|
-
this.turnInFlight = true;
|
|
117
|
-
else {
|
|
118
|
-
this.clearTurnTimeout();
|
|
119
|
-
this.turnInFlight = false;
|
|
120
|
-
void this.drainQueue();
|
|
121
|
-
}
|
|
122
|
-
break;
|
|
123
|
-
}
|
|
124
|
-
case 'turn/completed':
|
|
125
|
-
this.clearTurnTimeout();
|
|
126
|
-
this.turnInFlight = false;
|
|
127
|
-
void this.drainQueue();
|
|
128
|
-
break;
|
|
129
|
-
case 'turn/started':
|
|
130
|
-
this.turnInFlight = true;
|
|
131
|
-
break;
|
|
132
|
-
case 'thread/closed':
|
|
133
|
-
case 'thread/archived':
|
|
134
|
-
log.warn({ method: msg.method }, 'codex-rc thread closed/archived');
|
|
135
|
-
this.setThreadId(null);
|
|
136
|
-
break;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
onClose() {
|
|
140
|
-
if (this.closed)
|
|
141
|
-
return;
|
|
142
|
-
this.connected = false;
|
|
143
|
-
this.ws = null;
|
|
144
|
-
for (const p of this.pending.values())
|
|
145
|
-
p.reject(new Error('websocket closed'));
|
|
146
|
-
this.pending.clear();
|
|
147
|
-
this.scheduleReconnect();
|
|
148
|
-
}
|
|
149
|
-
scheduleReconnect() {
|
|
150
|
-
if (this.closed)
|
|
151
|
-
return;
|
|
152
|
-
this.connected = false;
|
|
153
|
-
setTimeout(() => void this.connect(), RECONNECT_DELAY_MS);
|
|
154
|
-
}
|
|
155
|
-
/** Prefer the most-recently-loaded thread (the TUI's if attached); else create our own. */
|
|
156
|
-
async pickOrCreateThread() {
|
|
157
|
-
try {
|
|
158
|
-
const loaded = await this.call('thread/loaded/list', {});
|
|
159
|
-
const existing = loaded.data?.[loaded.data.length - 1];
|
|
160
|
-
if (existing)
|
|
161
|
-
return existing;
|
|
162
|
-
}
|
|
163
|
-
catch (err) {
|
|
164
|
-
log.warn({ err: errMsg(err) }, 'codex-rc thread/loaded/list failed');
|
|
165
|
-
}
|
|
166
|
-
try {
|
|
167
|
-
const created = await this.call('thread/start', {});
|
|
168
|
-
return created.thread?.id ?? null;
|
|
169
|
-
}
|
|
170
|
-
catch (err) {
|
|
171
|
-
log.warn({ err: errMsg(err) }, 'codex-rc thread/start failed');
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
async drainQueue() {
|
|
176
|
-
if (!this.connected || this.turnInFlight || !this.queue.length)
|
|
177
|
-
return;
|
|
178
|
-
if (!this.threadId) {
|
|
179
|
-
this.setThreadId(await this.pickOrCreateThread());
|
|
180
|
-
if (!this.threadId)
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
const line = this.queue[0];
|
|
184
|
-
this.turnInFlight = true;
|
|
185
|
-
this.armTurnTimeout();
|
|
186
|
-
try {
|
|
187
|
-
await this.call('turn/start', { threadId: this.threadId, input: buildTurnInput(line) });
|
|
188
|
-
this.queue.shift();
|
|
189
|
-
}
|
|
190
|
-
catch (err) {
|
|
191
|
-
const dead = errMsg(err).includes('thread not found');
|
|
192
|
-
log.warn({ err: errMsg(err) }, dead ? 'codex-rc thread gone; will create a new one' : 'codex-rc turn/start failed; will retry');
|
|
193
|
-
this.clearTurnTimeout();
|
|
194
|
-
this.turnInFlight = false;
|
|
195
|
-
if (dead)
|
|
196
|
-
this.setThreadId(null);
|
|
197
|
-
setTimeout(() => void this.drainQueue(), 1_000);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
armTurnTimeout() {
|
|
201
|
-
this.clearTurnTimeout();
|
|
202
|
-
this.turnTimeout = setTimeout(() => {
|
|
203
|
-
log.warn({ thread: this.threadId, queue: this.queue.length }, `codex-rc turn/completed not received within ${TURN_TIMEOUT_MS}ms; force-clearing gate`);
|
|
204
|
-
this.turnInFlight = false;
|
|
205
|
-
this.turnTimeout = null;
|
|
206
|
-
void this.drainQueue();
|
|
207
|
-
}, TURN_TIMEOUT_MS);
|
|
208
|
-
}
|
|
209
|
-
clearTurnTimeout() {
|
|
210
|
-
if (this.turnTimeout) {
|
|
211
|
-
clearTimeout(this.turnTimeout);
|
|
212
|
-
this.turnTimeout = null;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
call(method, params) {
|
|
216
|
-
if (!this.ws)
|
|
217
|
-
return Promise.reject(new Error('not connected'));
|
|
218
|
-
const id = this.nextId++;
|
|
219
|
-
const ws = this.ws;
|
|
220
|
-
return new Promise((resolve, reject) => {
|
|
221
|
-
this.pending.set(id, { resolve: resolve, reject });
|
|
222
|
-
ws.send(encodeRpc(id, method, params));
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/** Codex JSON-RPC over WS: endpoint parsing, socket open, message encode/decode. */
|
|
2
|
-
import { createConnection } from 'node:net';
|
|
3
|
-
import { WebSocket } from 'ws';
|
|
4
|
-
/** Accept ws://, wss://, unix:///abs/path, or /abs/path (shorthand for unix). */
|
|
5
|
-
export function parseUrl(input) {
|
|
6
|
-
if (input.startsWith('ws://') || input.startsWith('wss://'))
|
|
7
|
-
return { kind: 'tcp', url: input };
|
|
8
|
-
if (input.startsWith('unix://'))
|
|
9
|
-
return { kind: 'unix', path: input.replace(/^unix:\/+/, '/') };
|
|
10
|
-
if (input.startsWith('/'))
|
|
11
|
-
return { kind: 'unix', path: input };
|
|
12
|
-
throw new Error(`unsupported METRO_CODEX_RC: ${input} (expected ws://, wss://, unix://, or abs path)`);
|
|
13
|
-
}
|
|
14
|
-
export function openSocket(endpoint) {
|
|
15
|
-
if (endpoint.kind === 'tcp')
|
|
16
|
-
return new WebSocket(endpoint.url);
|
|
17
|
-
return new WebSocket('ws://localhost/', {
|
|
18
|
-
createConnection: () => createConnection({ path: endpoint.path }),
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
export function encodeRpc(id, method, params) {
|
|
22
|
-
return JSON.stringify({ jsonrpc: '2.0', id, method, params });
|
|
23
|
-
}
|
|
24
|
-
/** Extract the active-thread state from a `thread/status/changed` params payload. */
|
|
25
|
-
/** Codex 0.130+: `status: {active}` ⇒ in-flight; any other shape ⇒ idle. */
|
|
26
|
-
export function isStatusActive(params, expectedThreadId) {
|
|
27
|
-
const p = params;
|
|
28
|
-
if (p?.threadId !== expectedThreadId)
|
|
29
|
-
return { match: false, active: false };
|
|
30
|
-
const active = typeof p.status === 'object' && p.status !== null && 'active' in p.status;
|
|
31
|
-
return { match: true, active };
|
|
32
|
-
}
|
|
33
|
-
export function extractThreadStartedId(params) {
|
|
34
|
-
return params?.thread?.id;
|
|
35
|
-
}
|
|
36
|
-
export function buildTurnInput(line) {
|
|
37
|
-
return [{ type: 'text', text: line, textElements: [] }];
|
|
38
|
-
}
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
/** Dispatcher's plumbing: outbound event emission + train-envelope translation + HTTP receiver. */
|
|
2
|
-
import { createHmac, randomUUID, timingSafeEqual } from 'node:crypto';
|
|
3
|
-
import { createServer, } from 'node:http';
|
|
4
|
-
import { Line } from '../lines.js';
|
|
5
|
-
import { errMsg, log } from '../log.js';
|
|
6
|
-
import { noteSeen } from '../paths.js';
|
|
7
|
-
import { appendHistory, formatDisplay, mintId, noteUserFromLine, userSelf, } from '../history.js';
|
|
8
|
-
import { handleMonitorRequest } from '../cli/tail.js';
|
|
9
|
-
import { findEndpoint, listEndpoints, webhookPort } from '../tunnel.js';
|
|
10
|
-
export function makeEmit(codexRc) {
|
|
11
|
-
return function emit(entry) {
|
|
12
|
-
/** `display` first so it survives Monitor's body truncation — the user must see it to echo it. */
|
|
13
|
-
const enriched = { display: formatDisplay(entry), ...entry };
|
|
14
|
-
const json = JSON.stringify(enriched);
|
|
15
|
-
process.stdout.write(json + '\n');
|
|
16
|
-
codexRc?.push(json);
|
|
17
|
-
noteSeen(entry.line, entry.lineName);
|
|
18
|
-
for (const l of [entry.line, entry.from, entry.to])
|
|
19
|
-
if (l)
|
|
20
|
-
noteUserFromLine(l);
|
|
21
|
-
appendHistory(enriched);
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
/** Translate the snake_case train wire envelope to a camelCase `HistoryEntry`. */
|
|
25
|
-
/** Trains can omit `id`/`station`/`to`; metro fills sensible defaults. */
|
|
26
|
-
export function trainEventToHistoryEntry(env, trainName) {
|
|
27
|
-
const line = env.line;
|
|
28
|
-
if (typeof line !== 'string') {
|
|
29
|
-
log.warn({ train: trainName }, 'train: dropped event without `line`');
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
const station = env.station ?? Line.station(line) ?? trainName;
|
|
33
|
-
const isPrivate = env.is_private === true;
|
|
34
|
-
/** Trains may still emit `emoji` for reactions — fold it into text so the new envelope stays minimal. */
|
|
35
|
-
const text = env.text ?? (env.emoji ? `[react ${env.emoji}]` : undefined);
|
|
36
|
-
return {
|
|
37
|
-
id: env.id ?? mintId(),
|
|
38
|
-
ts: env.ts ?? new Date().toISOString(),
|
|
39
|
-
station,
|
|
40
|
-
line: line,
|
|
41
|
-
lineName: env.line_name,
|
|
42
|
-
from: (env.from ?? `metro://${station}`),
|
|
43
|
-
fromName: env.from_name,
|
|
44
|
-
to: (env.to ?? (isPrivate ? userSelf() : line)),
|
|
45
|
-
text,
|
|
46
|
-
messageId: env.message_id,
|
|
47
|
-
replyTo: env.reply_to,
|
|
48
|
-
payload: env.payload,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
export async function startWebhookServer(emit) {
|
|
52
|
-
const port = webhookPort();
|
|
53
|
-
const server = createServer((req, res) => {
|
|
54
|
-
handleRequest(req, res, emit).catch(err => {
|
|
55
|
-
log.warn({ err: errMsg(err) }, 'webhook handler error');
|
|
56
|
-
if (!res.headersSent)
|
|
57
|
-
res.writeHead(500).end();
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
await new Promise((resolve, reject) => {
|
|
61
|
-
server.once('error', reject);
|
|
62
|
-
server.listen(port, '127.0.0.1', () => {
|
|
63
|
-
log.info({ port, endpoints: listEndpoints().length }, 'webhook + monitor ready');
|
|
64
|
-
resolve();
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
return server;
|
|
68
|
-
}
|
|
69
|
-
async function handleRequest(req, res, emit) {
|
|
70
|
-
if (handleMonitorRequest(req, res, emit))
|
|
71
|
-
return;
|
|
72
|
-
const m = req.url?.match(/^\/wh\/([A-Za-z0-9_-]+)/);
|
|
73
|
-
if (!m) {
|
|
74
|
-
res.writeHead(404).end();
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
const endpointId = m[1];
|
|
78
|
-
const endpoint = findEndpoint(endpointId);
|
|
79
|
-
if (!endpoint) {
|
|
80
|
-
res.writeHead(404).end();
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
if (req.method === 'GET') {
|
|
84
|
-
res.writeHead(200).end(`metro webhook ${endpointId} ready\n`);
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
if (req.method !== 'POST') {
|
|
88
|
-
res.writeHead(405).end();
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
const chunks = [];
|
|
92
|
-
for await (const c of req)
|
|
93
|
-
chunks.push(c);
|
|
94
|
-
const raw = Buffer.concat(chunks);
|
|
95
|
-
const headers = Object.fromEntries(Object.entries(req.headers).map(([k, v]) => [k, Array.isArray(v) ? v.join(',') : v ?? '']));
|
|
96
|
-
if (endpoint.secret && !verifySig(endpoint.secret, raw, headers['x-hub-signature-256'])) {
|
|
97
|
-
log.warn({ endpoint: endpointId }, 'webhook signature mismatch — rejecting');
|
|
98
|
-
res.writeHead(401).end('signature mismatch');
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
let body = raw.toString('utf8');
|
|
102
|
-
try {
|
|
103
|
-
body = JSON.parse(body);
|
|
104
|
-
}
|
|
105
|
-
catch { /* keep as string */ }
|
|
106
|
-
const line = Line.webhook(endpointId);
|
|
107
|
-
emit({
|
|
108
|
-
id: mintId(), ts: new Date().toISOString(), station: 'webhook',
|
|
109
|
-
line, lineName: endpoint.label, from: line, to: line,
|
|
110
|
-
messageId: headers['x-github-delivery'] || headers['x-request-id'] || randomUUID(),
|
|
111
|
-
text: `${headers['x-github-event'] ?? headers['x-intercom-topic'] ?? 'event'} ${req.method} ${req.url}`,
|
|
112
|
-
payload: { headers, body },
|
|
113
|
-
});
|
|
114
|
-
res.writeHead(200).end('ok');
|
|
115
|
-
}
|
|
116
|
-
function verifySig(secret, raw, header) {
|
|
117
|
-
if (!header?.startsWith('sha256='))
|
|
118
|
-
return false;
|
|
119
|
-
const given = Buffer.from(header.slice(7), 'hex');
|
|
120
|
-
const want = createHmac('sha256', secret).update(raw).digest();
|
|
121
|
-
return given.length === want.length && timingSafeEqual(given, want);
|
|
122
|
-
}
|