@stage-labs/metro 0.1.0-beta.23 → 0.1.0-beta.231

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 (457) hide show
  1. package/dist/api.js +9 -101
  2. package/dist/background.js +123 -0
  3. package/dist/claude-settings.js +40 -0
  4. package/dist/claude.js +197 -0
  5. package/dist/cli.js +52 -110
  6. package/dist/control.js +19 -103
  7. package/dist/hold.js +210 -0
  8. package/dist/local.js +43 -0
  9. package/dist/mcp-config.js +25 -0
  10. package/dist/memory.js +222 -0
  11. package/dist/node-name.js +71 -0
  12. package/dist/onboarding.js +44 -0
  13. package/dist/provider-flags.js +9 -0
  14. package/dist/route.js +58 -0
  15. package/dist/runtime-install.js +96 -0
  16. package/dist/runtime.js +29 -52
  17. package/dist/serve.js +157 -0
  18. package/dist/service.js +304 -0
  19. package/dist/tail.js +119 -0
  20. package/dist/update.js +13 -1
  21. package/package.json +2 -23
  22. package/runtime/marketplace/.claude-plugin/marketplace.json +12 -0
  23. package/runtime/marketplace/plugin/.claude-plugin/plugin.json +17 -0
  24. package/runtime/marketplace/plugin/.mcp.json +1 -0
  25. package/runtime/marketplace/plugin/MEMORY.md +78 -0
  26. package/runtime/marketplace/plugin/METRO.md +26 -0
  27. package/runtime/marketplace/plugin/STAGE.md +42 -0
  28. package/runtime/marketplace/plugin/bin/guard.mjs +71 -0
  29. package/runtime/marketplace/plugin/bin/metro-plugin.mjs +30 -0
  30. package/runtime/marketplace/plugin/bin/policy.mjs +97 -0
  31. package/runtime/marketplace/plugin/bin/session-start.mjs +31 -0
  32. package/runtime/marketplace/plugin/hooks/hooks.json +25 -0
  33. package/runtime/node_modules/@metro-labs/core/package.json +51 -0
  34. package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
  35. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/events.ts +11 -7
  36. package/runtime/node_modules/@metro-labs/{mcp/src/db → core/src}/ids.ts +5 -0
  37. package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
  38. package/runtime/node_modules/@metro-labs/{mcp/src/stations → core/src}/lines.ts +22 -26
  39. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/protocol.ts +7 -4
  40. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/secure-fs.ts +17 -0
  41. package/runtime/node_modules/@metro-labs/core/src/station-names.ts +14 -0
  42. package/runtime/node_modules/@metro-labs/core/src/stations/account-files.ts +41 -0
  43. package/runtime/node_modules/@metro-labs/core/src/stations/account-store.ts +83 -0
  44. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/attachments.ts +0 -1
  45. package/runtime/node_modules/@metro-labs/core/src/stations/mail-text.ts +72 -0
  46. package/runtime/node_modules/@metro-labs/core/src/stations/mail-trust.ts +29 -0
  47. package/runtime/node_modules/@metro-labs/core/src/stations/mail.ts +212 -0
  48. package/runtime/node_modules/@metro-labs/core/src/stations/messaging-normalize.ts +16 -0
  49. package/runtime/node_modules/@metro-labs/core/src/stations/oauth.ts +126 -0
  50. package/runtime/node_modules/@metro-labs/core/src/stations/profile.ts +58 -0
  51. package/runtime/node_modules/@metro-labs/core/src/stations/sender-profile.ts +64 -0
  52. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/station-runtime.ts +6 -11
  53. package/runtime/node_modules/@metro-labs/core/src/stations/train-boot.ts +42 -0
  54. package/runtime/node_modules/@metro-labs/core/src/stations/train-events.ts +84 -0
  55. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/types.ts +18 -1
  56. package/runtime/node_modules/@metro-labs/core/src/tickets.ts +37 -0
  57. package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
  58. package/runtime/node_modules/@metro-labs/daemon/package.json +49 -0
  59. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/agent-fs.ts +134 -0
  60. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/crontab.ts +44 -0
  61. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files-api.ts +12 -0
  62. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files.ts +89 -0
  63. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/home-fs.ts +113 -0
  64. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/job-env.ts +39 -0
  65. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/provision.ts +80 -0
  66. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedule-detail.ts +99 -0
  67. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules-api.ts +27 -0
  68. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules.ts +144 -0
  69. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/unit-files.ts +43 -0
  70. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/user.ts +91 -0
  71. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/view.ts +87 -0
  72. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-attach.ts +19 -0
  73. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-lookups.ts +55 -0
  74. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-routes.ts +76 -0
  75. package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +357 -0
  76. package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +30 -0
  77. package/runtime/node_modules/@metro-labs/daemon/src/agents/allowlist.ts +59 -0
  78. package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +131 -0
  79. package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +132 -0
  80. package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +305 -0
  81. package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +142 -0
  82. package/runtime/node_modules/@metro-labs/{mcp/src/db/key-map.ts → daemon/src/agents/keys.ts} +1 -11
  83. package/runtime/node_modules/@metro-labs/daemon/src/agents/map.ts +133 -0
  84. package/runtime/node_modules/@metro-labs/daemon/src/agents/policy-route.ts +27 -0
  85. package/runtime/node_modules/@metro-labs/{mcp/src/db/agent-scope.ts → daemon/src/agents/scope.ts} +2 -2
  86. package/runtime/node_modules/@metro-labs/daemon/src/agents/sender-cards.ts +94 -0
  87. package/runtime/node_modules/@metro-labs/daemon/src/agents/senders.ts +38 -0
  88. package/runtime/node_modules/@metro-labs/daemon/src/approvals/api.ts +55 -0
  89. package/runtime/node_modules/@metro-labs/daemon/src/approvals/pending.ts +150 -0
  90. package/runtime/node_modules/@metro-labs/daemon/src/approvals/preview.ts +66 -0
  91. package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +223 -0
  92. package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +36 -0
  93. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/crash-guard.ts +1 -1
  94. package/runtime/node_modules/@metro-labs/daemon/src/boot/local-owner.ts +21 -0
  95. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/paths.ts +6 -34
  96. package/runtime/node_modules/@metro-labs/daemon/src/channels/addressed.ts +26 -0
  97. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/inbound.ts +75 -45
  98. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/media-note.ts +11 -7
  99. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/pending.ts +4 -1
  100. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/relay.ts +2 -2
  101. package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +380 -0
  102. package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +359 -0
  103. package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +208 -0
  104. package/runtime/node_modules/@metro-labs/daemon/src/claude/memory-routine.ts +114 -0
  105. package/runtime/node_modules/@metro-labs/daemon/src/claude/memory.ts +32 -0
  106. package/runtime/node_modules/@metro-labs/daemon/src/claude/onboarding.ts +60 -0
  107. package/runtime/node_modules/@metro-labs/daemon/src/claude/plugin-install.ts +149 -0
  108. package/runtime/node_modules/@metro-labs/daemon/src/claude/session-files.ts +75 -0
  109. package/runtime/node_modules/@metro-labs/daemon/src/claude/session.ts +295 -0
  110. package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +109 -0
  111. package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +346 -0
  112. package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +120 -0
  113. package/runtime/node_modules/@metro-labs/daemon/src/claude/usage-probe.ts +127 -0
  114. package/runtime/node_modules/@metro-labs/daemon/src/claude/version.ts +113 -0
  115. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-api.ts → daemon/src/connectors/api.ts} +79 -113
  116. package/runtime/node_modules/@metro-labs/{mcp/src/db/connector-config.ts → daemon/src/connectors/config.ts} +67 -41
  117. package/runtime/node_modules/@metro-labs/daemon/src/connectors/gates.ts +72 -0
  118. package/runtime/node_modules/@metro-labs/daemon/src/connectors/health.ts +18 -0
  119. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-client.ts +14 -17
  120. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-discovery.ts +33 -20
  121. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth-routes.ts → daemon/src/connectors/oauth-routes.ts} +30 -32
  122. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth.ts → daemon/src/connectors/oauth.ts} +61 -22
  123. package/runtime/node_modules/@metro-labs/daemon/src/connectors/plugin-sync.ts +131 -0
  124. package/runtime/node_modules/@metro-labs/daemon/src/connectors/reach.ts +27 -0
  125. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-policy.ts +90 -0
  126. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +347 -0
  127. package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +385 -0
  128. package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +81 -0
  129. package/runtime/node_modules/@metro-labs/daemon/src/connectors/transfer-api.ts +116 -0
  130. package/runtime/node_modules/@metro-labs/daemon/src/connectors/transfer-crypto.ts +44 -0
  131. package/runtime/node_modules/@metro-labs/daemon/src/connectors/transfer-store.ts +48 -0
  132. package/runtime/node_modules/@metro-labs/daemon/src/connectors/url.ts +37 -0
  133. package/runtime/node_modules/@metro-labs/daemon/src/connectors/verify.ts +106 -0
  134. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-grant.ts +4 -4
  135. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-owner.ts +3 -3
  136. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-reaper.ts +174 -0
  137. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-serve.ts +12 -13
  138. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-api.ts +10 -27
  139. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-store.ts +4 -4
  140. package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +233 -0
  141. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +214 -0
  142. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-device.ts +91 -0
  143. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +173 -0
  144. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +209 -0
  145. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-version.ts +44 -0
  146. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +155 -0
  147. package/runtime/node_modules/@metro-labs/daemon/src/gateway/effort.ts +93 -0
  148. package/runtime/node_modules/@metro-labs/daemon/src/gateway/eventstream.ts +123 -0
  149. package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +237 -0
  150. package/runtime/node_modules/@metro-labs/daemon/src/gateway/frames.ts +118 -0
  151. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +307 -0
  152. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-auth.ts +160 -0
  153. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-client.ts +46 -0
  154. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-setup.ts +150 -0
  155. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-stream.ts +139 -0
  156. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-translate.ts +235 -0
  157. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini.ts +208 -0
  158. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +203 -0
  159. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +285 -0
  160. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-lists.ts +57 -0
  161. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-signin.ts +161 -0
  162. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-store.ts +72 -0
  163. package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +104 -0
  164. package/runtime/node_modules/@metro-labs/daemon/src/gateway/pkce.ts +36 -0
  165. package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +118 -0
  166. package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +18 -0
  167. package/runtime/node_modules/@metro-labs/daemon/src/gateway/subscription.ts +120 -0
  168. package/runtime/node_modules/@metro-labs/daemon/src/gateway/text.ts +35 -0
  169. package/runtime/node_modules/@metro-labs/daemon/src/gateway/tool-search.ts +126 -0
  170. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage-refresh.ts +102 -0
  171. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +348 -0
  172. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/accounts.ts +28 -17
  173. package/runtime/node_modules/@metro-labs/daemon/src/mcp/attachment-schema.ts +91 -0
  174. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/call-tools.ts +49 -20
  175. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/ctx.ts +4 -4
  176. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/event-store.ts +15 -16
  177. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/group-tools.ts +2 -2
  178. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/index.ts +34 -80
  179. package/runtime/node_modules/@metro-labs/daemon/src/mcp/instructions.ts +19 -0
  180. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/member-tools.ts +2 -2
  181. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-prompt.ts +87 -0
  182. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +88 -0
  183. package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-gate.ts +82 -0
  184. package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-snapshot.ts +79 -0
  185. package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-lookup.ts +60 -0
  186. package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-tool.ts +96 -0
  187. package/runtime/node_modules/@metro-labs/daemon/src/mcp/read-tool.ts +87 -0
  188. package/runtime/node_modules/@metro-labs/daemon/src/mcp/request-identity.ts +46 -0
  189. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-slot.ts +71 -0
  190. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/session.ts +47 -44
  191. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-catalog.ts +93 -0
  192. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-def.ts +9 -0
  193. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-dispatch.ts +53 -40
  194. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-schemas.ts +64 -113
  195. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/upload-tool.ts +6 -11
  196. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/helper-script.ts +126 -0
  197. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/install.ts +37 -0
  198. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/privilege.ts +48 -0
  199. package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +132 -0
  200. package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +316 -0
  201. package/runtime/node_modules/@metro-labs/daemon/src/policy/policy.ts +118 -0
  202. package/runtime/node_modules/@metro-labs/daemon/src/routes/bearer.ts +35 -0
  203. package/runtime/node_modules/@metro-labs/daemon/src/routes/body.ts +24 -0
  204. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/routes}/http.ts +63 -51
  205. package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +209 -0
  206. package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +69 -0
  207. package/runtime/node_modules/@metro-labs/daemon/src/routes/session.ts +29 -0
  208. package/runtime/node_modules/@metro-labs/daemon/src/routes/threema-callback.ts +103 -0
  209. package/runtime/node_modules/@metro-labs/daemon/src/server/cloudwatch.ts +178 -0
  210. package/runtime/node_modules/@metro-labs/daemon/src/server/control.ts +39 -0
  211. package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +58 -0
  212. package/runtime/node_modules/@metro-labs/daemon/src/server/owner.ts +26 -0
  213. package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +90 -0
  214. package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
  215. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-browser.ts +102 -0
  216. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-driver.ts +42 -0
  217. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-inline.ts +29 -1
  218. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-interactive.ts +5 -31
  219. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-resolve.ts +38 -13
  220. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/attach-session.ts +32 -22
  221. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-xmtp.ts +8 -9
  222. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach.ts +69 -3
  223. package/runtime/node_modules/@metro-labs/{mcp/src/db → daemon/src/stations}/materialize.ts +60 -179
  224. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/registry.ts +20 -2
  225. package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +82 -0
  226. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor-io.ts +3 -3
  227. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor.ts +6 -9
  228. package/runtime/node_modules/@metro-labs/daemon/src/stations/threema-callbacks.ts +32 -0
  229. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/train-call.ts +1 -1
  230. package/runtime/node_modules/@metro-labs/daemon/src/stations/webhook-endpoints.ts +51 -0
  231. package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +84 -0
  232. package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +124 -0
  233. package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +15 -0
  234. package/runtime/node_modules/@metro-labs/daemon/src/vault/api.ts +45 -0
  235. package/runtime/node_modules/@metro-labs/daemon/src/vault/config.ts +51 -0
  236. package/runtime/node_modules/@metro-labs/daemon/src/vault/firewall.ts +9 -0
  237. package/runtime/node_modules/@metro-labs/daemon/src/vault/index.ts +96 -0
  238. package/runtime/node_modules/@metro-labs/daemon/src/vault/install.ts +56 -0
  239. package/runtime/node_modules/@metro-labs/daemon/src/vault/paths.ts +26 -0
  240. package/runtime/node_modules/@metro-labs/daemon/src/vault/proxy.ts +147 -0
  241. package/runtime/node_modules/@metro-labs/daemon/src/vault/store.ts +129 -0
  242. package/runtime/node_modules/@metro-labs/daemon/src/vault/trust.ts +44 -0
  243. package/runtime/node_modules/@metro-labs/discord-bot/package.json +2 -4
  244. package/runtime/node_modules/@metro-labs/discord-bot/src/accounts.ts +3 -23
  245. package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +19 -187
  246. package/runtime/node_modules/@metro-labs/discord-bot/src/attachments.ts +2 -2
  247. package/runtime/node_modules/@metro-labs/discord-bot/src/format.ts +26 -67
  248. package/runtime/node_modules/@metro-labs/discord-bot/src/group-actions.ts +1 -1
  249. package/runtime/node_modules/@metro-labs/discord-bot/src/group.ts +2 -2
  250. package/runtime/node_modules/@metro-labs/discord-bot/src/index.ts +8 -14
  251. package/runtime/node_modules/@metro-labs/discord-bot/src/members.ts +2 -2
  252. package/runtime/node_modules/@metro-labs/discord-bot/src/profile.ts +68 -0
  253. package/runtime/node_modules/@metro-labs/discord-bot/src/send-files.ts +12 -13
  254. package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +5 -1
  255. package/runtime/node_modules/@metro-labs/gmail/package.json +25 -0
  256. package/runtime/node_modules/@metro-labs/gmail/src/accounts.ts +81 -0
  257. package/runtime/node_modules/@metro-labs/gmail/src/actions.ts +14 -0
  258. package/runtime/node_modules/@metro-labs/gmail/src/api.ts +31 -0
  259. package/runtime/node_modules/@metro-labs/gmail/src/attachments.ts +35 -0
  260. package/runtime/node_modules/@metro-labs/gmail/src/auth.ts +105 -0
  261. package/runtime/node_modules/@metro-labs/gmail/src/config.ts +13 -0
  262. package/runtime/node_modules/@metro-labs/gmail/src/inbound.ts +96 -0
  263. package/runtime/node_modules/@metro-labs/gmail/src/index.ts +12 -0
  264. package/runtime/node_modules/@metro-labs/gmail/src/login.ts +37 -0
  265. package/runtime/node_modules/@metro-labs/gmail/src/message.ts +125 -0
  266. package/runtime/node_modules/@metro-labs/gmail/src/mime.ts +70 -0
  267. package/runtime/node_modules/@metro-labs/gmail/src/outbound.ts +124 -0
  268. package/runtime/node_modules/@metro-labs/gmail/src/query.ts +99 -0
  269. package/runtime/node_modules/@metro-labs/gmail/src/state.ts +24 -0
  270. package/runtime/node_modules/@metro-labs/gmail/src/station.ts +15 -0
  271. package/runtime/node_modules/@metro-labs/gmail/src/trust.ts +42 -0
  272. package/runtime/node_modules/@metro-labs/http/package.json +30 -0
  273. package/runtime/node_modules/@metro-labs/http/src/api-http.ts +135 -0
  274. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/session-api.ts → http/src/mode-api.ts} +13 -9
  275. package/runtime/node_modules/@metro-labs/http/src/return-to.ts +21 -0
  276. package/runtime/node_modules/@metro-labs/http/src/sigv4.ts +90 -0
  277. package/runtime/node_modules/@metro-labs/http/src/workos-token.ts +149 -0
  278. package/runtime/node_modules/@metro-labs/outlook/package.json +25 -0
  279. package/runtime/node_modules/@metro-labs/outlook/src/accounts.ts +78 -0
  280. package/runtime/node_modules/@metro-labs/outlook/src/actions.ts +14 -0
  281. package/runtime/node_modules/@metro-labs/outlook/src/attachments.ts +81 -0
  282. package/runtime/node_modules/@metro-labs/outlook/src/auth.ts +120 -0
  283. package/runtime/node_modules/@metro-labs/outlook/src/browser.ts +42 -0
  284. package/runtime/node_modules/@metro-labs/outlook/src/config.ts +23 -0
  285. package/runtime/node_modules/@metro-labs/outlook/src/format.ts +59 -0
  286. package/runtime/node_modules/@metro-labs/outlook/src/graph.ts +55 -0
  287. package/runtime/node_modules/@metro-labs/outlook/src/inbound.ts +96 -0
  288. package/runtime/node_modules/@metro-labs/outlook/src/index.ts +12 -0
  289. package/runtime/node_modules/@metro-labs/outlook/src/login.ts +129 -0
  290. package/runtime/node_modules/@metro-labs/outlook/src/me.ts +31 -0
  291. package/runtime/node_modules/@metro-labs/outlook/src/outbound.ts +103 -0
  292. package/runtime/node_modules/@metro-labs/outlook/src/query.ts +84 -0
  293. package/runtime/node_modules/@metro-labs/outlook/src/state.ts +28 -0
  294. package/runtime/node_modules/@metro-labs/outlook/src/station.ts +15 -0
  295. package/runtime/node_modules/@metro-labs/outlook/src/trust.ts +41 -0
  296. package/runtime/node_modules/@metro-labs/telegram/package.json +1 -3
  297. package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +5 -24
  298. package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +8 -6
  299. package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +1 -1
  300. package/runtime/node_modules/@metro-labs/telegram/src/client.ts +2 -2
  301. package/runtime/node_modules/@metro-labs/telegram/src/format.ts +19 -34
  302. package/runtime/node_modules/@metro-labs/telegram/src/group.ts +3 -3
  303. package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +13 -34
  304. package/runtime/node_modules/@metro-labs/telegram/src/index.ts +4 -43
  305. package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +2 -3
  306. package/runtime/node_modules/@metro-labs/telegram/src/members.ts +1 -1
  307. package/runtime/node_modules/@metro-labs/telegram/src/profile.ts +70 -0
  308. package/runtime/node_modules/@metro-labs/telegram/src/reactions.ts +2 -2
  309. package/runtime/node_modules/@metro-labs/telegram/src/station.ts +4 -1
  310. package/runtime/node_modules/@metro-labs/telegram/src/types.ts +0 -1
  311. package/runtime/node_modules/@metro-labs/telegram-bot/package.json +1 -1
  312. package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +7 -41
  313. package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +22 -77
  314. package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +2 -2
  315. package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +46 -48
  316. package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +15 -15
  317. package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +6 -82
  318. package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +1 -1
  319. package/runtime/node_modules/@metro-labs/telegram-bot/src/profile.ts +85 -0
  320. package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +5 -1
  321. package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +20 -12
  322. package/runtime/node_modules/@metro-labs/threema/package.json +26 -0
  323. package/runtime/node_modules/@metro-labs/threema/src/accounts.ts +96 -0
  324. package/runtime/node_modules/@metro-labs/threema/src/actions.ts +124 -0
  325. package/runtime/node_modules/@metro-labs/threema/src/api.ts +152 -0
  326. package/runtime/node_modules/@metro-labs/threema/src/crypto.ts +100 -0
  327. package/runtime/node_modules/@metro-labs/threema/src/files.ts +47 -0
  328. package/runtime/node_modules/@metro-labs/threema/src/format.ts +164 -0
  329. package/runtime/node_modules/@metro-labs/threema/src/groups.ts +96 -0
  330. package/runtime/node_modules/@metro-labs/threema/src/ids.ts +21 -0
  331. package/runtime/node_modules/@metro-labs/threema/src/inbound.ts +87 -0
  332. package/runtime/node_modules/@metro-labs/threema/src/index.ts +24 -0
  333. package/runtime/node_modules/@metro-labs/threema/src/messages.ts +264 -0
  334. package/runtime/node_modules/@metro-labs/threema/src/outbound.ts +160 -0
  335. package/runtime/node_modules/@metro-labs/threema/src/station.ts +13 -0
  336. package/runtime/node_modules/@metro-labs/threema/src/verify.ts +117 -0
  337. package/runtime/node_modules/@metro-labs/webhook/package.json +1 -1
  338. package/runtime/node_modules/@metro-labs/webhook/src/station.ts +5 -8
  339. package/runtime/node_modules/@metro-labs/whatsapp/package.json +2 -5
  340. package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +6 -28
  341. package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +1 -1
  342. package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +54 -11
  343. package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +2 -2
  344. package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +1 -1
  345. package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +86 -4
  346. package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +7 -58
  347. package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +11 -28
  348. package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +4 -37
  349. package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +1 -1
  350. package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +1 -1
  351. package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +1 -1
  352. package/runtime/node_modules/@metro-labs/whatsapp/src/names.ts +75 -0
  353. package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +44 -0
  354. package/runtime/node_modules/@metro-labs/whatsapp/src/resolve.ts +52 -0
  355. package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +16 -1
  356. package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +5 -9
  357. package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +0 -1
  358. package/runtime/node_modules/@metro-labs/xmtp/package.json +3 -2
  359. package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +10 -20
  360. package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +2 -2
  361. package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +15 -204
  362. package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +40 -53
  363. package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +72 -220
  364. package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +3 -3
  365. package/runtime/node_modules/@metro-labs/xmtp/src/codecs.ts +27 -0
  366. package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +11 -7
  367. package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +7 -24
  368. package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +8 -18
  369. package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +1 -1
  370. package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +2 -2
  371. package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +30 -16
  372. package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +12 -20
  373. package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +57 -33
  374. package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +1 -1
  375. package/runtime/node_modules/@metro-labs/xmtp/src/names.ts +61 -0
  376. package/runtime/node_modules/@metro-labs/xmtp/src/profile.ts +153 -0
  377. package/runtime/node_modules/@metro-labs/xmtp/src/resolve.ts +44 -0
  378. package/runtime/node_modules/@metro-labs/xmtp/src/sender.ts +112 -0
  379. package/runtime/node_modules/@metro-labs/xmtp/src/smart.ts +72 -0
  380. package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +7 -2
  381. package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +22 -58
  382. package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +55 -48
  383. package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +4 -6
  384. package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +19 -5
  385. package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +14 -4
  386. package/runtime/runtime.json +1 -1
  387. package/runtime/server.ts +1 -0
  388. package/runtime/stations.json +38 -0
  389. package/dist/prompt.js +0 -61
  390. package/dist/store.js +0 -70
  391. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-speak.ts +0 -195
  392. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-transcribe.ts +0 -292
  393. package/runtime/node_modules/@metro-labs/discord-bot/src/voice.ts +0 -197
  394. package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +0 -5
  395. package/runtime/node_modules/@metro-labs/mcp/package.json +0 -66
  396. package/runtime/node_modules/@metro-labs/mcp/src/channels/dedupe.ts +0 -24
  397. package/runtime/node_modules/@metro-labs/mcp/src/daemon/account-api.ts +0 -311
  398. package/runtime/node_modules/@metro-labs/mcp/src/daemon/agent-api.ts +0 -341
  399. package/runtime/node_modules/@metro-labs/mcp/src/daemon/api-http.ts +0 -129
  400. package/runtime/node_modules/@metro-labs/mcp/src/daemon/boot.ts +0 -320
  401. package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair-api.ts +0 -111
  402. package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair.ts +0 -20
  403. package/runtime/node_modules/@metro-labs/mcp/src/daemon/collection-api.ts +0 -202
  404. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-json.ts +0 -31
  405. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-tools.ts +0 -100
  406. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-url.ts +0 -57
  407. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-verify.ts +0 -333
  408. package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-auth.ts +0 -164
  409. package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-oauth.ts +0 -208
  410. package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity.ts +0 -79
  411. package/runtime/node_modules/@metro-labs/mcp/src/daemon/oauth-pending.ts +0 -65
  412. package/runtime/node_modules/@metro-labs/mcp/src/daemon/pair-codes.ts +0 -58
  413. package/runtime/node_modules/@metro-labs/mcp/src/daemon/project-api.ts +0 -214
  414. package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-api.ts +0 -125
  415. package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-pair.ts +0 -18
  416. package/runtime/node_modules/@metro-labs/mcp/src/daemon/runtime-source.ts +0 -105
  417. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session-apis.ts +0 -41
  418. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session.ts +0 -218
  419. package/runtime/node_modules/@metro-labs/mcp/src/daemon/tunnel.ts +0 -169
  420. package/runtime/node_modules/@metro-labs/mcp/src/db/account-attach.ts +0 -91
  421. package/runtime/node_modules/@metro-labs/mcp/src/db/agent-admin.ts +0 -215
  422. package/runtime/node_modules/@metro-labs/mcp/src/db/agent-map.ts +0 -71
  423. package/runtime/node_modules/@metro-labs/mcp/src/db/client.ts +0 -37
  424. package/runtime/node_modules/@metro-labs/mcp/src/db/connector-collections.ts +0 -218
  425. package/runtime/node_modules/@metro-labs/mcp/src/db/connectors.ts +0 -329
  426. package/runtime/node_modules/@metro-labs/mcp/src/db/projects.ts +0 -300
  427. package/runtime/node_modules/@metro-labs/mcp/src/db/runtime-admin.ts +0 -31
  428. package/runtime/node_modules/@metro-labs/mcp/src/db/runtimes.ts +0 -105
  429. package/runtime/node_modules/@metro-labs/mcp/src/db/schema.ts +0 -131
  430. package/runtime/node_modules/@metro-labs/mcp/src/db/token-carry.ts +0 -45
  431. package/runtime/node_modules/@metro-labs/mcp/src/db/users.ts +0 -57
  432. package/runtime/node_modules/@metro-labs/mcp/src/db/whatsapp-login.ts +0 -18
  433. package/runtime/node_modules/@metro-labs/mcp/src/mcp/channel-owner.ts +0 -29
  434. package/runtime/node_modules/@metro-labs/mcp/src/mcp/frame-scope.ts +0 -21
  435. package/runtime/node_modules/@metro-labs/mcp/src/mcp/permission-relay.ts +0 -66
  436. package/runtime/node_modules/@metro-labs/mcp/src/mcp/request-identity.ts +0 -73
  437. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-registry.ts +0 -172
  438. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-route.ts +0 -43
  439. package/runtime/node_modules/@metro-labs/mcp/src/monitor/api.ts +0 -240
  440. package/runtime/node_modules/@metro-labs/mcp/src/server.ts +0 -2
  441. package/runtime/node_modules/@metro-labs/mcp/src/stations/account-store.ts +0 -80
  442. package/runtime/node_modules/@metro-labs/mcp/src/stations/messaging-normalize.ts +0 -88
  443. package/runtime/node_modules/@metro-labs/telegram/src/normalize.ts +0 -22
  444. package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +0 -1
  445. package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +0 -3
  446. package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +0 -22
  447. package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +0 -5
  448. package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +0 -87
  449. package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +0 -55
  450. package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +0 -349
  451. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/log.ts +0 -0
  452. /package/runtime/node_modules/@metro-labs/{mcp/src/mcp → core/src}/str.ts +0 -0
  453. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/train-error.ts +0 -0
  454. /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/webhook-note.ts +0 -0
  455. /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/raw-get-stream.ts +0 -0
  456. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/api-error.ts +0 -0
  457. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/cors.ts +0 -0
package/dist/api.js CHANGED
@@ -1,103 +1,11 @@
1
- import { metroUrl, readToken } from './store.js';
2
- export class NotSignedIn extends Error {
3
- }
4
- const TIMEOUT_MS = 20_000;
5
- const LOOPBACK = new Set(['localhost', '127.0.0.1', '::1', '[::1]']);
6
- export function carriesSecretsSafely(base) {
7
- let url;
8
- try {
9
- url = new URL(base);
10
- }
11
- catch {
12
- return false;
13
- }
14
- if (url.protocol === 'https:')
15
- return true;
16
- return url.protocol === 'http:' && LOOPBACK.has(url.hostname);
17
- }
18
- function tokenOrThrow() {
19
- if (!carriesSecretsSafely(metroUrl()))
20
- throw new Error(`refusing to send your session to ${metroUrl()} in the clear — use https, or a loopback address`);
21
- const token = readToken();
22
- if (token === null)
23
- throw new NotSignedIn('not signed in — run `metro login` first');
24
- return token;
25
- }
26
- async function get(path) {
27
- const auth = tokenOrThrow();
28
- let res;
29
- try {
30
- res = await fetch(`${metroUrl()}${path}`, {
31
- headers: { authorization: `Bearer ${auth}` },
32
- signal: AbortSignal.timeout(TIMEOUT_MS),
33
- });
34
- }
35
- catch {
36
- throw new Error(`could not reach ${metroUrl()}`);
37
- }
38
- if (res.status === 401)
39
- throw new NotSignedIn('that sign-in has expired — run `metro login` again');
40
- if (!res.ok)
41
- throw new Error(`metro answered ${String(res.status)}`);
42
- return res.json();
43
- }
44
- function isRecord(value) {
45
- return typeof value === 'object' && value !== null && !Array.isArray(value);
46
- }
47
- async function post(path, body) {
48
- if (!carriesSecretsSafely(metroUrl()))
49
- throw new Error(`refusing to send your code to ${metroUrl()} in the clear — use https, or a loopback address`);
50
- let res;
51
- try {
52
- res = await fetch(`${metroUrl()}${path}`, {
53
- method: 'POST',
54
- headers: { 'content-type': 'application/json' },
55
- body: JSON.stringify(body),
56
- signal: AbortSignal.timeout(TIMEOUT_MS),
57
- });
58
- }
59
- catch {
60
- throw new Error(`could not reach ${metroUrl()}`);
61
- }
62
- const parsed = await res.json().catch(() => null);
63
- if (res.ok)
64
- return parsed;
65
- const detail = isRecord(parsed) ? parsed.error : undefined;
66
- throw new Error(typeof detail === 'string' ? detail : `metro answered ${String(res.status)}`);
67
- }
68
- export async function claimCode(code) {
69
- const body = await post('/api/cli/claim', { code });
70
- if (!isRecord(body) ||
71
- typeof body.token !== 'string' ||
72
- typeof body.email !== 'string' ||
73
- typeof body.collection !== 'string')
74
- throw new Error('metro returned an unexpected response');
75
- return {
76
- token: body.token,
77
- email: body.email,
78
- collection: body.collection,
79
- };
80
- }
81
- export async function claimRuntime(code, label) {
82
- const body = await post('/api/run/claim', { code, label });
83
- if (!isRecord(body) ||
84
- typeof body.token !== 'string' ||
85
- typeof body.agent !== 'string' ||
86
- typeof body.label !== 'string')
87
- throw new Error('metro returned an unexpected response');
88
- return { token: body.token, agent: body.agent, label: body.label };
89
- }
90
- export async function mcpServers() {
91
- const body = await get('/api/cli/mcp');
92
- if (!isRecord(body) || typeof body.json !== 'string')
93
- throw new Error('metro returned an unexpected response');
94
- return body.json;
95
- }
1
+ import { localAgent, localDaemonUp } from './local.js';
2
+ import { localUrl } from './runtime.js';
3
+ const NO_DAEMON = `no metro daemon on ${localUrl()} — start one with: metro serve`;
96
4
  export async function whoisAuthorized() {
97
- const body = await get('/api/cli/session');
98
- if (!isRecord(body) ||
99
- typeof body.email !== 'string' ||
100
- typeof body.collection !== 'string')
101
- throw new Error('metro returned an unexpected response');
102
- return { email: body.email, collection: body.collection };
5
+ if (!(await localDaemonUp()))
6
+ throw new Error(NO_DAEMON);
7
+ const agent = localAgent();
8
+ if (agent === null)
9
+ throw new Error('no agent on this machine yet');
10
+ return { agent: agent.id, where: localUrl() };
103
11
  }
@@ -0,0 +1,123 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { basename, join } from 'node:path';
5
+ export const AGENT_VIEW_OFF = 'CLAUDE_CODE_DISABLE_AGENT_VIEW';
6
+ const STOP_MS = 30_000;
7
+ const SETTLE_MS = 5_000;
8
+ const POLL_MS = 250;
9
+ const given = (value) => value !== undefined && value.trim() !== '' ? value.trim() : undefined;
10
+ const isRecord = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
11
+ export const keepInSession = (env) => given(env[AGENT_VIEW_OFF]) === undefined ? { ...env, [AGENT_VIEW_OFF]: '1' } : env;
12
+ export const claudeDir = (env = process.env) => given(env.CLAUDE_CONFIG_DIR) ?? join(given(env.HOME) ?? homedir(), '.claude');
13
+ export const projectDir = (dir, cwd) => join(dir, 'projects', cwd.replace(/[^A-Za-z0-9]/g, '-'));
14
+ function startTime(pid) {
15
+ try {
16
+ const stat = readFileSync(`/proc/${String(pid)}/stat`, 'utf8');
17
+ return stat.slice(stat.lastIndexOf(')') + 2).split(' ')[19] ?? null;
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
23
+ export function processAlive(pid, procStart) {
24
+ try {
25
+ process.kill(pid, 0);
26
+ }
27
+ catch (err) {
28
+ if (err.code !== 'EPERM')
29
+ return false;
30
+ }
31
+ const started = procStart === undefined ? null : startTime(pid);
32
+ return started === null || started === procStart;
33
+ }
34
+ function backgroundEntry(file, alive) {
35
+ try {
36
+ const raw = JSON.parse(readFileSync(file, 'utf8'));
37
+ if (!isRecord(raw) || typeof raw.pid !== 'number' || typeof raw.sessionId !== 'string')
38
+ return null;
39
+ if (raw.kind === 'interactive' || typeof raw.kind !== 'string')
40
+ return null;
41
+ return alive(raw.pid, typeof raw.procStart === 'string' ? raw.procStart : undefined) ? raw.sessionId : null;
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ export function liveBackground(sessions, alive = processAlive) {
48
+ if (!existsSync(sessions))
49
+ return new Set();
50
+ const ids = readdirSync(sessions)
51
+ .filter((name) => name.endsWith('.json'))
52
+ .map((name) => backgroundEntry(join(sessions, name), alive));
53
+ return new Set(ids.filter((id) => id !== null));
54
+ }
55
+ function newestFirst(dir) {
56
+ if (!existsSync(dir))
57
+ return [];
58
+ return readdirSync(dir)
59
+ .filter((name) => name.endsWith('.jsonl'))
60
+ .map((name) => ({ path: join(dir, name), at: statSync(join(dir, name)).mtimeMs }))
61
+ .sort((a, b) => b.at - a.at)
62
+ .map((file) => file.path);
63
+ }
64
+ function continuedIn(text) {
65
+ const last = text.split('\n').findLast((line) => line.includes('"type":"continued-in"'));
66
+ if (last === undefined)
67
+ return null;
68
+ try {
69
+ const record = JSON.parse(last);
70
+ return isRecord(record) && typeof record.continuedInSessionId === 'string' ? record.continuedInSessionId : null;
71
+ }
72
+ catch {
73
+ return null;
74
+ }
75
+ }
76
+ const HAS_TURN = /"type":"(user|assistant)"/;
77
+ export function heldConversation(dir, live) {
78
+ if (live.size === 0)
79
+ return null;
80
+ for (const file of newestFirst(dir)) {
81
+ const text = readFileSync(file, 'utf8');
82
+ if (!HAS_TURN.test(text))
83
+ continue;
84
+ const moved = continuedIn(text);
85
+ if (moved !== null && live.has(moved))
86
+ return moved;
87
+ if (!live.has(basename(file, '.jsonl')))
88
+ return null;
89
+ }
90
+ return null;
91
+ }
92
+ function stopBackground(id, env = process.env) {
93
+ const run = spawnSync('claude', ['stop', id], { env, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout: STOP_MS });
94
+ if (run.error !== undefined)
95
+ return { ok: false, detail: run.error.message };
96
+ const said = `${run.stdout}${run.stderr}`.trim().split('\n').at(-1) ?? '';
97
+ return { ok: run.status === 0, detail: said === '' ? `exit ${String(run.status)}` : said };
98
+ }
99
+ const sleep = (ms) => new Promise((resolve) => {
100
+ setTimeout(resolve, ms);
101
+ });
102
+ async function settled(sessions, held, alive, ms) {
103
+ if (!liveBackground(sessions, alive).has(held))
104
+ return true;
105
+ if (ms <= 0)
106
+ return false;
107
+ await sleep(POLL_MS);
108
+ return settled(sessions, held, alive, ms - POLL_MS);
109
+ }
110
+ export async function takeBackConversation(deps = {}) {
111
+ const env = deps.env ?? process.env;
112
+ const alive = deps.alive ?? processAlive;
113
+ const dir = claudeDir(env);
114
+ const sessions = join(dir, 'sessions');
115
+ const held = heldConversation(projectDir(dir, deps.cwd ?? process.cwd()), liveBackground(sessions, alive));
116
+ if (held === null)
117
+ return null;
118
+ const id = held.slice(0, 8);
119
+ const stopped = (deps.stop ?? stopBackground)(id, env);
120
+ if (!stopped.ok || !(await settled(sessions, held, alive, deps.settleMs ?? SETTLE_MS)))
121
+ return `the conversation is held by the Claude Code background session ${id} and it could not be stopped (${stopped.detail}), so Claude Code will refuse to continue it: run claude stop ${id}`;
122
+ return `the conversation had moved to the Claude Code background session ${id}, where no chat reaches it; stopped that session (its conversation is kept) and continuing it here`;
123
+ }
@@ -0,0 +1,40 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { PROVIDER_FLAGS } from './provider-flags.js';
5
+ const CONFLICTING = [...PROVIDER_FLAGS, 'ANTHROPIC_BASE_URL', 'ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN'];
6
+ export function settingsFiles(cwd = process.cwd(), env = process.env) {
7
+ const explicit = env.CLAUDE_CONFIG_DIR?.trim() ?? '';
8
+ const configDir = explicit === '' ? join(homedir(), '.claude') : explicit;
9
+ return [
10
+ ...new Set([
11
+ join(configDir, 'settings.json'),
12
+ join(cwd, '.claude', 'settings.json'),
13
+ join(cwd, '.claude', 'settings.local.json'),
14
+ ]),
15
+ ];
16
+ }
17
+ function envBlock(file) {
18
+ if (!existsSync(file))
19
+ return {};
20
+ try {
21
+ const parsed = JSON.parse(readFileSync(file, 'utf8'));
22
+ const block = parsed.env;
23
+ return typeof block === 'object' && block !== null ? block : {};
24
+ }
25
+ catch {
26
+ return {};
27
+ }
28
+ }
29
+ export function settingsConflicts(files) {
30
+ const out = [];
31
+ for (const file of files) {
32
+ const block = envBlock(file);
33
+ for (const key of CONFLICTING) {
34
+ const value = block[key];
35
+ if (typeof value === 'string' && value.trim() !== '')
36
+ out.push(`${file}: ${key}`);
37
+ }
38
+ }
39
+ return out;
40
+ }
package/dist/claude.js ADDED
@@ -0,0 +1,197 @@
1
+ import { spawn, spawnSync } from 'node:child_process';
2
+ import { markOnboardingDone, seedChannels } from './onboarding.js';
3
+ import { writeMcpConfig } from './mcp-config.js';
4
+ import { currentRoute, permissionMode, routeModelEnv, systemPrompt } from './route.js';
5
+ import { settingsConflicts, settingsFiles } from './claude-settings.js';
6
+ import { localAgent } from './local.js';
7
+ import { PROVIDER_FLAGS } from './provider-flags.js';
8
+ import { localPort, localUrl } from './runtime.js';
9
+ import { keepInSession, takeBackConversation } from './background.js';
10
+ const CHANNEL_FLAGS = ['--dangerously-load-development-channels', 'server:metro'];
11
+ const FRESH_PROMPT_FLAGS = ['--system-prompt-snapshot', 'off'];
12
+ const PERMISSION_MODE_FLAG = { auto: 'auto', bypass: 'bypassPermissions' };
13
+ const KEY_HEADER = 'x-metro-key';
14
+ const PROBE_MS = 3_000;
15
+ const AUTH_STATUS_MS = 20_000;
16
+ const KILL_GRACE_MS = 30_000;
17
+ export const claudeArgs = (extra, mcpConfig, mode = 'auto', prompt = null) => [
18
+ ...CHANNEL_FLAGS,
19
+ '--permission-mode',
20
+ PERMISSION_MODE_FLAG[mode],
21
+ ...FRESH_PROMPT_FLAGS,
22
+ ...(mcpConfig === undefined ? [] : ['--mcp-config', mcpConfig]),
23
+ ...(prompt === null ? [] : ['--append-system-prompt', prompt]),
24
+ ...extra,
25
+ ];
26
+ const set = (env, name) => (env[name] ?? '').trim() !== '';
27
+ export function pinnedBy(env) {
28
+ if (set(env, 'ANTHROPIC_BASE_URL'))
29
+ return 'ANTHROPIC_BASE_URL';
30
+ return PROVIDER_FLAGS.find((flag) => set(env, flag)) ?? null;
31
+ }
32
+ export function gatewayEnv(base, agentKey, port) {
33
+ if (agentKey === null || pinnedBy(base) !== null)
34
+ return base;
35
+ const own = (base.ANTHROPIC_CUSTOM_HEADERS ?? '').trim();
36
+ const mine = `${KEY_HEADER}: ${agentKey}`;
37
+ return {
38
+ ...base,
39
+ ANTHROPIC_BASE_URL: `http://127.0.0.1:${String(port)}/gateway`,
40
+ ANTHROPIC_CUSTOM_HEADERS: own === '' ? mine : `${own}\n${mine}`,
41
+ CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY: '1',
42
+ };
43
+ }
44
+ export const channelEnv = (env) => set(env, 'MCP_PROTOCOL_NEGOTIATION') ? env : { ...env, MCP_PROTOCOL_NEGOTIATION: 'legacy' };
45
+ export const toolSearchEnv = (env) => set(env, 'ENABLE_TOOL_SEARCH') ? env : { ...env, ENABLE_TOOL_SEARCH: 'true' };
46
+ const OWN_CREDENTIALS = ['ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN'];
47
+ export function credentialEnv(env, agentKey, signedIn) {
48
+ if (signedIn || OWN_CREDENTIALS.some((name) => set(env, name)))
49
+ return env;
50
+ return { ...env, ANTHROPIC_AUTH_TOKEN: agentKey };
51
+ }
52
+ function claudeSignedIn() {
53
+ const run = spawnSync('claude', ['auth', 'status', '--json'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], timeout: AUTH_STATUS_MS });
54
+ if (run.error !== undefined || typeof run.stdout !== 'string')
55
+ return false;
56
+ try {
57
+ const parsed = JSON.parse(run.stdout);
58
+ return parsed.authenticated === true || parsed.loggedIn === true || typeof parsed.email === 'string' || typeof parsed.organization === 'string';
59
+ }
60
+ catch {
61
+ return false;
62
+ }
63
+ }
64
+ export function servingDaemon(body) {
65
+ if (typeof body !== 'object' || body === null)
66
+ return false;
67
+ const mode = body;
68
+ return mode.mode === 'local' && mode.stopped !== true;
69
+ }
70
+ async function daemonServing(base = localUrl()) {
71
+ try {
72
+ const res = await fetch(`${base}/api/mode`, { signal: AbortSignal.timeout(PROBE_MS) });
73
+ return res.ok && servingDaemon(await res.json());
74
+ }
75
+ catch {
76
+ return false;
77
+ }
78
+ }
79
+ export function agentKey(agent) {
80
+ return agent === null ? { skip: 'no agent lives on this machine yet, so Claude Code talks to Anthropic directly' } : { key: agent.key };
81
+ }
82
+ async function verdict() {
83
+ const pinned = pinnedBy(process.env);
84
+ if (pinned !== null)
85
+ return { skip: `${pinned} is set, so Claude Code keeps talking to it` };
86
+ const conflicts = settingsConflicts(settingsFiles());
87
+ if (conflicts.length > 0)
88
+ return { skip: `a settings file pins the provider (${conflicts.join(', ')}), so Claude Code keeps it` };
89
+ const picked = agentKey(localAgent());
90
+ if ('skip' in picked)
91
+ return picked;
92
+ if (await daemonServing())
93
+ return picked;
94
+ return { skip: 'the daemon is not serving here (stopped, or not running), so Claude Code talks to Anthropic directly' };
95
+ }
96
+ function deadline(child, timeoutMs) {
97
+ if (timeoutMs === undefined)
98
+ return () => undefined;
99
+ let kill;
100
+ const term = setTimeout(() => {
101
+ child.kill('SIGTERM');
102
+ kill = setTimeout(() => {
103
+ child.kill('SIGKILL');
104
+ }, KILL_GRACE_MS);
105
+ }, timeoutMs);
106
+ return () => {
107
+ clearTimeout(term);
108
+ clearTimeout(kill);
109
+ };
110
+ }
111
+ export function runClaude(args, env, headless) {
112
+ return new Promise((resolve, reject) => {
113
+ const leaveToChild = () => undefined;
114
+ process.on('SIGINT', leaveToChild);
115
+ process.on('SIGTERM', leaveToChild);
116
+ const child = spawn('claude', args, { stdio: [headless === undefined ? 'inherit' : 'ignore', 'inherit', 'inherit'], env });
117
+ const stop = deadline(child, headless?.timeoutMs);
118
+ child.on('error', (err) => {
119
+ reject(new Error(err.code === 'ENOENT'
120
+ ? 'the `claude` command is not on PATH — install Claude Code first'
121
+ : err.message));
122
+ });
123
+ child.on('exit', (code) => {
124
+ stop();
125
+ resolve(code ?? 1);
126
+ });
127
+ });
128
+ }
129
+ async function servedKey(decision) {
130
+ if ('key' in decision)
131
+ return decision.key;
132
+ const picked = agentKey(localAgent());
133
+ if ('skip' in picked)
134
+ return null;
135
+ return (await daemonServing()) ? picked.key : null;
136
+ }
137
+ function mcpConfigFor(key, port) {
138
+ if (key === null)
139
+ return null;
140
+ const file = writeMcpConfig(key, port);
141
+ process.stderr.write(`metro claude: the metro MCP server is loaded for this session from the daemon at http://127.0.0.1:${String(port)}/mcp, nothing to add by hand\n`);
142
+ return file;
143
+ }
144
+ function gatewayLaunchEnv(key, port) {
145
+ process.stderr.write(`metro claude: inference goes through the daemon at http://127.0.0.1:${String(port)}/gateway (the Model page decides where)\n`);
146
+ const pointed = routeModelEnv(gatewayEnv(process.env, key, port), currentRoute());
147
+ const routed = toolSearchEnv(pointed);
148
+ if (routed !== pointed)
149
+ process.stderr.write('metro claude: MCP tool search is on, so connector tools load when Claude needs them instead of all at start\n');
150
+ const env = credentialEnv(routed, key, claudeSignedIn());
151
+ if (env !== routed)
152
+ process.stderr.write("metro claude: Claude Code has no login of its own here, so metro's key stands in as its credential; the Model page must route to Bedrock, OpenRouter or Codex\n");
153
+ if (seedChannels() === 'marked')
154
+ process.stderr.write('metro claude: marked Channels as available in Claude Code cached flags, since a box that sends no telemetry never fetches them\n');
155
+ if (markOnboardingDone() === 'marked')
156
+ process.stderr.write("metro claude: skipped Claude Code's first-run setup, since it already has a credential here\n");
157
+ return env;
158
+ }
159
+ function inferenceEnv(decision, port) {
160
+ if ('key' in decision)
161
+ return gatewayLaunchEnv(decision.key, port);
162
+ process.stderr.write(`metro claude: ${decision.skip}\n`);
163
+ return process.env;
164
+ }
165
+ export async function headlessEnv() {
166
+ return keepInSession(inferenceEnv(await verdict(), localPort()));
167
+ }
168
+ const continues = (args) => args.includes('-c') || args.includes('--continue');
169
+ async function reclaimConversation(extra) {
170
+ if (!continues(extra))
171
+ return;
172
+ try {
173
+ const note = await takeBackConversation();
174
+ if (note !== null)
175
+ process.stderr.write(`metro claude: ${note}\n`);
176
+ }
177
+ catch (err) {
178
+ const message = err instanceof Error ? err.message : String(err);
179
+ process.stderr.write(`metro claude: could not check for a Claude Code background session holding the conversation (${message})\n`);
180
+ }
181
+ }
182
+ export async function launchClaude(extra) {
183
+ await reclaimConversation(extra);
184
+ const decision = await verdict();
185
+ const port = localPort();
186
+ const mcp = mcpConfigFor(await servedKey(decision), port);
187
+ const mode = permissionMode();
188
+ const prompt = systemPrompt();
189
+ if (prompt !== null)
190
+ process.stderr.write('metro claude: the system prompt from the Harness page is appended to this session\n');
191
+ try {
192
+ return await runClaude(claudeArgs(extra, mcp?.path, mode, prompt), keepInSession(channelEnv(inferenceEnv(decision, port))));
193
+ }
194
+ finally {
195
+ mcp?.cleanup();
196
+ }
197
+ }
package/dist/cli.js CHANGED
@@ -1,133 +1,75 @@
1
1
  #!/usr/bin/env node
2
- import { hostname } from 'node:os';
3
- import { claimCode, claimRuntime, mcpServers, NotSignedIn, whoisAuthorized, } from './api.js';
4
- import { askSecret } from './prompt.js';
5
- import { clearToken, credentialsPath, metroUrl, metroWebUrl, writeToken, } from './store.js';
6
- import { detach, lockedBy, probe, runningPid, stopAll, tail } from './control.js';
7
- import { assertAgentId, daemonPlan, localUrl, readRunToken, runDaemon, runtimeDir, writeRunToken, } from './runtime.js';
2
+ import { whoisAuthorized } from './api.js';
3
+ import { stopAll } from './control.js';
4
+ import { tailEvents } from './tail.js';
5
+ import { launchClaude } from './claude.js';
6
+ import { memoryRoutine } from './memory.js';
8
7
  import { update } from './update.js';
8
+ import { serve } from './serve.js';
9
+ import { service, serviceStopHint } from './service.js';
9
10
  import { currentVersion } from './version.js';
10
- const USAGE = `metro — the command line for your MCP connectors
11
+ const USAGE = `metro: run your agent on this machine
11
12
 
12
- metro start <agent-id> [--detach]
13
- run that agent's stations on this machine
14
- metro stop [agent-id]
15
- stop every metro daemon on this machine, however it was started
16
- metro status <agent-id>
17
- is it running, and is it healthy
18
- metro logs <agent-id> [-f]
19
- show the detached daemon's log
20
- metro login authorize a connector collection with a code from the web UI
21
- metro logout forget this machine's sign-in
22
- metro whoami print the account and collection this machine may read
23
- metro mcp print the mcpServers block for the authorized collection
24
- metro update update to the newest published version
13
+ metro serve [--port <n>] [--owner <organization id>]
14
+ run the daemon: the agent, its channels and its connectors live in
15
+ ~/.metro/agents here, and it is published through Tailscale Funnel at a
16
+ permanent https://<machine>.<tailnet>.ts.net (Tailscale installed and
17
+ signed in on this machine); the page at metro.box manages it through the
18
+ link it prints; --owner names the organization whose members may sign
19
+ in, needed on the first start only; Stop on the page parks the daemon and keeps the
20
+ address, so Start works from the page too
21
+ metro service install [--port <n>] [--owner <organization id>] [--user metro]
22
+ run metro serve as a service (systemd on Linux, launchd on macOS): it
23
+ starts at boot and after a crash, so the page can stop, start and
24
+ restart it with no shell; on Linux, root passes --user metro so Metro
25
+ runs as its own user and Claude Code as the user agent;
26
+ metro service uninstall and status as well
27
+ metro stop stop metro on this machine, metro serve included
28
+ metro tail [agent-id]
29
+ follow this machine's inbound events, one JSON line each
30
+ metro whoami print the agent this machine runs
31
+ metro claude [args...]
32
+ open Claude Code with the metro channel and the metro MCP server, its
33
+ inference routed through the daemon's model gateway (the Model page);
34
+ every argument is passed through the same
35
+ metro memory run the daily memory routine once: when Claude Code transcripts changed
36
+ since the last run, Claude Code reads the memory skill and files them into
37
+ its memory, with no metro tools and writes only inside the memory folder
38
+ metro update update to the newest published version (--check only reports)
25
39
  metro version print this CLI's version
26
40
 
27
- Start Claude Code with all of them, without writing them to disk:
28
-
29
- claude --mcp-config <(metro mcp)
30
-
31
- METRO_URL the metro to talk to (default https://mcp.metro.box)
32
- METRO_UI_URL where the web UI lives (default https://metro.box)
33
- METRO_TOKEN use this connector sign-in instead of the stored one
34
- METRO_RUN_TOKEN use this runtime authorization instead of the stored one
41
+ METRO_WEBHOOK_PORT the daemon's port (default 8420)
42
+ METRO_AGENTS_DIR where the agents live (default ~/.metro/agents)
43
+ METRO_AGENT_KEY the key metro tail presents, instead of the agent file's
35
44
  METRO_RUNTIME_DIR run the daemon from this directory instead of the bundled one
36
45
  `;
37
- function hostLabel() {
38
- const name = hostname().trim();
39
- return name === '' ? 'unnamed machine' : name;
40
- }
41
- async function authorizeRuntime(agentId) {
42
- process.stderr.write(`Authorize this machine at ${metroWebUrl()}/#/authorize/${agentId}\n`);
43
- const code = (await askSecret('Paste the code (input is hidden): ')).trim();
44
- if (code === '')
45
- throw new Error('no code given');
46
- const claimed = await claimRuntime(code, hostLabel());
47
- writeRunToken(claimed.agent, claimed.token);
48
- process.stderr.write(`Authorized as '${claimed.label}'.\n`);
49
- return claimed.token;
50
- }
51
- async function start(argv) {
52
- const agentId = assertAgentId(argv[0]);
53
- if (runningPid(agentId) !== null || lockedBy() !== null)
54
- throw new Error('a metro daemon is already running on this machine. ' +
55
- 'Stop it first: metro stop');
56
- const dir = runtimeDir();
57
- const token = readRunToken(agentId) ?? (await authorizeRuntime(agentId));
58
- const detached = argv.includes('--detach');
59
- const plan = daemonPlan({ agentId, token, dir });
60
- if (!detached)
61
- return runDaemon(agentId, plan);
62
- const pid = detach({ agentId, ...plan });
63
- process.stderr.write(`metro is running for ${agentId} (pid ${String(pid)})\n` +
64
- ` logs: metro logs ${agentId} -f\n` +
65
- ` stop: metro stop ${agentId}\n`);
66
- return 0;
67
- }
68
- async function stopDaemon(argv) {
69
- const agentId = argv[0] === undefined ? undefined : assertAgentId(argv[0]);
70
- const stopped = await stopAll(agentId);
46
+ async function stopDaemon() {
47
+ const stopped = await stopAll();
71
48
  if (stopped.length === 0) {
72
49
  process.stderr.write('no metro daemon is running on this machine\n');
73
50
  return 1;
74
51
  }
75
52
  for (const d of stopped)
76
53
  process.stderr.write(`Stopped metro (pid ${String(d.pid)}, via ${d.via})\n`);
54
+ const hint = serviceStopHint();
55
+ if (hint !== null)
56
+ process.stderr.write(`${hint}\n`);
77
57
  return 0;
78
58
  }
79
- async function status(argv) {
80
- const agentId = assertAgentId(argv[0]);
81
- const pid = runningPid(agentId);
82
- if (pid === null) {
83
- process.stdout.write(`${agentId}: not running\n`);
84
- return 1;
85
- }
86
- const health = await probe(localUrl());
87
- process.stdout.write(`${agentId}: running (pid ${String(pid)}) · ` +
88
- (health === null
89
- ? `not answering on ${localUrl()}\n`
90
- : `healthy, up ${String(health.uptime)}s\n`));
91
- return health === null ? 1 : 0;
92
- }
93
- function logs(argv) {
94
- const agentId = assertAgentId(argv[0]);
95
- return tail(agentId, argv.includes('-f') || argv.includes('--follow'));
96
- }
97
- async function login() {
98
- process.stderr.write(`Choose a connector collection at ${metroWebUrl()}/#/authorize\n`);
99
- const { token, email, collection } = await claimCode(await askSecret('Paste the code here (input is hidden): '));
100
- writeToken(token);
101
- process.stderr.write(`Authorized '${collection}' for ${email}. Stored in ${credentialsPath()}\n`);
102
- }
103
- async function whoami() {
104
- const { email, collection } = await whoisAuthorized();
105
- process.stdout.write(`${email} · collection '${collection}' on ${metroUrl()}\n`);
106
- }
107
59
  const HELP = new Set([undefined, 'help', '--help', '-h']);
108
60
  const COMMANDS = {
109
- login: async () => {
110
- await login();
111
- return 0;
112
- },
113
- logout: async () => {
114
- clearToken();
115
- process.stderr.write('Signed out.\n');
116
- return Promise.resolve(0);
117
- },
118
61
  whoami: async () => {
119
- await whoami();
120
- return 0;
121
- },
122
- start: () => start(process.argv.slice(3)),
123
- stop: () => stopDaemon(process.argv.slice(3)),
124
- status: () => status(process.argv.slice(3)),
125
- logs: () => logs(process.argv.slice(3)),
126
- mcp: async () => {
127
- process.stdout.write(`${await mcpServers()}\n`);
62
+ const { agent, where } = await whoisAuthorized();
63
+ process.stdout.write(`agent ${agent} on ${where}\n`);
128
64
  return 0;
129
65
  },
130
- update,
66
+ serve: () => serve(process.argv.slice(3)),
67
+ service: () => service(process.argv.slice(3)),
68
+ stop: stopDaemon,
69
+ tail: () => tailEvents(process.argv.slice(3)),
70
+ claude: () => launchClaude(process.argv.slice(3)),
71
+ memory: () => memoryRoutine(),
72
+ update: () => update(process.argv.slice(3)),
131
73
  version: async () => {
132
74
  process.stdout.write(`${currentVersion()}\n`);
133
75
  return Promise.resolve(0);
@@ -143,6 +85,6 @@ async function run(command) {
143
85
  const code = await run(process.argv[2]).catch((err) => {
144
86
  const message = err instanceof Error ? err.message : String(err);
145
87
  process.stderr.write(`metro: ${message}\n`);
146
- return err instanceof NotSignedIn ? 2 : 1;
88
+ return 1;
147
89
  });
148
90
  process.exit(code);