@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.
Files changed (327) hide show
  1. package/dist/api.js +9 -0
  2. package/dist/claude-settings.js +40 -0
  3. package/dist/claude.js +182 -0
  4. package/dist/cli.js +86 -0
  5. package/dist/control.js +74 -0
  6. package/dist/hold.js +211 -0
  7. package/dist/local.js +77 -0
  8. package/dist/mcp-config.js +25 -0
  9. package/dist/node-name.js +71 -0
  10. package/dist/onboarding.js +43 -0
  11. package/dist/provider-flags.js +9 -0
  12. package/dist/route.js +50 -0
  13. package/dist/runtime-install.js +97 -0
  14. package/dist/runtime.js +74 -0
  15. package/dist/serve.js +155 -0
  16. package/dist/service.js +242 -0
  17. package/dist/tail.js +119 -0
  18. package/dist/update.js +45 -0
  19. package/dist/version.js +97 -0
  20. package/package.json +14 -28
  21. package/runtime/marketplace/.claude-plugin/marketplace.json +12 -0
  22. package/runtime/marketplace/plugin/.claude-plugin/plugin.json +18 -0
  23. package/runtime/marketplace/plugin/.mcp.json +1 -0
  24. package/runtime/marketplace/plugin/bin/guard.mjs +55 -0
  25. package/runtime/marketplace/plugin/bin/metro-plugin.mjs +40 -0
  26. package/runtime/marketplace/plugin/bin/session-start.mjs +31 -0
  27. package/runtime/marketplace/plugin/hooks/hooks.json +25 -0
  28. package/runtime/marketplace/plugin/orchestrator.md +16 -0
  29. package/runtime/node_modules/@metro-labs/core/package.json +43 -0
  30. package/runtime/node_modules/@metro-labs/core/src/address.ts +6 -0
  31. package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
  32. package/runtime/node_modules/@metro-labs/core/src/events.ts +120 -0
  33. package/runtime/node_modules/@metro-labs/core/src/identity.ts +7 -0
  34. package/runtime/node_modules/@metro-labs/core/src/ids.ts +21 -0
  35. package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
  36. package/runtime/node_modules/@metro-labs/core/src/lines.ts +87 -0
  37. package/runtime/node_modules/@metro-labs/core/src/log.ts +42 -0
  38. package/runtime/node_modules/@metro-labs/core/src/protocol.ts +226 -0
  39. package/runtime/node_modules/@metro-labs/core/src/secure-fs.ts +57 -0
  40. package/runtime/node_modules/@metro-labs/core/src/station-names.ts +13 -0
  41. package/runtime/node_modules/@metro-labs/core/src/stations/account-store.ts +60 -0
  42. package/runtime/node_modules/@metro-labs/core/src/stations/attachments.ts +196 -0
  43. package/runtime/node_modules/@metro-labs/core/src/stations/messaging-normalize.ts +88 -0
  44. package/runtime/node_modules/@metro-labs/core/src/stations/station-runtime.ts +64 -0
  45. package/runtime/node_modules/@metro-labs/core/src/stations/types.ts +108 -0
  46. package/runtime/node_modules/@metro-labs/core/src/str.ts +5 -0
  47. package/runtime/node_modules/@metro-labs/core/src/train-error.ts +53 -0
  48. package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
  49. package/runtime/node_modules/@metro-labs/daemon/package.json +47 -0
  50. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-attach.ts +19 -0
  51. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-routes.ts +70 -0
  52. package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +365 -0
  53. package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +39 -0
  54. package/runtime/node_modules/@metro-labs/daemon/src/agents/allowlist.ts +37 -0
  55. package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +225 -0
  56. package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +122 -0
  57. package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +364 -0
  58. package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +185 -0
  59. package/runtime/node_modules/@metro-labs/daemon/src/agents/keys.ts +40 -0
  60. package/runtime/node_modules/@metro-labs/daemon/src/agents/map.ts +95 -0
  61. package/runtime/node_modules/@metro-labs/daemon/src/agents/scope.ts +64 -0
  62. package/runtime/node_modules/@metro-labs/daemon/src/agents/senders.ts +38 -0
  63. package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +200 -0
  64. package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +39 -0
  65. package/runtime/node_modules/@metro-labs/daemon/src/boot/crash-guard.ts +49 -0
  66. package/runtime/node_modules/@metro-labs/daemon/src/boot/local-owner.ts +30 -0
  67. package/runtime/node_modules/@metro-labs/daemon/src/boot/paths.ts +106 -0
  68. package/runtime/node_modules/@metro-labs/daemon/src/channels/addressed.ts +25 -0
  69. package/runtime/node_modules/@metro-labs/daemon/src/channels/dedupe.ts +24 -0
  70. package/runtime/node_modules/@metro-labs/daemon/src/channels/inbound.ts +380 -0
  71. package/runtime/node_modules/@metro-labs/daemon/src/channels/media-note.ts +85 -0
  72. package/runtime/node_modules/@metro-labs/daemon/src/channels/pending.ts +75 -0
  73. package/runtime/node_modules/@metro-labs/daemon/src/channels/relay.ts +129 -0
  74. package/runtime/node_modules/@metro-labs/daemon/src/channels/webhook-note.ts +51 -0
  75. package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +354 -0
  76. package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +358 -0
  77. package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +169 -0
  78. package/runtime/node_modules/@metro-labs/daemon/src/claude/onboarding.ts +56 -0
  79. package/runtime/node_modules/@metro-labs/daemon/src/claude/plugin-install.ts +140 -0
  80. package/runtime/node_modules/@metro-labs/daemon/src/claude/session-files.ts +90 -0
  81. package/runtime/node_modules/@metro-labs/daemon/src/claude/session.ts +253 -0
  82. package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +117 -0
  83. package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +263 -0
  84. package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +118 -0
  85. package/runtime/node_modules/@metro-labs/daemon/src/claude/version.ts +109 -0
  86. package/runtime/node_modules/@metro-labs/daemon/src/connectors/api.ts +313 -0
  87. package/runtime/node_modules/@metro-labs/daemon/src/connectors/config.ts +157 -0
  88. package/runtime/node_modules/@metro-labs/daemon/src/connectors/health.ts +18 -0
  89. package/runtime/node_modules/@metro-labs/daemon/src/connectors/model.ts +69 -0
  90. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-client.ts +166 -0
  91. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-discovery.ts +139 -0
  92. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-pending.ts +65 -0
  93. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-routes.ts +171 -0
  94. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth.ts +155 -0
  95. package/runtime/node_modules/@metro-labs/daemon/src/connectors/plugin-sync.ts +122 -0
  96. package/runtime/node_modules/@metro-labs/daemon/src/connectors/reach.ts +27 -0
  97. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-target.ts +39 -0
  98. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +304 -0
  99. package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +299 -0
  100. package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +108 -0
  101. package/runtime/node_modules/@metro-labs/daemon/src/connectors/url.ts +59 -0
  102. package/runtime/node_modules/@metro-labs/daemon/src/connectors/verify.ts +101 -0
  103. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-grant.ts +99 -0
  104. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-owner.ts +32 -0
  105. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-serve.ts +121 -0
  106. package/runtime/node_modules/@metro-labs/daemon/src/files/upload-api.ts +294 -0
  107. package/runtime/node_modules/@metro-labs/daemon/src/files/upload-store.ts +181 -0
  108. package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +259 -0
  109. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +231 -0
  110. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-device.ts +91 -0
  111. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +288 -0
  112. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +203 -0
  113. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +231 -0
  114. package/runtime/node_modules/@metro-labs/daemon/src/gateway/eventstream.ts +123 -0
  115. package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +187 -0
  116. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +247 -0
  117. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-auth.ts +182 -0
  118. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-client.ts +46 -0
  119. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-setup.ts +150 -0
  120. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-stream.ts +148 -0
  121. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-translate.ts +201 -0
  122. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini.ts +257 -0
  123. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +353 -0
  124. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +232 -0
  125. package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +90 -0
  126. package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +65 -0
  127. package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +17 -0
  128. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +242 -0
  129. package/runtime/node_modules/@metro-labs/daemon/src/mcp/accounts.ts +151 -0
  130. package/runtime/node_modules/@metro-labs/daemon/src/mcp/call-tools.ts +216 -0
  131. package/runtime/node_modules/@metro-labs/daemon/src/mcp/channel-owner.ts +29 -0
  132. package/runtime/node_modules/@metro-labs/daemon/src/mcp/ctx.ts +62 -0
  133. package/runtime/node_modules/@metro-labs/daemon/src/mcp/event-store.ts +91 -0
  134. package/runtime/node_modules/@metro-labs/daemon/src/mcp/frame-scope.ts +21 -0
  135. package/runtime/node_modules/@metro-labs/daemon/src/mcp/group-tools.ts +129 -0
  136. package/runtime/node_modules/@metro-labs/daemon/src/mcp/index.ts +186 -0
  137. package/runtime/node_modules/@metro-labs/daemon/src/mcp/member-tools.ts +72 -0
  138. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +66 -0
  139. package/runtime/node_modules/@metro-labs/daemon/src/mcp/raw-get-stream.ts +207 -0
  140. package/runtime/node_modules/@metro-labs/daemon/src/mcp/request-identity.ts +47 -0
  141. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-registry.ts +172 -0
  142. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-route.ts +43 -0
  143. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session.ts +215 -0
  144. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-dispatch.ts +215 -0
  145. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-schemas.ts +400 -0
  146. package/runtime/node_modules/@metro-labs/daemon/src/mcp/upload-tool.ts +66 -0
  147. package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +237 -0
  148. package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +389 -0
  149. package/runtime/node_modules/@metro-labs/daemon/src/routes/bearer.ts +35 -0
  150. package/runtime/node_modules/@metro-labs/daemon/src/routes/body.ts +24 -0
  151. package/runtime/node_modules/@metro-labs/daemon/src/routes/http.ts +370 -0
  152. package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +210 -0
  153. package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +58 -0
  154. package/runtime/node_modules/@metro-labs/daemon/src/routes/session.ts +29 -0
  155. package/runtime/node_modules/@metro-labs/daemon/src/routes/threema-callback.ts +103 -0
  156. package/runtime/node_modules/@metro-labs/daemon/src/server/control.ts +65 -0
  157. package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +80 -0
  158. package/runtime/node_modules/@metro-labs/daemon/src/server/owner.ts +48 -0
  159. package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +117 -0
  160. package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
  161. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-inline.ts +100 -0
  162. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-interactive.ts +161 -0
  163. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-resolve.ts +202 -0
  164. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-session.ts +280 -0
  165. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-xmtp.ts +111 -0
  166. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach.ts +248 -0
  167. package/runtime/node_modules/@metro-labs/daemon/src/stations/materialize.ts +261 -0
  168. package/runtime/node_modules/@metro-labs/daemon/src/stations/registry.ts +37 -0
  169. package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +82 -0
  170. package/runtime/node_modules/@metro-labs/daemon/src/stations/supervisor-io.ts +97 -0
  171. package/runtime/node_modules/@metro-labs/daemon/src/stations/supervisor.ts +320 -0
  172. package/runtime/node_modules/@metro-labs/daemon/src/stations/threema-callbacks.ts +32 -0
  173. package/runtime/node_modules/@metro-labs/daemon/src/stations/train-call.ts +22 -0
  174. package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +97 -0
  175. package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +123 -0
  176. package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +40 -0
  177. package/runtime/node_modules/@metro-labs/discord-bot/package.json +28 -0
  178. package/runtime/node_modules/@metro-labs/discord-bot/src/accounts.ts +118 -0
  179. package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +388 -0
  180. package/runtime/node_modules/@metro-labs/discord-bot/src/api-base.ts +1 -0
  181. package/runtime/node_modules/@metro-labs/discord-bot/src/attachments.ts +29 -0
  182. package/runtime/node_modules/@metro-labs/discord-bot/src/format.ts +220 -0
  183. package/runtime/node_modules/@metro-labs/discord-bot/src/group-actions.ts +50 -0
  184. package/runtime/node_modules/@metro-labs/discord-bot/src/group.ts +115 -0
  185. package/runtime/node_modules/@metro-labs/discord-bot/src/index.ts +127 -0
  186. package/runtime/node_modules/@metro-labs/discord-bot/src/members.ts +215 -0
  187. package/runtime/node_modules/@metro-labs/discord-bot/src/send-files.ts +43 -0
  188. package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +19 -0
  189. package/runtime/node_modules/@metro-labs/discord-bot/src/verify.ts +82 -0
  190. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-speak.ts +195 -0
  191. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-transcribe.ts +292 -0
  192. package/runtime/node_modules/@metro-labs/discord-bot/src/voice.ts +197 -0
  193. package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +5 -0
  194. package/runtime/node_modules/@metro-labs/http/package.json +29 -0
  195. package/runtime/node_modules/@metro-labs/http/src/api-error.ts +8 -0
  196. package/runtime/node_modules/@metro-labs/http/src/api-http.ts +106 -0
  197. package/runtime/node_modules/@metro-labs/http/src/cors.ts +29 -0
  198. package/runtime/node_modules/@metro-labs/http/src/mode-api.ts +32 -0
  199. package/runtime/node_modules/@metro-labs/http/src/return-to.ts +21 -0
  200. package/runtime/node_modules/@metro-labs/http/src/workos-token.ts +150 -0
  201. package/runtime/node_modules/@metro-labs/telegram/package.json +26 -0
  202. package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +80 -0
  203. package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +254 -0
  204. package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +87 -0
  205. package/runtime/node_modules/@metro-labs/telegram/src/client.ts +77 -0
  206. package/runtime/node_modules/@metro-labs/telegram/src/format.ts +156 -0
  207. package/runtime/node_modules/@metro-labs/telegram/src/group.ts +261 -0
  208. package/runtime/node_modules/@metro-labs/telegram/src/history.ts +52 -0
  209. package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +78 -0
  210. package/runtime/node_modules/@metro-labs/telegram/src/index.ts +46 -0
  211. package/runtime/node_modules/@metro-labs/telegram/src/login.ts +166 -0
  212. package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +80 -0
  213. package/runtime/node_modules/@metro-labs/telegram/src/members.ts +75 -0
  214. package/runtime/node_modules/@metro-labs/telegram/src/normalize.ts +22 -0
  215. package/runtime/node_modules/@metro-labs/telegram/src/reactions.ts +167 -0
  216. package/runtime/node_modules/@metro-labs/telegram/src/station.ts +24 -0
  217. package/runtime/node_modules/@metro-labs/telegram/src/types.ts +7 -0
  218. package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +1 -0
  219. package/runtime/node_modules/@metro-labs/telegram-bot/package.json +25 -0
  220. package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +120 -0
  221. package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +295 -0
  222. package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +128 -0
  223. package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +201 -0
  224. package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +109 -0
  225. package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +166 -0
  226. package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +47 -0
  227. package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +17 -0
  228. package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +58 -0
  229. package/runtime/node_modules/@metro-labs/telegram-bot/src/verify.ts +38 -0
  230. package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +3 -0
  231. package/runtime/node_modules/@metro-labs/threema/package.json +26 -0
  232. package/runtime/node_modules/@metro-labs/threema/src/accounts.ts +100 -0
  233. package/runtime/node_modules/@metro-labs/threema/src/actions.ts +223 -0
  234. package/runtime/node_modules/@metro-labs/threema/src/api.ts +130 -0
  235. package/runtime/node_modules/@metro-labs/threema/src/crypto.ts +132 -0
  236. package/runtime/node_modules/@metro-labs/threema/src/format.ts +123 -0
  237. package/runtime/node_modules/@metro-labs/threema/src/ids.ts +21 -0
  238. package/runtime/node_modules/@metro-labs/threema/src/index.ts +29 -0
  239. package/runtime/node_modules/@metro-labs/threema/src/station.ts +10 -0
  240. package/runtime/node_modules/@metro-labs/threema/src/verify.ts +117 -0
  241. package/runtime/node_modules/@metro-labs/webhook/package.json +23 -0
  242. package/runtime/node_modules/@metro-labs/webhook/src/station.ts +37 -0
  243. package/runtime/node_modules/@metro-labs/whatsapp/package.json +27 -0
  244. package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +66 -0
  245. package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +101 -0
  246. package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +190 -0
  247. package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +72 -0
  248. package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +129 -0
  249. package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +347 -0
  250. package/runtime/node_modules/@metro-labs/whatsapp/src/delivery.ts +49 -0
  251. package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +138 -0
  252. package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +57 -0
  253. package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +40 -0
  254. package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +59 -0
  255. package/runtime/node_modules/@metro-labs/whatsapp/src/logger.ts +60 -0
  256. package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +176 -0
  257. package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +84 -0
  258. package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +22 -0
  259. package/runtime/node_modules/@metro-labs/whatsapp/src/outbox.ts +38 -0
  260. package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +185 -0
  261. package/runtime/node_modules/@metro-labs/whatsapp/src/resolve.ts +52 -0
  262. package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +18 -0
  263. package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +98 -0
  264. package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +6 -0
  265. package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +5 -0
  266. package/runtime/node_modules/@metro-labs/xmtp/package.json +33 -0
  267. package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +112 -0
  268. package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +110 -0
  269. package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +299 -0
  270. package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +157 -0
  271. package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +87 -0
  272. package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +375 -0
  273. package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +107 -0
  274. package/runtime/node_modules/@metro-labs/xmtp/src/codecs.ts +171 -0
  275. package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +239 -0
  276. package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +55 -0
  277. package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +335 -0
  278. package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +80 -0
  279. package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +34 -0
  280. package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +56 -0
  281. package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +33 -0
  282. package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +125 -0
  283. package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +157 -0
  284. package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +40 -0
  285. package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +349 -0
  286. package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +13 -0
  287. package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +126 -0
  288. package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +212 -0
  289. package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +90 -0
  290. package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +84 -0
  291. package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +53 -0
  292. package/runtime/runtime.json +3 -0
  293. package/runtime/server.ts +1 -0
  294. package/runtime/stations.json +37 -0
  295. package/runtime/trains/.keep +0 -0
  296. package/LICENSE +0 -21
  297. package/README.md +0 -139
  298. package/dist/broker/claims.js +0 -144
  299. package/dist/broker/history-stream.js +0 -149
  300. package/dist/cli/config.js +0 -179
  301. package/dist/cli/index.js +0 -175
  302. package/dist/cli/messenger-api.js +0 -214
  303. package/dist/cli/messenger-transcribe.js +0 -43
  304. package/dist/cli/messenger-uploads.js +0 -116
  305. package/dist/cli/monitor-api.js +0 -205
  306. package/dist/cli/tail.js +0 -95
  307. package/dist/cli/util.js +0 -72
  308. package/dist/cli/webhook.js +0 -181
  309. package/dist/codex-rc/client.js +0 -225
  310. package/dist/codex-rc/protocol.js +0 -38
  311. package/dist/dispatcher/server.js +0 -122
  312. package/dist/dispatcher.js +0 -97
  313. package/dist/history.js +0 -143
  314. package/dist/ipc.js +0 -90
  315. package/dist/lines.js +0 -54
  316. package/dist/local-identity.js +0 -80
  317. package/dist/log.js +0 -15
  318. package/dist/paths.js +0 -114
  319. package/dist/trains/protocol.js +0 -99
  320. package/dist/trains/supervisor.js +0 -210
  321. package/dist/tunnel.js +0 -102
  322. package/docs/broker.md +0 -166
  323. package/docs/monitor.md +0 -241
  324. package/docs/uri-scheme.md +0 -127
  325. package/examples/README.md +0 -32
  326. package/examples/telegram.ts +0 -121
  327. package/skills/metro/SKILL.md +0 -110
@@ -0,0 +1,25 @@
1
+ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ const METRO_SERVER = 'metro';
5
+ export function metroMcpConfig(agentKey, port) {
6
+ const servers = {
7
+ [METRO_SERVER]: {
8
+ type: 'http',
9
+ url: `http://127.0.0.1:${String(port)}/mcp`,
10
+ headers: { Authorization: `Bearer ${agentKey}` },
11
+ },
12
+ };
13
+ return `${JSON.stringify({ mcpServers: servers }, null, 2)}\n`;
14
+ }
15
+ export function writeMcpConfig(agentKey, port, base = tmpdir()) {
16
+ const dir = mkdtempSync(join(base, 'metro-claude-'));
17
+ const path = join(dir, 'mcp.json');
18
+ writeFileSync(path, metroMcpConfig(agentKey, port), { mode: 0o600 });
19
+ return {
20
+ path,
21
+ cleanup: () => {
22
+ rmSync(dir, { recursive: true, force: true });
23
+ },
24
+ };
25
+ }
@@ -0,0 +1,71 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { randomBytes } from 'node:crypto';
3
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { agentsDir } from './local.js';
6
+ const NODE_FILE = '.node';
7
+ const ALPHABET = 'abcdefghjkmnpqrstuvwxyz23456789';
8
+ const NAME_RE = /^metro-[a-z0-9](?:[a-z0-9-]{0,38}[a-z0-9])?$/;
9
+ const RENAME_WAIT_MS = 30_000;
10
+ const RENAME_POLL_MS = 500;
11
+ const renameWaitMs = () => Number(process.env.METRO_NODE_RENAME_WAIT_MS) || RENAME_WAIT_MS;
12
+ const pause = (ms) => {
13
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
14
+ };
15
+ const stderrLine = (line) => {
16
+ process.stderr.write(`${line}\n`);
17
+ };
18
+ export function newNodeName() {
19
+ const bytes = randomBytes(6);
20
+ return `metro-${[...bytes].map((b) => ALPHABET[b % ALPHABET.length] ?? 'x').join('')}`;
21
+ }
22
+ export function nodeName(dir = agentsDir()) {
23
+ const path = join(dir, NODE_FILE);
24
+ if (existsSync(path)) {
25
+ const held = readFileSync(path, 'utf8').trim();
26
+ if (NAME_RE.test(held))
27
+ return held;
28
+ }
29
+ const name = newNodeName();
30
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
31
+ writeFileSync(path, `${name}\n`, { mode: 0o600 });
32
+ return name;
33
+ }
34
+ export function currentNodeLabel(bin) {
35
+ const run = spawnSync(bin, ['status', '--json'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
36
+ if (run.error !== undefined || run.status !== 0)
37
+ return null;
38
+ try {
39
+ const parsed = JSON.parse(run.stdout);
40
+ const dns = typeof parsed.Self?.DNSName === 'string' ? parsed.Self.DNSName : '';
41
+ const label = dns.split('.')[0] ?? '';
42
+ return label === '' ? null : label.toLowerCase();
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ }
48
+ function awaitRename(bin, wanted, warn) {
49
+ const wait = renameWaitMs();
50
+ const until = Date.now() + wait;
51
+ while (Date.now() < until) {
52
+ if (currentNodeLabel(bin) === wanted)
53
+ return;
54
+ pause(RENAME_POLL_MS);
55
+ }
56
+ warn(`tailscale still reports the old machine name after ${String(Math.round(wait / 1000))}s; the Funnel address may come up under it until the next restart`);
57
+ }
58
+ export function ensureNodeName(bin, dir = agentsDir(), warn = stderrLine) {
59
+ const wanted = nodeName(dir);
60
+ if (currentNodeLabel(bin) === wanted)
61
+ return wanted;
62
+ const run = spawnSync(bin, ['set', '--hostname', wanted], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
63
+ if (run.error !== undefined || run.status !== 0) {
64
+ const said = run.stderr.trim();
65
+ const reason = said === '' ? (run.error?.message ?? `exit ${String(run.status)}`) : said;
66
+ throw new Error(`could not name this machine ${wanted} on your tailnet (${reason}).\n` +
67
+ `Run it once yourself, then start again: sudo tailscale set --hostname ${wanted}`);
68
+ }
69
+ awaitRename(bin, wanted, warn);
70
+ return wanted;
71
+ }
@@ -0,0 +1,43 @@
1
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ const FILE = '.claude.json';
5
+ const FLAG = 'hasCompletedOnboarding';
6
+ const given = (value) => value !== undefined && value.trim() !== '' ? value.trim() : undefined;
7
+ export function claudeConfigPath(env = process.env) {
8
+ return join(given(env.CLAUDE_CONFIG_DIR) ?? given(env.HOME) ?? homedir(), FILE);
9
+ }
10
+ function readConfig(path) {
11
+ if (!existsSync(path))
12
+ return {};
13
+ try {
14
+ const parsed = JSON.parse(readFileSync(path, 'utf8'));
15
+ return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed) ? parsed : null;
16
+ }
17
+ catch {
18
+ return null;
19
+ }
20
+ }
21
+ export function markOnboardingDone(path = claudeConfigPath()) {
22
+ const config = readConfig(path);
23
+ if (config === null)
24
+ return 'unreadable';
25
+ if (config[FLAG] === true)
26
+ return 'already';
27
+ writeFileSync(path, `${JSON.stringify({ ...config, [FLAG]: true }, null, 2)}\n`, { mode: 0o600 });
28
+ return 'marked';
29
+ }
30
+ const FEATURES = 'cachedGrowthBookFeatures';
31
+ const CHANNELS_FLAG = 'tengu_harbor';
32
+ const isRecord = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
33
+ export function seedChannels(path = claudeConfigPath()) {
34
+ const config = readConfig(path);
35
+ if (config === null)
36
+ return 'unreadable';
37
+ const features = isRecord(config[FEATURES]) ? config[FEATURES] : {};
38
+ if (features[CHANNELS_FLAG] === true)
39
+ return 'already';
40
+ const next = { ...config, [FEATURES]: { ...features, [CHANNELS_FLAG]: true } };
41
+ writeFileSync(path, `${JSON.stringify(next, null, 2)}\n`, { mode: 0o600 });
42
+ return 'marked';
43
+ }
@@ -0,0 +1,9 @@
1
+ export const PROVIDER_FLAGS = [
2
+ 'CLAUDE_CODE_USE_BEDROCK',
3
+ 'CLAUDE_CODE_USE_MANTLE',
4
+ 'CLAUDE_CODE_USE_VERTEX',
5
+ 'CLAUDE_CODE_USE_FOUNDRY',
6
+ 'CLAUDE_CODE_USE_ANTHROPIC_AWS',
7
+ 'CLAUDE_CODE_USE_ANTHROPIC_GOOGLE_CLOUD',
8
+ 'CLAUDE_CODE_USE_GATEWAY',
9
+ ];
package/dist/route.js ADDED
@@ -0,0 +1,50 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { agentsDir } from './local.js';
4
+ const PROVIDERS = ['bedrock', 'openrouter', 'codex', 'gemini'];
5
+ export function currentRoute(dir = agentsDir()) {
6
+ const path = join(dir, 'model.json');
7
+ if (!existsSync(path))
8
+ return null;
9
+ try {
10
+ const cfg = JSON.parse(readFileSync(path, 'utf8'));
11
+ const provider = PROVIDERS.find((p) => p === cfg.provider);
12
+ if (provider === undefined)
13
+ return null;
14
+ const block = cfg[provider];
15
+ const model = typeof block === 'object' && block !== null ? block.model : undefined;
16
+ return typeof model === 'string' && model !== '' ? `${provider}:${model}` : null;
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ }
22
+ export function routeModelEnv(env, route) {
23
+ if (route === null || (env.ANTHROPIC_MODEL ?? '').trim() !== '')
24
+ return env;
25
+ return { ...env, ANTHROPIC_MODEL: route };
26
+ }
27
+ export function permissionMode(dir = agentsDir()) {
28
+ const path = join(dir, 'claude-setup.json');
29
+ if (!existsSync(path))
30
+ return 'auto';
31
+ try {
32
+ const state = JSON.parse(readFileSync(path, 'utf8'));
33
+ return state.permissionMode === 'bypass' ? 'bypass' : 'auto';
34
+ }
35
+ catch {
36
+ return 'auto';
37
+ }
38
+ }
39
+ export function systemPrompt(dir = agentsDir()) {
40
+ const path = join(dir, 'system-prompt.md');
41
+ if (!existsSync(path))
42
+ return null;
43
+ try {
44
+ const text = readFileSync(path, 'utf8').trim();
45
+ return text === '' ? null : text;
46
+ }
47
+ catch {
48
+ return null;
49
+ }
50
+ }
@@ -0,0 +1,97 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { localStations } from './local.js';
6
+ import { STORE_ENTRY, daemonEntry, findBun, runtimeDir } from './runtime.js';
7
+ export const MANIFEST_FILE = 'stations.json';
8
+ export const MARKETPLACE = 'marketplace';
9
+ const METRO_SOURCES = join('node_modules', '@metro-labs');
10
+ const INSTALL_TIMEOUT_MS = 15 * 60_000;
11
+ export function runtimeStore() {
12
+ const env = process.env.METRO_RUNTIME_STORE?.trim() ?? '';
13
+ return env === '' ? join(homedir(), '.metro', 'runtime') : env;
14
+ }
15
+ const isRecord = (v) => typeof v === 'object' && v !== null;
16
+ const ranges = (raw) => isRecord(raw)
17
+ ? Object.fromEntries(Object.entries(raw).filter((e) => typeof e[1] === 'string'))
18
+ : {};
19
+ export function readManifest(path) {
20
+ const raw = JSON.parse(readFileSync(path, 'utf8'));
21
+ if (!isRecord(raw))
22
+ throw new Error(`${path} is not a runtime manifest`);
23
+ const stations = isRecord(raw.stations) ? raw.stations : {};
24
+ return {
25
+ core: ranges(raw.core),
26
+ stations: Object.fromEntries(Object.entries(stations).map(([name, deps]) => [name, ranges(deps)])),
27
+ };
28
+ }
29
+ export function dependenciesFor(manifest, stations) {
30
+ const out = { ...manifest.core };
31
+ for (const station of new Set(stations))
32
+ Object.assign(out, manifest.stations[station] ?? {});
33
+ return Object.fromEntries(Object.entries(out).sort(([a], [b]) => a.localeCompare(b)));
34
+ }
35
+ const packageText = (deps) => `${JSON.stringify({ name: 'metro-runtime', private: true, dependencies: deps }, null, 2)}\n`;
36
+ function readOrNull(path) {
37
+ try {
38
+ return readFileSync(path, 'utf8');
39
+ }
40
+ catch {
41
+ return null;
42
+ }
43
+ }
44
+ function copyMarketplace(sources, store) {
45
+ const staged = join(sources, MARKETPLACE);
46
+ if (!existsSync(staged))
47
+ return false;
48
+ cpSync(staged, join(store, MARKETPLACE), { recursive: true });
49
+ return true;
50
+ }
51
+ function syncSources(sources, store) {
52
+ const shim = join(sources, STORE_ENTRY);
53
+ if (existsSync(shim))
54
+ copyFileSync(shim, join(store, STORE_ENTRY));
55
+ const stamp = readOrNull(join(sources, 'runtime.json'));
56
+ if (stamp !== null && readOrNull(join(store, 'runtime.json')) === stamp)
57
+ return existsSync(join(store, MARKETPLACE)) ? false : copyMarketplace(sources, store);
58
+ rmSync(join(store, METRO_SOURCES), { recursive: true, force: true });
59
+ cpSync(join(sources, METRO_SOURCES), join(store, METRO_SOURCES), { recursive: true });
60
+ rmSync(join(store, MARKETPLACE), { recursive: true, force: true });
61
+ copyMarketplace(sources, store);
62
+ if (stamp !== null)
63
+ writeFileSync(join(store, 'runtime.json'), stamp);
64
+ return true;
65
+ }
66
+ export function installDependencies(store, deps, bun, log) {
67
+ const wanted = packageText(deps);
68
+ const marker = join(store, 'node_modules', '.metro-installed');
69
+ if (existsSync(marker) && readOrNull(join(store, 'package.json')) === wanted)
70
+ return false;
71
+ writeFileSync(join(store, 'package.json'), wanted);
72
+ log(`Installing the channel SDKs this machine needs into ${store}`);
73
+ const run = spawnSync(bun, ['install', '--no-summary', '--no-progress'], {
74
+ cwd: store,
75
+ stdio: ['ignore', 'inherit', 'inherit'],
76
+ timeout: INSTALL_TIMEOUT_MS,
77
+ });
78
+ if (run.error !== undefined || run.status !== 0)
79
+ throw new Error(`bun install failed in ${store}: ${run.error?.message ?? `exit ${String(run.status)}`}`);
80
+ writeFileSync(marker, `${new Date().toISOString()}\n`);
81
+ return true;
82
+ }
83
+ export function prepareRuntime(opts = {}) {
84
+ const sources = opts.sources ?? runtimeDir();
85
+ const manifestPath = join(sources, MANIFEST_FILE);
86
+ if (!existsSync(manifestPath))
87
+ return { dir: sources, entry: daemonEntry(sources), trains: join(sources, 'trains'), manifest: null };
88
+ const store = opts.store ?? runtimeStore();
89
+ const log = opts.log ??
90
+ ((line) => {
91
+ process.stderr.write(`${line}\n`);
92
+ });
93
+ mkdirSync(join(store, 'trains'), { recursive: true });
94
+ syncSources(sources, store);
95
+ installDependencies(store, dependenciesFor(readManifest(manifestPath), localStations(opts.agents)), opts.bun ?? findBun(), log);
96
+ return { dir: store, entry: daemonEntry(store), trains: join(store, 'trains'), manifest: manifestPath };
97
+ }
@@ -0,0 +1,74 @@
1
+ import { spawn, spawnSync } from 'node:child_process';
2
+ import { existsSync } from 'node:fs';
3
+ import { dirname, join } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ const AGENT_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{10}$/;
6
+ export const STORE_ENTRY = 'server.ts';
7
+ export const PACKAGE_ENTRY = join('node_modules', '@metro-labs', 'daemon', 'src', 'server.ts');
8
+ export const daemonEntry = (dir) => existsSync(join(dir, STORE_ENTRY))
9
+ ? join(dir, STORE_ENTRY)
10
+ : join(dir, PACKAGE_ENTRY);
11
+ export class MissingRuntime extends Error {
12
+ }
13
+ export function runtimeDir() {
14
+ const explicit = process.env.METRO_RUNTIME_DIR?.trim();
15
+ const dir = explicit !== undefined && explicit !== ''
16
+ ? explicit
17
+ : join(dirname(dirname(fileURLToPath(import.meta.url))), 'runtime');
18
+ if (!existsSync(daemonEntry(dir)))
19
+ throw new MissingRuntime(`no metro daemon at ${dir}. Reinstall with: npm i -g @stage-labs/metro@beta`);
20
+ return dir;
21
+ }
22
+ class MissingBun extends Error {
23
+ }
24
+ export function assertAgentId(id) {
25
+ if (id === undefined || !AGENT_RE.test(id))
26
+ throw new Error(`'${id ?? ''}' is not an agent id — copy it from the agent's page in the web UI`);
27
+ return id;
28
+ }
29
+ export function findBun() {
30
+ const found = spawnSync('bun', ['--version'], { stdio: 'ignore' });
31
+ if (found.error !== undefined || found.status !== 0)
32
+ throw new MissingBun('metro serve needs Bun, which is not on PATH.\n' +
33
+ 'Install it with: curl -fsSL https://bun.sh/install | bash');
34
+ return 'bun';
35
+ }
36
+ export const localPort = () => Number(process.env.METRO_WEBHOOK_PORT) || 8420;
37
+ export const localUrl = () => `http://127.0.0.1:${String(localPort())}`;
38
+ export const RESTART_CODE = 75;
39
+ export const HOLD_CODE = 76;
40
+ function spawnOnce(plan) {
41
+ const child = spawn(plan.command, plan.args, {
42
+ cwd: plan.cwd,
43
+ env: plan.env,
44
+ stdio: ['ignore', 'inherit', 'inherit'],
45
+ });
46
+ const relay = (sig) => () => {
47
+ child.kill(sig);
48
+ };
49
+ const onInt = relay('SIGINT');
50
+ const onTerm = relay('SIGTERM');
51
+ process.on('SIGINT', onInt);
52
+ process.on('SIGTERM', onTerm);
53
+ return new Promise((resolve) => {
54
+ child.on('exit', (code) => {
55
+ process.off('SIGINT', onInt);
56
+ process.off('SIGTERM', onTerm);
57
+ resolve(code ?? 0);
58
+ });
59
+ });
60
+ }
61
+ export async function spawnPlan(plan, hold) {
62
+ for (;;) {
63
+ const code = await spawnOnce(plan());
64
+ if (code === RESTART_CODE) {
65
+ process.stderr.write('metro was updated; restarting the daemon on the new version\n');
66
+ continue;
67
+ }
68
+ if (code !== HOLD_CODE || hold === undefined)
69
+ return code;
70
+ if ((await hold()) === 'exit')
71
+ return 0;
72
+ process.stderr.write('starting the daemon again\n');
73
+ }
74
+ }
package/dist/serve.js ADDED
@@ -0,0 +1,155 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { existsSync, readFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { agentsDir } from './local.js';
5
+ import { currentVersion } from './version.js';
6
+ import { serveLockedBy, serveStateDir } from './control.js';
7
+ import { findBun, localPort, spawnPlan } from './runtime.js';
8
+ import { prepareRuntime } from './runtime-install.js';
9
+ import { ensureNodeName } from './node-name.js';
10
+ import { holdUntilStart } from './hold.js';
11
+ const SCRUBBED = new Set(['METRO_RUN_TOKEN', 'METRO_AGENT', 'DATABASE_URL']);
12
+ const PORT_FLAG = /^--port=(.*)$/;
13
+ const OWNER_FLAG = /^--owner=(.*)$/;
14
+ const ADDRESS = /^0x[0-9a-fA-F]{40}$/;
15
+ const USAGE = 'usage: metro serve [--port <n>] [--owner <address>]';
16
+ const TUNNEL_FLAG = /^--(no-)?tunnel(=.*)?$/;
17
+ const TAILSCALE_APP = '/Applications/Tailscale.app/Contents/MacOS/Tailscale';
18
+ function portOf(raw) {
19
+ const n = Number(raw);
20
+ if (raw === undefined || raw === '' || !Number.isInteger(n) || n < 1 || n > 65535)
21
+ throw new Error(`'${raw ?? ''}' is not a port — ${USAGE}`);
22
+ return n;
23
+ }
24
+ const ORGANIZATION = /^org_[A-Za-z0-9]{10,64}$/;
25
+ function ownerOf(raw) {
26
+ if (raw !== undefined && ORGANIZATION.test(raw))
27
+ return raw;
28
+ if (raw === undefined || !ADDRESS.test(raw))
29
+ throw new Error(`'${raw ?? ''}' is neither an organization id (org_…) nor an Ethereum address — ${USAGE}`);
30
+ return raw.toLowerCase();
31
+ }
32
+ export function parseServeArgs(argv) {
33
+ let port = localPort();
34
+ let owner = null;
35
+ for (let i = 0; i < argv.length; i += 1) {
36
+ const arg = argv[i] ?? '';
37
+ if (TUNNEL_FLAG.test(arg))
38
+ throw new Error('--tunnel is gone: metro serve always publishes through Tailscale Funnel — ' + USAGE);
39
+ const inlineOwner = OWNER_FLAG.exec(arg);
40
+ if (inlineOwner) {
41
+ owner = ownerOf(inlineOwner[1]);
42
+ continue;
43
+ }
44
+ if (arg === '--owner') {
45
+ owner = ownerOf(argv[i + 1]);
46
+ i += 1;
47
+ continue;
48
+ }
49
+ const inline = PORT_FLAG.exec(arg);
50
+ if (inline) {
51
+ port = portOf(inline[1]);
52
+ continue;
53
+ }
54
+ if (arg === '--port' || arg === '-p') {
55
+ port = portOf(argv[i + 1]);
56
+ i += 1;
57
+ continue;
58
+ }
59
+ throw new Error(`unknown argument '${arg}' — ${USAGE}`);
60
+ }
61
+ return { port, owner };
62
+ }
63
+ export function requireOwner(owner, dir = agentsDir()) {
64
+ if (owner !== null || existsSync(join(dir, '.owner')))
65
+ return;
66
+ throw new Error('no owner is set for this machine, so nobody could sign in.\n' +
67
+ 'Pass the organization that owns it once; it is remembered in ' +
68
+ join(dir, '.owner') +
69
+ ':\n metro serve --owner <org_…>');
70
+ }
71
+ export function readOwner(dir = agentsDir()) {
72
+ try {
73
+ const raw = readFileSync(join(dir, '.owner'), 'utf8').trim();
74
+ if (ORGANIZATION.test(raw))
75
+ return raw;
76
+ return ADDRESS.test(raw.toLowerCase()) ? raw.toLowerCase() : null;
77
+ }
78
+ catch {
79
+ return null;
80
+ }
81
+ }
82
+ export function holdInfo(port, owner, tailscaleBin) {
83
+ return {
84
+ port,
85
+ host: process.env.METRO_HTTP_HOST ?? '127.0.0.1',
86
+ owner: owner ?? readOwner(),
87
+ version: currentVersion(),
88
+ funnel: tailscaleBin,
89
+ lockFile: join(process.env.METRO_STATE_DIR ?? serveStateDir(), '.tail-lock'),
90
+ };
91
+ }
92
+ function tailscaleStatus(bin) {
93
+ const run = spawnSync(bin, ['status', '--json'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
94
+ if (run.error !== undefined || run.status !== 0)
95
+ return { ok: false, state: 'not running' };
96
+ try {
97
+ const parsed = JSON.parse(run.stdout);
98
+ if (parsed.BackendState !== 'Running')
99
+ return { ok: false, state: String(parsed.BackendState) };
100
+ if (parsed.Self?.Online === false)
101
+ return { ok: false, state: 'Running, but not connected to the tailnet: the machine may have been removed from it' };
102
+ return { ok: true };
103
+ }
104
+ catch {
105
+ return { ok: false, state: 'unreadable' };
106
+ }
107
+ }
108
+ export function findTailscale(candidates = ['tailscale', TAILSCALE_APP]) {
109
+ const bin = candidates.find((c) => spawnSync(c, ['version'], { stdio: 'ignore' }).status === 0);
110
+ if (bin === undefined)
111
+ throw new Error('metro serve needs Tailscale on this machine: the daemon is published through Tailscale Funnel.\n' +
112
+ 'macOS: brew install --cask tailscale (or the App Store app)\n' +
113
+ 'Linux: curl -fsSL https://tailscale.com/install.sh | sh\n' +
114
+ 'Then sign the machine in: tailscale up');
115
+ const status = tailscaleStatus(bin);
116
+ if (!status.ok)
117
+ throw new Error(`Tailscale is installed but this machine is not connected (${status.state}). Sign it in first: tailscale up\n` +
118
+ 'Funnel also has to be enabled once on your tailnet: https://tailscale.com/kb/1223/funnel');
119
+ return bin;
120
+ }
121
+ export function servePlan(opts) {
122
+ const env = Object.fromEntries(Object.entries(process.env).filter(([key]) => !SCRUBBED.has(key)));
123
+ return {
124
+ command: findBun(),
125
+ args: [opts.runtime.entry],
126
+ cwd: opts.runtime.dir,
127
+ env: {
128
+ ...env,
129
+ METRO_VERSION: currentVersion(),
130
+ METRO_CLI_BIN: process.argv[1] ?? '',
131
+ METRO_WEBHOOK_PORT: String(opts.port),
132
+ METRO_HTTP_HOST: process.env.METRO_HTTP_HOST ?? '127.0.0.1',
133
+ METRO_TRAINS_DIR: opts.runtime.trains,
134
+ ...(opts.runtime.manifest === null
135
+ ? {}
136
+ : { METRO_RUNTIME_STORE: opts.runtime.dir, METRO_RUNTIME_MANIFEST: opts.runtime.manifest }),
137
+ METRO_STATE_DIR: process.env.METRO_STATE_DIR ?? serveStateDir(),
138
+ METRO_TUNNEL: 'tailscale',
139
+ METRO_TAILSCALE_BIN: opts.tailscaleBin,
140
+ ...(opts.owner === null ? {} : { METRO_OWNER: opts.owner }),
141
+ },
142
+ };
143
+ }
144
+ export function serve(argv) {
145
+ const { port, owner } = parseServeArgs(argv);
146
+ const running = serveLockedBy();
147
+ if (running !== null)
148
+ throw new Error(`a metro serve daemon is already running on this machine (pid ${String(running)}). ` +
149
+ 'Stop it first: metro stop');
150
+ requireOwner(owner);
151
+ const tailscaleBin = findTailscale();
152
+ const node = ensureNodeName(tailscaleBin);
153
+ process.stderr.write(`Starting a metro daemon of your own on http://127.0.0.1:${String(port)}, published as ${node} on your tailnet\n`);
154
+ return spawnPlan(() => servePlan({ runtime: prepareRuntime(), port, owner, tailscaleBin }), () => holdUntilStart(holdInfo(port, owner, tailscaleBin)));
155
+ }