@stage-labs/metro 0.1.0-beta.8 → 0.1.0-beta.80

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.
Files changed (282) hide show
  1. package/dist/api.js +14 -0
  2. package/dist/claude-settings.js +40 -0
  3. package/dist/claude.js +107 -0
  4. package/dist/cli.js +101 -0
  5. package/dist/control.js +74 -0
  6. package/dist/hold.js +211 -0
  7. package/dist/local.js +93 -0
  8. package/dist/node-name.js +71 -0
  9. package/dist/plugin.js +80 -0
  10. package/dist/provider-flags.js +9 -0
  11. package/dist/runtime-install.js +87 -0
  12. package/dist/runtime.js +74 -0
  13. package/dist/serve.js +146 -0
  14. package/dist/service.js +242 -0
  15. package/dist/tail.js +119 -0
  16. package/dist/update.js +45 -0
  17. package/dist/version.js +97 -0
  18. package/package.json +14 -25
  19. package/runtime/node_modules/@metro-labs/core/package.json +43 -0
  20. package/runtime/node_modules/@metro-labs/core/src/address.ts +6 -0
  21. package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
  22. package/runtime/node_modules/@metro-labs/core/src/events.ts +120 -0
  23. package/runtime/node_modules/@metro-labs/core/src/identity.ts +7 -0
  24. package/runtime/node_modules/@metro-labs/core/src/ids.ts +21 -0
  25. package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
  26. package/runtime/node_modules/@metro-labs/core/src/lines.ts +82 -0
  27. package/runtime/node_modules/@metro-labs/core/src/log.ts +42 -0
  28. package/runtime/node_modules/@metro-labs/core/src/protocol.ts +226 -0
  29. package/runtime/node_modules/@metro-labs/core/src/secure-fs.ts +57 -0
  30. package/runtime/node_modules/@metro-labs/core/src/station-names.ts +12 -0
  31. package/runtime/node_modules/@metro-labs/core/src/stations/account-store.ts +60 -0
  32. package/runtime/node_modules/@metro-labs/core/src/stations/attachments.ts +196 -0
  33. package/runtime/node_modules/@metro-labs/core/src/stations/messaging-normalize.ts +88 -0
  34. package/runtime/node_modules/@metro-labs/core/src/stations/station-runtime.ts +64 -0
  35. package/runtime/node_modules/@metro-labs/core/src/stations/types.ts +107 -0
  36. package/runtime/node_modules/@metro-labs/core/src/str.ts +5 -0
  37. package/runtime/node_modules/@metro-labs/core/src/train-error.ts +53 -0
  38. package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
  39. package/runtime/node_modules/@metro-labs/daemon/package.json +47 -0
  40. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-attach.ts +19 -0
  41. package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +311 -0
  42. package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +43 -0
  43. package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +302 -0
  44. package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +111 -0
  45. package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +329 -0
  46. package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +155 -0
  47. package/runtime/node_modules/@metro-labs/daemon/src/agents/keys.ts +45 -0
  48. package/runtime/node_modules/@metro-labs/daemon/src/agents/map.ts +84 -0
  49. package/runtime/node_modules/@metro-labs/daemon/src/agents/scope.ts +64 -0
  50. package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +176 -0
  51. package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +39 -0
  52. package/runtime/node_modules/@metro-labs/daemon/src/boot/crash-guard.ts +49 -0
  53. package/runtime/node_modules/@metro-labs/daemon/src/boot/local-owner.ts +14 -0
  54. package/runtime/node_modules/@metro-labs/daemon/src/boot/paths.ts +106 -0
  55. package/runtime/node_modules/@metro-labs/daemon/src/channels/addressed.ts +25 -0
  56. package/runtime/node_modules/@metro-labs/daemon/src/channels/dedupe.ts +24 -0
  57. package/runtime/node_modules/@metro-labs/daemon/src/channels/inbound.ts +377 -0
  58. package/runtime/node_modules/@metro-labs/daemon/src/channels/media-note.ts +85 -0
  59. package/runtime/node_modules/@metro-labs/daemon/src/channels/pending.ts +75 -0
  60. package/runtime/node_modules/@metro-labs/daemon/src/channels/relay.ts +129 -0
  61. package/runtime/node_modules/@metro-labs/daemon/src/channels/webhook-note.ts +51 -0
  62. package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +148 -0
  63. package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +329 -0
  64. package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +167 -0
  65. package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +117 -0
  66. package/runtime/node_modules/@metro-labs/daemon/src/connectors/api.ts +307 -0
  67. package/runtime/node_modules/@metro-labs/daemon/src/connectors/cli-api.ts +63 -0
  68. package/runtime/node_modules/@metro-labs/daemon/src/connectors/config.ts +144 -0
  69. package/runtime/node_modules/@metro-labs/daemon/src/connectors/json.ts +21 -0
  70. package/runtime/node_modules/@metro-labs/daemon/src/connectors/model.ts +69 -0
  71. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-client.ts +159 -0
  72. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-discovery.ts +117 -0
  73. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-pending.ts +65 -0
  74. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-routes.ts +157 -0
  75. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth.ts +127 -0
  76. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-target.ts +39 -0
  77. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +295 -0
  78. package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +277 -0
  79. package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +98 -0
  80. package/runtime/node_modules/@metro-labs/daemon/src/connectors/url.ts +70 -0
  81. package/runtime/node_modules/@metro-labs/daemon/src/connectors/verify.ts +330 -0
  82. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-grant.ts +99 -0
  83. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-owner.ts +32 -0
  84. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-serve.ts +121 -0
  85. package/runtime/node_modules/@metro-labs/daemon/src/files/upload-api.ts +294 -0
  86. package/runtime/node_modules/@metro-labs/daemon/src/files/upload-store.ts +181 -0
  87. package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +252 -0
  88. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +231 -0
  89. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-device.ts +91 -0
  90. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +288 -0
  91. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +203 -0
  92. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +220 -0
  93. package/runtime/node_modules/@metro-labs/daemon/src/gateway/eventstream.ts +123 -0
  94. package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +182 -0
  95. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +197 -0
  96. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +195 -0
  97. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +198 -0
  98. package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +40 -0
  99. package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +17 -0
  100. package/runtime/node_modules/@metro-labs/daemon/src/mcp/accounts.ts +137 -0
  101. package/runtime/node_modules/@metro-labs/daemon/src/mcp/call-tools.ts +216 -0
  102. package/runtime/node_modules/@metro-labs/daemon/src/mcp/channel-owner.ts +29 -0
  103. package/runtime/node_modules/@metro-labs/daemon/src/mcp/ctx.ts +62 -0
  104. package/runtime/node_modules/@metro-labs/daemon/src/mcp/event-store.ts +91 -0
  105. package/runtime/node_modules/@metro-labs/daemon/src/mcp/frame-scope.ts +21 -0
  106. package/runtime/node_modules/@metro-labs/daemon/src/mcp/group-tools.ts +129 -0
  107. package/runtime/node_modules/@metro-labs/daemon/src/mcp/index.ts +191 -0
  108. package/runtime/node_modules/@metro-labs/daemon/src/mcp/member-tools.ts +72 -0
  109. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +66 -0
  110. package/runtime/node_modules/@metro-labs/daemon/src/mcp/raw-get-stream.ts +207 -0
  111. package/runtime/node_modules/@metro-labs/daemon/src/mcp/request-identity.ts +47 -0
  112. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-registry.ts +172 -0
  113. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-route.ts +43 -0
  114. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session.ts +215 -0
  115. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-dispatch.ts +215 -0
  116. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-schemas.ts +400 -0
  117. package/runtime/node_modules/@metro-labs/daemon/src/mcp/upload-tool.ts +66 -0
  118. package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +237 -0
  119. package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +389 -0
  120. package/runtime/node_modules/@metro-labs/daemon/src/routes/http.ts +390 -0
  121. package/runtime/node_modules/@metro-labs/daemon/src/routes/identity.ts +54 -0
  122. package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +187 -0
  123. package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +60 -0
  124. package/runtime/node_modules/@metro-labs/daemon/src/routes/session.ts +29 -0
  125. package/runtime/node_modules/@metro-labs/daemon/src/server/control.ts +64 -0
  126. package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +61 -0
  127. package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +116 -0
  128. package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
  129. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-inline.ts +100 -0
  130. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-interactive.ts +161 -0
  131. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-resolve.ts +202 -0
  132. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-session.ts +280 -0
  133. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-xmtp.ts +111 -0
  134. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach.ts +184 -0
  135. package/runtime/node_modules/@metro-labs/daemon/src/stations/materialize.ts +248 -0
  136. package/runtime/node_modules/@metro-labs/daemon/src/stations/registry.ts +35 -0
  137. package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +82 -0
  138. package/runtime/node_modules/@metro-labs/daemon/src/stations/supervisor-io.ts +97 -0
  139. package/runtime/node_modules/@metro-labs/daemon/src/stations/supervisor.ts +320 -0
  140. package/runtime/node_modules/@metro-labs/daemon/src/stations/train-call.ts +22 -0
  141. package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +71 -0
  142. package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +123 -0
  143. package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +40 -0
  144. package/runtime/node_modules/@metro-labs/discord-bot/package.json +28 -0
  145. package/runtime/node_modules/@metro-labs/discord-bot/src/accounts.ts +118 -0
  146. package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +388 -0
  147. package/runtime/node_modules/@metro-labs/discord-bot/src/api-base.ts +1 -0
  148. package/runtime/node_modules/@metro-labs/discord-bot/src/attachments.ts +29 -0
  149. package/runtime/node_modules/@metro-labs/discord-bot/src/format.ts +220 -0
  150. package/runtime/node_modules/@metro-labs/discord-bot/src/group-actions.ts +50 -0
  151. package/runtime/node_modules/@metro-labs/discord-bot/src/group.ts +115 -0
  152. package/runtime/node_modules/@metro-labs/discord-bot/src/index.ts +127 -0
  153. package/runtime/node_modules/@metro-labs/discord-bot/src/members.ts +215 -0
  154. package/runtime/node_modules/@metro-labs/discord-bot/src/send-files.ts +43 -0
  155. package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +19 -0
  156. package/runtime/node_modules/@metro-labs/discord-bot/src/verify.ts +82 -0
  157. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-speak.ts +195 -0
  158. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-transcribe.ts +292 -0
  159. package/runtime/node_modules/@metro-labs/discord-bot/src/voice.ts +197 -0
  160. package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +5 -0
  161. package/runtime/node_modules/@metro-labs/http/package.json +33 -0
  162. package/runtime/node_modules/@metro-labs/http/src/api-error.ts +8 -0
  163. package/runtime/node_modules/@metro-labs/http/src/api-http.ts +95 -0
  164. package/runtime/node_modules/@metro-labs/http/src/cors.ts +29 -0
  165. package/runtime/node_modules/@metro-labs/http/src/identity-key.ts +33 -0
  166. package/runtime/node_modules/@metro-labs/http/src/identity-registry.ts +13 -0
  167. package/runtime/node_modules/@metro-labs/http/src/mode-api.ts +32 -0
  168. package/runtime/node_modules/@metro-labs/http/src/return-to.ts +21 -0
  169. package/runtime/node_modules/@metro-labs/http/src/signed-identity.ts +36 -0
  170. package/runtime/node_modules/@metro-labs/telegram/package.json +26 -0
  171. package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +80 -0
  172. package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +254 -0
  173. package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +87 -0
  174. package/runtime/node_modules/@metro-labs/telegram/src/client.ts +77 -0
  175. package/runtime/node_modules/@metro-labs/telegram/src/format.ts +156 -0
  176. package/runtime/node_modules/@metro-labs/telegram/src/group.ts +261 -0
  177. package/runtime/node_modules/@metro-labs/telegram/src/history.ts +52 -0
  178. package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +78 -0
  179. package/runtime/node_modules/@metro-labs/telegram/src/index.ts +46 -0
  180. package/runtime/node_modules/@metro-labs/telegram/src/login.ts +166 -0
  181. package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +80 -0
  182. package/runtime/node_modules/@metro-labs/telegram/src/members.ts +75 -0
  183. package/runtime/node_modules/@metro-labs/telegram/src/normalize.ts +22 -0
  184. package/runtime/node_modules/@metro-labs/telegram/src/reactions.ts +167 -0
  185. package/runtime/node_modules/@metro-labs/telegram/src/station.ts +24 -0
  186. package/runtime/node_modules/@metro-labs/telegram/src/types.ts +7 -0
  187. package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +1 -0
  188. package/runtime/node_modules/@metro-labs/telegram-bot/package.json +25 -0
  189. package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +120 -0
  190. package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +295 -0
  191. package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +128 -0
  192. package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +201 -0
  193. package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +109 -0
  194. package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +166 -0
  195. package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +47 -0
  196. package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +17 -0
  197. package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +58 -0
  198. package/runtime/node_modules/@metro-labs/telegram-bot/src/verify.ts +38 -0
  199. package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +3 -0
  200. package/runtime/node_modules/@metro-labs/webhook/package.json +23 -0
  201. package/runtime/node_modules/@metro-labs/webhook/src/station.ts +37 -0
  202. package/runtime/node_modules/@metro-labs/whatsapp/package.json +27 -0
  203. package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +66 -0
  204. package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +101 -0
  205. package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +178 -0
  206. package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +72 -0
  207. package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +129 -0
  208. package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +327 -0
  209. package/runtime/node_modules/@metro-labs/whatsapp/src/delivery.ts +49 -0
  210. package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +138 -0
  211. package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +57 -0
  212. package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +40 -0
  213. package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +59 -0
  214. package/runtime/node_modules/@metro-labs/whatsapp/src/logger.ts +60 -0
  215. package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +176 -0
  216. package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +84 -0
  217. package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +22 -0
  218. package/runtime/node_modules/@metro-labs/whatsapp/src/outbox.ts +38 -0
  219. package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +185 -0
  220. package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +17 -0
  221. package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +98 -0
  222. package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +6 -0
  223. package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +5 -0
  224. package/runtime/node_modules/@metro-labs/xmtp/package.json +33 -0
  225. package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +112 -0
  226. package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +110 -0
  227. package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +299 -0
  228. package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +157 -0
  229. package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +87 -0
  230. package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +375 -0
  231. package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +107 -0
  232. package/runtime/node_modules/@metro-labs/xmtp/src/codecs.ts +171 -0
  233. package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +239 -0
  234. package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +55 -0
  235. package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +335 -0
  236. package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +80 -0
  237. package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +34 -0
  238. package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +56 -0
  239. package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +33 -0
  240. package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +125 -0
  241. package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +157 -0
  242. package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +40 -0
  243. package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +349 -0
  244. package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +13 -0
  245. package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +126 -0
  246. package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +212 -0
  247. package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +90 -0
  248. package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +84 -0
  249. package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +53 -0
  250. package/runtime/runtime.json +3 -0
  251. package/runtime/server.ts +1 -0
  252. package/runtime/stations.json +36 -0
  253. package/runtime/trains/.keep +0 -0
  254. package/LICENSE +0 -21
  255. package/README.md +0 -249
  256. package/dist/cache.js +0 -75
  257. package/dist/cli/actions.js +0 -139
  258. package/dist/cli/config.js +0 -185
  259. package/dist/cli/index.js +0 -177
  260. package/dist/cli/skill.js +0 -62
  261. package/dist/cli/util.js +0 -72
  262. package/dist/cli/webhook.js +0 -83
  263. package/dist/codex-rc.js +0 -245
  264. package/dist/dispatcher.js +0 -122
  265. package/dist/history.js +0 -99
  266. package/dist/ipc.js +0 -72
  267. package/dist/log.js +0 -15
  268. package/dist/paths.js +0 -68
  269. package/dist/registry.js +0 -48
  270. package/dist/stations/claude.js +0 -45
  271. package/dist/stations/codex.js +0 -68
  272. package/dist/stations/discord.js +0 -200
  273. package/dist/stations/index.js +0 -133
  274. package/dist/stations/telegram-md.js +0 -34
  275. package/dist/stations/telegram-upload.js +0 -113
  276. package/dist/stations/telegram.js +0 -213
  277. package/dist/stations/webhook.js +0 -100
  278. package/dist/tunnel.js +0 -49
  279. package/dist/webhooks.js +0 -40
  280. package/docs/agents.md +0 -216
  281. package/docs/uri-scheme.md +0 -125
  282. package/skills/metro/SKILL.md +0 -249
@@ -0,0 +1,84 @@
1
+ export type AgentMap = Record<string, string>;
2
+ export type AgentNameMap = Record<string, string>;
3
+ export type AllowlistMap = Record<string, string[]>;
4
+
5
+ const mapKey = (station: string, accountId: string): string =>
6
+ `${station}/${accountId}`;
7
+
8
+ let agentMap: AgentMap = {};
9
+ let agentNames: AgentNameMap = {};
10
+ let allowlistMap: AllowlistMap = {};
11
+
12
+ export function setAgentMap(map: AgentMap, names: AgentNameMap): void {
13
+ agentMap = map;
14
+ agentNames = names;
15
+ }
16
+
17
+ export function setAllowlistMap(map: AllowlistMap): void {
18
+ allowlistMap = map;
19
+ }
20
+
21
+ export function accountFromLine(
22
+ line: string,
23
+ ): { station: string; accountId: string } | undefined {
24
+ const parts = line.split('/');
25
+ const station = parts[2];
26
+ const accountId = parts[3];
27
+ if (!station || !accountId) return undefined;
28
+ return { station, accountId };
29
+ }
30
+
31
+ export function agentIdForAccount(
32
+ station: string,
33
+ accountId: string,
34
+ ): string | undefined {
35
+ return agentMap[mapKey(station, accountId)];
36
+ }
37
+
38
+ export function agentIdForLine(line: string): string | undefined {
39
+ const a = accountFromLine(line);
40
+ return a ? agentIdForAccount(a.station, a.accountId) : undefined;
41
+ }
42
+
43
+ export function agentForLine(line: string): string | undefined {
44
+ const id = agentIdForLine(line);
45
+ return id === undefined ? undefined : agentNames[id];
46
+ }
47
+
48
+ export interface KnownAccount {
49
+ station: string;
50
+ id: string;
51
+ agentId: string;
52
+ }
53
+
54
+ export function knownAccounts(): KnownAccount[] {
55
+ return Object.entries(agentMap).flatMap(([key, agentId]) => {
56
+ const cut = key.indexOf('/');
57
+ return cut === -1 ? [] : [{ station: key.slice(0, cut), id: key.slice(cut + 1), agentId }];
58
+ });
59
+ }
60
+
61
+ export function stationAgentIds(station: string): string[] {
62
+ const prefix = `${station}/`;
63
+ return Object.entries(agentMap)
64
+ .filter(([key]) => key.startsWith(prefix))
65
+ .map(([, id]) => id);
66
+ }
67
+
68
+ export function allowlistForLine(line: string): string[] | undefined {
69
+ const a = accountFromLine(line);
70
+ return a ? allowlistMap[mapKey(a.station, a.accountId)] : undefined;
71
+ }
72
+
73
+ export function senderMatchesAllowlist(
74
+ allowlist: string[],
75
+ from: string,
76
+ ): boolean {
77
+ if (allowlist.length === 0 || allowlist.includes('*')) return true;
78
+ const f = (from ?? '').toLowerCase();
79
+ const id = f.split('/').pop() ?? f;
80
+ return allowlist.some((a) => {
81
+ const v = a.toLowerCase();
82
+ return v === f || v === id;
83
+ });
84
+ }
@@ -0,0 +1,64 @@
1
+ import {
2
+ accountFromLine,
3
+ agentIdForAccount,
4
+ stationAgentIds,
5
+ } from './map.js';
6
+ import { STATIONS } from '@metro-labs/core/station-names';
7
+
8
+ const ACCOUNT_STATIONS = new Set<string>(STATIONS);
9
+
10
+ const stationHasAccounts = (station: string): boolean =>
11
+ ACCOUNT_STATIONS.has(station);
12
+
13
+ const accountInScope = (
14
+ allowed: Set<string>,
15
+ station: string,
16
+ accountId: string,
17
+ ): boolean => {
18
+ const agentId = agentIdForAccount(station, accountId);
19
+ return agentId !== undefined && allowed.has(agentId);
20
+ };
21
+
22
+ export function lineTargetDenied(
23
+ allowed: Set<string>,
24
+ args: Record<string, unknown>,
25
+ station?: string,
26
+ ): boolean {
27
+ const line = typeof args.line === 'string' ? args.line : undefined;
28
+ if (line === undefined) return false;
29
+ const acct = accountFromLine(line);
30
+ if (!acct) return true;
31
+ if (station !== undefined && acct.station !== station) return true;
32
+ if (!accountInScope(allowed, acct.station, acct.accountId)) return true;
33
+ const override = typeof args.account === 'string' ? args.account : undefined;
34
+ return override !== undefined
35
+ ? !accountInScope(allowed, acct.station, override)
36
+ : false;
37
+ }
38
+
39
+ export function stationFullyScoped(
40
+ allowed: Set<string>,
41
+ station: string,
42
+ ): boolean {
43
+ const ids = stationAgentIds(station);
44
+ return ids.length > 0 && ids.every((id) => allowed.has(id));
45
+ }
46
+
47
+ export function callTargetDenied(
48
+ allowed: Set<string>,
49
+ station: string,
50
+ args: Record<string, unknown>,
51
+ ): boolean {
52
+ if (typeof args.line === 'string')
53
+ return lineTargetDenied(allowed, args, station);
54
+ if (typeof args.account === 'string')
55
+ return !accountInScope(allowed, station, args.account);
56
+ return !stationFullyScoped(allowed, station);
57
+ }
58
+
59
+ export function eventInScope(allowed: Set<string>, line: string): boolean {
60
+ const acct = accountFromLine(line);
61
+ if (!acct) return false;
62
+ if (!stationHasAccounts(acct.station)) return true;
63
+ return accountInScope(allowed, acct.station, acct.accountId);
64
+ }
@@ -0,0 +1,176 @@
1
+ import { join } from 'node:path';
2
+ import { type Server } from 'node:http';
3
+ import { userSelf } from '@metro-labs/core/events';
4
+ import { setTrainCallBackend } from '../stations/train-call.js';
5
+ import { errMsg, log, logFatalSync } from '@metro-labs/core/log';
6
+ import { acquireLock, STATE_DIR, trainsDir } from './paths.js';
7
+ import { installCrashGuard, markDaemonReady } from './crash-guard.js';
8
+ import { METRO_VERSION } from '@metro-labs/core/version';
9
+ import { funnelDriver, Tunnel, tunnelWanted, webhookPort } from '../net/tunnel.js';
10
+ import {
11
+ localConnectHint,
12
+ publicConnectHint,
13
+ tunnelPendingHint,
14
+ } from './connect-hint.js';
15
+ import { TrainSupervisor } from '../stations/supervisor.js';
16
+ import {
17
+ makeEmit,
18
+ startWebhookServer,
19
+ trainEventToMetroEvent,
20
+ } from '../routes/http.js';
21
+ import { localAgentKey } from '../stations/materialize.js';
22
+ import { fileSource } from '../agents/files.js';
23
+ import { applyLocalOwner } from './local-owner.js';
24
+ import { localOwner } from '../agents/file-admin.js';
25
+ import { ensureStationDeps } from '../stations/runtime-deps.js';
26
+ import { localSessionApis } from '../routes/local-mode.js';
27
+ import type { SessionApis } from '../routes/session-apis.js';
28
+ import {
29
+ agentLiveness,
30
+ closeAgentSession,
31
+ createMetroMcp,
32
+ } from '../mcp/index.js';
33
+ import { metroCall } from '../mcp/ctx.js';
34
+ import { gatherAccountsForAgents } from '../mcp/accounts.js';
35
+ import {
36
+ accountStationCapabilities,
37
+ stationByName,
38
+ } from '../stations/registry.js';
39
+ import { prepareAccount } from '../stations/attach.js';
40
+ import { materializeFrom, reloadFrom } from '../stations/materialize.js';
41
+ import type { StationName } from '@metro-labs/core/station-names';
42
+ import { startUploadReaper } from '../files/upload-store.js';
43
+
44
+ installCrashGuard();
45
+ acquireLock(join(STATE_DIR, '.tail-lock'));
46
+
47
+ log.info({ self: userSelf() }, 'user identity');
48
+
49
+ process.stdout.on('error', (err) => {
50
+ if ((err as NodeJS.ErrnoException).code !== 'EPIPE')
51
+ log.warn({ err: errMsg(err) }, 'stdout error');
52
+ });
53
+
54
+ const supervisor = new TrainSupervisor();
55
+ const emit = makeEmit();
56
+
57
+ supervisor.onTrainEvent((env, train) => {
58
+ const entry = trainEventToMetroEvent(env, train);
59
+ if (entry) emit(entry);
60
+ });
61
+
62
+ let webhookServer: Server | null = null;
63
+ const tunnel = tunnelWanted() ? new Tunnel(funnelDriver(webhookPort()), announcePublic) : null;
64
+
65
+ function announcePublic(url: string): void {
66
+ process.stderr.write(`\n${publicConnectHint(url, localOwner())}`);
67
+ }
68
+
69
+ setTrainCallBackend((train, action, args) =>
70
+ supervisor.call(train, action, args),
71
+ );
72
+
73
+ function announceLocalEndpoint(): void {
74
+ process.stderr.write(
75
+ `\n${tunnel === null ? localConnectHint(webhookPort(), localOwner()) : tunnelPendingHint()}`,
76
+ );
77
+ const key = localAgentKey();
78
+ if (key === null) {
79
+ log.info('no agent on this machine yet');
80
+ return;
81
+ }
82
+ const url = `http://127.0.0.1:${String(webhookPort())}/mcp?token=${key}`;
83
+ process.stderr.write(
84
+ `\nConnect an agent on this machine:\n\n claude mcp add --transport http metro "${url}"\n\n`,
85
+ );
86
+ }
87
+
88
+ async function syncStations(station: StationName): Promise<void> {
89
+ const { removed } = await reloadFrom(fileSource);
90
+ if (stationByName(station)?.hasTrain === false) return;
91
+ if (removed.includes(station)) await supervisor.stopTrain(station);
92
+ else {
93
+ ensureStationDeps(station);
94
+ supervisor.requestReload(station);
95
+ }
96
+ }
97
+
98
+ function sessionApis(): SessionApis {
99
+ return localSessionApis({
100
+ syncStations,
101
+ restart: () => {
102
+ exitCode = RESTART_EXIT;
103
+ onShutdown();
104
+ },
105
+ stop: () => {
106
+ exitCode = HOLD_EXIT;
107
+ onShutdown();
108
+ },
109
+ closeAgentSession,
110
+ gatherAccounts: gatherAccountsForAgents,
111
+ capabilities: accountStationCapabilities,
112
+ liveness: agentLiveness,
113
+ prepareAccount,
114
+ });
115
+ }
116
+
117
+ async function main(): Promise<void> {
118
+ applyLocalOwner();
119
+ await materializeFrom(fileSource, { allowEmpty: true });
120
+ supervisor.start();
121
+ const metroMcp = await createMetroMcp();
122
+ webhookServer = await startWebhookServer(
123
+ emit,
124
+ sessionApis(),
125
+ metroMcp.httpHandler,
126
+ metroCall,
127
+ );
128
+ metroMcp.startInbound();
129
+ startUploadReaper();
130
+ announceLocalEndpoint();
131
+ tunnel?.start();
132
+ log.info(
133
+ { tunnel: !!tunnel, trainsDir: trainsDir(), mcp: '/', version: METRO_VERSION },
134
+ 'dispatcher ready',
135
+ );
136
+ markDaemonReady();
137
+ }
138
+
139
+ const SHUTDOWN_TIMEOUT_MS = 3_000;
140
+ const RESTART_EXIT = 75;
141
+ const HOLD_EXIT = 76;
142
+ let exitCode = 0;
143
+ let shuttingDown = false;
144
+ async function shutdown(): Promise<void> {
145
+ if (shuttingDown) return;
146
+ shuttingDown = true;
147
+ log.info('dispatcher shutting down');
148
+ tunnel?.stop();
149
+ if (webhookServer) {
150
+ const server = webhookServer;
151
+ await Promise.race([
152
+ new Promise<void>((r) => {
153
+ server.close(() => {
154
+ r();
155
+ });
156
+ }),
157
+ new Promise<void>((r) => {
158
+ setTimeout(r, SHUTDOWN_TIMEOUT_MS).unref();
159
+ }),
160
+ ]);
161
+ }
162
+ await supervisor.stop();
163
+ process.exit(exitCode);
164
+ }
165
+ const onShutdown = (): void => {
166
+ shutdown().catch((err: unknown) => {
167
+ log.error({ err: errMsg(err) }, 'dispatcher: shutdown failed');
168
+ process.exit(1);
169
+ });
170
+ };
171
+ for (const sig of ['SIGINT', 'SIGTERM'] as const) process.on(sig, onShutdown);
172
+
173
+ await main().catch((err: unknown) => {
174
+ logFatalSync({ err: errMsg(err) }, 'dispatcher failed to start');
175
+ process.exit(1);
176
+ });
@@ -0,0 +1,39 @@
1
+ import { hostname } from 'node:os';
2
+
3
+ const uiBase = (): string => process.env.METRO_UI_URL ?? 'https://metro.box';
4
+
5
+ const connectLink = (base: string): string =>
6
+ `${uiBase()}/#/${new URL(base).host}`;
7
+
8
+ const ownerLine = (owner: string | null): string =>
9
+ owner === null
10
+ ? 'No owner is set, so no wallet can sign in. Restart with: metro serve --owner <address>'
11
+ : `Only ${owner} can sign in.`;
12
+
13
+ export function localConnectHint(port: number, owner: string | null): string {
14
+ const here = `http://127.0.0.1:${String(port)}`;
15
+ const forward = `ssh -L ${String(port)}:127.0.0.1:${String(port)} ${hostname()}`;
16
+ return [
17
+ 'Manage this machine from the web UI:',
18
+ '',
19
+ ` ${connectLink(here)}`,
20
+ '',
21
+ `From another computer, forward the port first: ${forward}`,
22
+ ownerLine(owner),
23
+ '',
24
+ ].join('\n');
25
+ }
26
+
27
+ export function publicConnectHint(url: string, owner: string | null): string {
28
+ return [
29
+ 'Manage this machine from the web UI, from anywhere:',
30
+ '',
31
+ ` ${connectLink(url)}`,
32
+ '',
33
+ ownerLine(owner),
34
+ '',
35
+ ].join('\n');
36
+ }
37
+
38
+ export const tunnelPendingHint = (): string =>
39
+ 'Publishing this daemon through Tailscale Funnel… (if Tailscale asks to enable Funnel, its link is in the log)\n';
@@ -0,0 +1,49 @@
1
+ import { errMsg, log, logFatalSync } from '@metro-labs/core/log';
2
+
3
+ export type CrashKind = 'unhandledRejection' | 'uncaughtException';
4
+
5
+ const seen: Record<CrashKind, number> = {
6
+ unhandledRejection: 0,
7
+ uncaughtException: 0,
8
+ };
9
+
10
+ let ready = false;
11
+ let installed = false;
12
+
13
+ export function markDaemonReady(): void {
14
+ ready = true;
15
+ }
16
+
17
+ export function crashCount(kind: CrashKind): number {
18
+ return seen[kind];
19
+ }
20
+
21
+ function fields(kind: CrashKind, err: unknown): Record<string, unknown> {
22
+ return {
23
+ crash: kind,
24
+ seen: seen[kind],
25
+ err: errMsg(err),
26
+ errType: err instanceof Error ? err.name : typeof err,
27
+ stack: err instanceof Error ? err.stack : undefined,
28
+ };
29
+ }
30
+
31
+ function reportCrash(kind: CrashKind, err: unknown): void {
32
+ seen[kind] += 1;
33
+ if (!ready) {
34
+ logFatalSync(fields(kind, err), 'daemon: failed before it was ready');
35
+ process.exit(1);
36
+ }
37
+ log.error(fields(kind, err), 'daemon: kept running through a crash');
38
+ }
39
+
40
+ export function installCrashGuard(): void {
41
+ if (installed) return;
42
+ installed = true;
43
+ process.on('unhandledRejection', (reason: unknown) => {
44
+ reportCrash('unhandledRejection', reason);
45
+ });
46
+ process.on('uncaughtException', (err: unknown) => {
47
+ reportCrash('uncaughtException', err);
48
+ });
49
+ }
@@ -0,0 +1,14 @@
1
+ import { localOwner, setLocalOwner } from '../agents/file-admin.js';
2
+ import { log } from '@metro-labs/core/log';
3
+
4
+ export function applyLocalOwner(): string | null {
5
+ const wanted = process.env.METRO_OWNER?.trim() ?? '';
6
+ if (wanted !== '') {
7
+ const address = setLocalOwner(wanted);
8
+ log.info({ owner: address }, 'local daemon: owner set from METRO_OWNER');
9
+ return address;
10
+ }
11
+ const stored = localOwner();
12
+ if (stored === null) log.warn('local daemon: no owner set, so no wallet can sign in; restart with metro serve --owner <address>');
13
+ return stored;
14
+ }
@@ -0,0 +1,106 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import {
3
+ closeSync,
4
+ mkdirSync,
5
+ openSync,
6
+ readFileSync,
7
+ unlinkSync,
8
+ writeSync,
9
+ } from 'node:fs';
10
+ import { homedir } from 'node:os';
11
+ import { join } from 'node:path';
12
+ import { fileURLToPath } from 'node:url';
13
+ import { log } from '@metro-labs/core/log';
14
+
15
+ export const STATE_DIR =
16
+ process.env.METRO_STATE_DIR ?? join(homedir(), '.cache', 'metro');
17
+ mkdirSync(STATE_DIR, { recursive: true });
18
+
19
+
20
+ export function trainsDir(): string {
21
+ const env = process.env.METRO_TRAINS_DIR?.trim();
22
+ if (env !== undefined && env !== '') return env;
23
+ return fileURLToPath(new URL('../../trains', import.meta.url));
24
+ }
25
+
26
+ function readLockPid(lockFile: string): number {
27
+ try {
28
+ return Number(readFileSync(lockFile, 'utf8').trim());
29
+ } catch {
30
+ return NaN;
31
+ }
32
+ }
33
+
34
+ function namesMetro(text: string): boolean {
35
+ return text.includes('server.ts') || text.includes('metro');
36
+ }
37
+
38
+ function holderIsMetro(pid: number): boolean {
39
+ try {
40
+ return namesMetro(readFileSync(`/proc/${pid}/cmdline`, 'utf8'));
41
+ } catch {
42
+ return holderCommand(pid);
43
+ }
44
+ }
45
+
46
+ function holderCommand(pid: number): boolean {
47
+ try {
48
+ return namesMetro(
49
+ execFileSync('ps', ['-o', 'command=', '-p', String(pid)], {
50
+ encoding: 'utf8',
51
+ stdio: ['ignore', 'pipe', 'ignore'],
52
+ }),
53
+ );
54
+ } catch {
55
+ return false;
56
+ }
57
+ }
58
+
59
+ export function lockHeldByLiveDaemon(pid: number): boolean {
60
+ if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
61
+ try {
62
+ process.kill(pid, 0);
63
+ } catch {
64
+ return false;
65
+ }
66
+ return holderIsMetro(pid);
67
+ }
68
+
69
+ function writeOwnLock(lockFile: string): void {
70
+ const fd = openSync(lockFile, 'wx');
71
+ writeSync(fd, String(process.pid));
72
+ closeSync(fd);
73
+ process.on('exit', () => {
74
+ try {
75
+ if (readFileSync(lockFile, 'utf8').trim() === String(process.pid))
76
+ unlinkSync(lockFile);
77
+ } catch {
78
+ }
79
+ });
80
+ }
81
+
82
+ export function acquireLock(lockFile: string): void {
83
+ for (let attempt = 0; attempt < 5; attempt++) {
84
+ try {
85
+ writeOwnLock(lockFile);
86
+ return;
87
+ } catch (err) {
88
+ if ((err as NodeJS.ErrnoException).code !== 'EEXIST') throw err;
89
+ const pid = readLockPid(lockFile);
90
+ if (lockHeldByLiveDaemon(pid)) {
91
+ log.info(
92
+ { pid },
93
+ 'a healthy `metro` daemon is already running; exiting (no second dispatcher)',
94
+ );
95
+ process.exit(0);
96
+ }
97
+ try {
98
+ unlinkSync(lockFile);
99
+ } catch {
100
+ }
101
+ }
102
+ }
103
+ throw new Error(
104
+ `metro: could not acquire dispatcher lock (${lockFile}) after retries`,
105
+ );
106
+ }
@@ -0,0 +1,25 @@
1
+ import { str } from '@metro-labs/core/str';
2
+
3
+ export type Addressed = 'direct' | 'mention' | 'reply';
4
+
5
+ interface AddressFacts {
6
+ isPrivate?: unknown;
7
+ mentionsSelf?: unknown;
8
+ replyToSelf?: unknown;
9
+ }
10
+
11
+ export function addressedBy(facts: AddressFacts, replyTo: string, sent: ReadonlySet<string>): Addressed | undefined {
12
+ if (facts.isPrivate === true) return 'direct';
13
+ if (facts.mentionsSelf === true) return 'mention';
14
+ if (facts.replyToSelf === true || (replyTo !== '' && sent.has(replyTo))) return 'reply';
15
+ return undefined;
16
+ }
17
+
18
+ export function replyMeta(ev: Record<string, unknown>, sent: ReadonlySet<string>): Record<string, string> {
19
+ const replyTo = str(ev.replyTo);
20
+ const addressed = addressedBy(ev, replyTo, sent);
21
+ return {
22
+ ...(replyTo ? { reply_to: replyTo } : {}),
23
+ ...(addressed === undefined ? {} : { addressed }),
24
+ };
25
+ }
@@ -0,0 +1,24 @@
1
+ import { accountFromLine, agentIdForAccount } from '../agents/map.js';
2
+
3
+ const accountStrippedLine = (line: string): string => {
4
+ const parts = line.split('/');
5
+ if (parts.length < 5) return line;
6
+ return [parts[0], parts[1], parts[2], ...parts.slice(4)].join('/');
7
+ };
8
+
9
+ export const dedupeOwner = (line: string): string => {
10
+ const acct = accountFromLine(line);
11
+ if (!acct) return 'unowned';
12
+ const agentId = agentIdForAccount(acct.station, acct.accountId);
13
+ return agentId === undefined
14
+ ? `account:${acct.accountId}`
15
+ : `agent:${agentId}`;
16
+ };
17
+
18
+ export const dedupeKey = (
19
+ station: string,
20
+ line: string,
21
+ kind: string,
22
+ messageId: string,
23
+ ): string =>
24
+ `${dedupeOwner(line)} ${station} ${accountStrippedLine(line)} ${kind} ${messageId}`;