@stage-labs/metro 0.1.0-beta.21 → 0.1.0-beta.211

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 (436) hide show
  1. package/dist/api.js +9 -101
  2. package/dist/claude-settings.js +40 -0
  3. package/dist/claude.js +152 -0
  4. package/dist/cli.js +52 -109
  5. package/dist/control.js +47 -75
  6. package/dist/hold.js +210 -0
  7. package/dist/local.js +43 -0
  8. package/dist/mcp-config.js +25 -0
  9. package/dist/node-name.js +71 -0
  10. package/dist/onboarding.js +44 -0
  11. package/dist/provider-flags.js +9 -0
  12. package/dist/route.js +58 -0
  13. package/dist/runtime-install.js +96 -0
  14. package/dist/runtime.js +29 -52
  15. package/dist/serve.js +157 -0
  16. package/dist/service.js +304 -0
  17. package/dist/tail.js +119 -0
  18. package/dist/update.js +13 -1
  19. package/package.json +2 -23
  20. package/runtime/marketplace/.claude-plugin/marketplace.json +12 -0
  21. package/runtime/marketplace/plugin/.claude-plugin/plugin.json +17 -0
  22. package/runtime/marketplace/plugin/.mcp.json +1 -0
  23. package/runtime/marketplace/plugin/bin/guard.mjs +71 -0
  24. package/runtime/marketplace/plugin/bin/metro-plugin.mjs +30 -0
  25. package/runtime/marketplace/plugin/bin/policy.mjs +97 -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 +26 -0
  29. package/runtime/node_modules/@metro-labs/core/package.json +47 -0
  30. package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
  31. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/events.ts +11 -7
  32. package/runtime/node_modules/@metro-labs/{mcp/src/db → core/src}/ids.ts +5 -0
  33. package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
  34. package/runtime/node_modules/@metro-labs/{mcp/src/stations → core/src}/lines.ts +24 -28
  35. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/protocol.ts +7 -4
  36. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/secure-fs.ts +17 -0
  37. package/runtime/node_modules/@metro-labs/core/src/station-names.ts +13 -0
  38. package/runtime/node_modules/@metro-labs/core/src/stations/account-files.ts +41 -0
  39. package/runtime/node_modules/@metro-labs/core/src/stations/account-store.ts +83 -0
  40. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/attachments.ts +0 -1
  41. package/runtime/node_modules/@metro-labs/core/src/stations/messaging-normalize.ts +16 -0
  42. package/runtime/node_modules/@metro-labs/core/src/stations/profile.ts +58 -0
  43. package/runtime/node_modules/@metro-labs/core/src/stations/sender-profile.ts +64 -0
  44. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/station-runtime.ts +6 -11
  45. package/runtime/node_modules/@metro-labs/core/src/stations/train-boot.ts +42 -0
  46. package/runtime/node_modules/@metro-labs/core/src/stations/train-events.ts +84 -0
  47. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/types.ts +18 -1
  48. package/runtime/node_modules/@metro-labs/core/src/tickets.ts +37 -0
  49. package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
  50. package/runtime/node_modules/@metro-labs/daemon/package.json +48 -0
  51. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/agent-fs.ts +134 -0
  52. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files-api.ts +12 -0
  53. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files.ts +89 -0
  54. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/home-fs.ts +113 -0
  55. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/job-env.ts +51 -0
  56. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/provision.ts +80 -0
  57. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedule-detail.ts +99 -0
  58. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules-api.ts +27 -0
  59. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules.ts +144 -0
  60. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/unit-files.ts +37 -0
  61. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/user.ts +89 -0
  62. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/view.ts +87 -0
  63. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-attach.ts +19 -0
  64. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-lookups.ts +55 -0
  65. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-routes.ts +76 -0
  66. package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +357 -0
  67. package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +30 -0
  68. package/runtime/node_modules/@metro-labs/daemon/src/agents/allowlist.ts +59 -0
  69. package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +131 -0
  70. package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +132 -0
  71. package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +305 -0
  72. package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +142 -0
  73. package/runtime/node_modules/@metro-labs/{mcp/src/db/key-map.ts → daemon/src/agents/keys.ts} +1 -11
  74. package/runtime/node_modules/@metro-labs/{mcp/src/db/agent-map.ts → daemon/src/agents/map.ts} +58 -1
  75. package/runtime/node_modules/@metro-labs/daemon/src/agents/policy-route.ts +27 -0
  76. package/runtime/node_modules/@metro-labs/{mcp/src/db/agent-scope.ts → daemon/src/agents/scope.ts} +2 -2
  77. package/runtime/node_modules/@metro-labs/daemon/src/agents/sender-cards.ts +94 -0
  78. package/runtime/node_modules/@metro-labs/daemon/src/agents/senders.ts +38 -0
  79. package/runtime/node_modules/@metro-labs/daemon/src/approvals/api.ts +55 -0
  80. package/runtime/node_modules/@metro-labs/daemon/src/approvals/pending.ts +150 -0
  81. package/runtime/node_modules/@metro-labs/daemon/src/approvals/preview.ts +66 -0
  82. package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +218 -0
  83. package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +36 -0
  84. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/crash-guard.ts +1 -1
  85. package/runtime/node_modules/@metro-labs/daemon/src/boot/local-owner.ts +21 -0
  86. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/paths.ts +6 -34
  87. package/runtime/node_modules/@metro-labs/daemon/src/channels/addressed.ts +26 -0
  88. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/inbound.ts +70 -45
  89. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/media-note.ts +11 -7
  90. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/pending.ts +4 -1
  91. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/relay.ts +2 -2
  92. package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +355 -0
  93. package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +359 -0
  94. package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +208 -0
  95. package/runtime/node_modules/@metro-labs/daemon/src/claude/memory.ts +32 -0
  96. package/runtime/node_modules/@metro-labs/daemon/src/claude/onboarding.ts +60 -0
  97. package/runtime/node_modules/@metro-labs/daemon/src/claude/plugin-install.ts +149 -0
  98. package/runtime/node_modules/@metro-labs/daemon/src/claude/session-files.ts +75 -0
  99. package/runtime/node_modules/@metro-labs/daemon/src/claude/session.ts +313 -0
  100. package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +109 -0
  101. package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +273 -0
  102. package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +120 -0
  103. package/runtime/node_modules/@metro-labs/daemon/src/claude/version.ts +113 -0
  104. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-api.ts → daemon/src/connectors/api.ts} +79 -113
  105. package/runtime/node_modules/@metro-labs/{mcp/src/db/connector-config.ts → daemon/src/connectors/config.ts} +67 -41
  106. package/runtime/node_modules/@metro-labs/daemon/src/connectors/gates.ts +72 -0
  107. package/runtime/node_modules/@metro-labs/daemon/src/connectors/health.ts +18 -0
  108. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-client.ts +14 -17
  109. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-discovery.ts +33 -20
  110. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth-routes.ts → daemon/src/connectors/oauth-routes.ts} +30 -32
  111. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth.ts → daemon/src/connectors/oauth.ts} +61 -22
  112. package/runtime/node_modules/@metro-labs/daemon/src/connectors/plugin-sync.ts +131 -0
  113. package/runtime/node_modules/@metro-labs/daemon/src/connectors/reach.ts +27 -0
  114. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-policy.ts +90 -0
  115. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +347 -0
  116. package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +385 -0
  117. package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +81 -0
  118. package/runtime/node_modules/@metro-labs/daemon/src/connectors/url.ts +37 -0
  119. package/runtime/node_modules/@metro-labs/daemon/src/connectors/verify.ts +106 -0
  120. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-grant.ts +4 -4
  121. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-owner.ts +3 -3
  122. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-reaper.ts +174 -0
  123. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-serve.ts +12 -13
  124. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-api.ts +10 -27
  125. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-store.ts +4 -4
  126. package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +233 -0
  127. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +208 -0
  128. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-device.ts +91 -0
  129. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +173 -0
  130. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +195 -0
  131. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-version.ts +44 -0
  132. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +128 -0
  133. package/runtime/node_modules/@metro-labs/daemon/src/gateway/effort.ts +77 -0
  134. package/runtime/node_modules/@metro-labs/daemon/src/gateway/eventstream.ts +123 -0
  135. package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +237 -0
  136. package/runtime/node_modules/@metro-labs/daemon/src/gateway/frames.ts +118 -0
  137. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +274 -0
  138. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-auth.ts +160 -0
  139. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-client.ts +46 -0
  140. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-setup.ts +150 -0
  141. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-stream.ts +139 -0
  142. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-translate.ts +224 -0
  143. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini.ts +208 -0
  144. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +199 -0
  145. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +278 -0
  146. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-signin.ts +193 -0
  147. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-store.ts +70 -0
  148. package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +90 -0
  149. package/runtime/node_modules/@metro-labs/daemon/src/gateway/pkce.ts +36 -0
  150. package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +66 -0
  151. package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +18 -0
  152. package/runtime/node_modules/@metro-labs/daemon/src/gateway/subscription.ts +120 -0
  153. package/runtime/node_modules/@metro-labs/daemon/src/gateway/text.ts +14 -0
  154. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +244 -0
  155. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/accounts.ts +28 -17
  156. package/runtime/node_modules/@metro-labs/daemon/src/mcp/attachment-schema.ts +91 -0
  157. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/call-tools.ts +49 -20
  158. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/ctx.ts +4 -4
  159. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/event-store.ts +15 -16
  160. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/group-tools.ts +2 -2
  161. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/index.ts +24 -79
  162. package/runtime/node_modules/@metro-labs/daemon/src/mcp/instructions.ts +19 -0
  163. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/member-tools.ts +2 -2
  164. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-prompt.ts +87 -0
  165. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +79 -0
  166. package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-gate.ts +82 -0
  167. package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-snapshot.ts +79 -0
  168. package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-lookup.ts +60 -0
  169. package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-tool.ts +96 -0
  170. package/runtime/node_modules/@metro-labs/daemon/src/mcp/read-tool.ts +87 -0
  171. package/runtime/node_modules/@metro-labs/daemon/src/mcp/request-identity.ts +46 -0
  172. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-slot.ts +48 -0
  173. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/session.ts +33 -42
  174. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-catalog.ts +88 -0
  175. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-def.ts +9 -0
  176. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-dispatch.ts +53 -40
  177. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-schemas.ts +68 -119
  178. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/upload-tool.ts +6 -11
  179. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/helper-script.ts +126 -0
  180. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/install.ts +37 -0
  181. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/privilege.ts +48 -0
  182. package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +132 -0
  183. package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +316 -0
  184. package/runtime/node_modules/@metro-labs/daemon/src/policy/policy.ts +118 -0
  185. package/runtime/node_modules/@metro-labs/daemon/src/routes/bearer.ts +35 -0
  186. package/runtime/node_modules/@metro-labs/daemon/src/routes/body.ts +24 -0
  187. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/routes}/http.ts +59 -51
  188. package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +205 -0
  189. package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +66 -0
  190. package/runtime/node_modules/@metro-labs/daemon/src/routes/session.ts +29 -0
  191. package/runtime/node_modules/@metro-labs/daemon/src/routes/threema-callback.ts +103 -0
  192. package/runtime/node_modules/@metro-labs/daemon/src/server/control.ts +39 -0
  193. package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +58 -0
  194. package/runtime/node_modules/@metro-labs/daemon/src/server/owner.ts +26 -0
  195. package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +90 -0
  196. package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
  197. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-driver.ts +42 -0
  198. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-inline.ts +29 -1
  199. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-interactive.ts +9 -36
  200. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-outlook.ts +63 -0
  201. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-resolve.ts +38 -13
  202. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/attach-session.ts +32 -22
  203. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-xmtp.ts +8 -9
  204. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach.ts +75 -9
  205. package/runtime/node_modules/@metro-labs/daemon/src/stations/materialize.ts +265 -0
  206. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/registry.ts +22 -6
  207. package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +82 -0
  208. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor-io.ts +3 -3
  209. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor.ts +6 -9
  210. package/runtime/node_modules/@metro-labs/daemon/src/stations/threema-callbacks.ts +32 -0
  211. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/train-call.ts +1 -1
  212. package/runtime/node_modules/@metro-labs/daemon/src/stations/webhook-endpoints.ts +51 -0
  213. package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +84 -0
  214. package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +124 -0
  215. package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +15 -0
  216. package/runtime/node_modules/@metro-labs/daemon/src/vault/api.ts +45 -0
  217. package/runtime/node_modules/@metro-labs/daemon/src/vault/config.ts +51 -0
  218. package/runtime/node_modules/@metro-labs/daemon/src/vault/firewall.ts +9 -0
  219. package/runtime/node_modules/@metro-labs/daemon/src/vault/index.ts +96 -0
  220. package/runtime/node_modules/@metro-labs/daemon/src/vault/install.ts +56 -0
  221. package/runtime/node_modules/@metro-labs/daemon/src/vault/paths.ts +26 -0
  222. package/runtime/node_modules/@metro-labs/daemon/src/vault/proxy.ts +147 -0
  223. package/runtime/node_modules/@metro-labs/daemon/src/vault/store.ts +129 -0
  224. package/runtime/node_modules/@metro-labs/daemon/src/vault/trust.ts +44 -0
  225. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/package.json +3 -5
  226. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/accounts.ts +8 -28
  227. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/actions.ts +19 -187
  228. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/attachments.ts +3 -3
  229. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/format.ts +31 -72
  230. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/group-actions.ts +2 -2
  231. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/group.ts +2 -2
  232. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/index.ts +15 -21
  233. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/members.ts +2 -2
  234. package/runtime/node_modules/@metro-labs/discord-bot/src/profile.ts +68 -0
  235. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/send-files.ts +12 -13
  236. package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +23 -0
  237. package/runtime/node_modules/@metro-labs/http/package.json +29 -0
  238. package/runtime/node_modules/@metro-labs/http/src/api-http.ts +135 -0
  239. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/session-api.ts → http/src/mode-api.ts} +13 -9
  240. package/runtime/node_modules/@metro-labs/http/src/return-to.ts +21 -0
  241. package/runtime/node_modules/@metro-labs/http/src/workos-token.ts +149 -0
  242. package/runtime/node_modules/@metro-labs/{telegram-user → outlook}/package.json +2 -5
  243. package/runtime/node_modules/@metro-labs/outlook/src/accounts.ts +93 -0
  244. package/runtime/node_modules/@metro-labs/outlook/src/actions.ts +14 -0
  245. package/runtime/node_modules/@metro-labs/outlook/src/attachments.ts +97 -0
  246. package/runtime/node_modules/@metro-labs/outlook/src/auth.ts +150 -0
  247. package/runtime/node_modules/@metro-labs/outlook/src/browser.ts +53 -0
  248. package/runtime/node_modules/@metro-labs/outlook/src/config.ts +36 -0
  249. package/runtime/node_modules/@metro-labs/outlook/src/format.ts +140 -0
  250. package/runtime/node_modules/@metro-labs/outlook/src/graph.ts +60 -0
  251. package/runtime/node_modules/@metro-labs/outlook/src/html.ts +72 -0
  252. package/runtime/node_modules/@metro-labs/outlook/src/inbound.ts +104 -0
  253. package/runtime/node_modules/@metro-labs/outlook/src/index.ts +12 -0
  254. package/runtime/node_modules/@metro-labs/outlook/src/login.ts +150 -0
  255. package/runtime/node_modules/@metro-labs/outlook/src/me.ts +41 -0
  256. package/runtime/node_modules/@metro-labs/outlook/src/outbound.ts +116 -0
  257. package/runtime/node_modules/@metro-labs/outlook/src/query.ts +119 -0
  258. package/runtime/node_modules/@metro-labs/outlook/src/state.ts +43 -0
  259. package/runtime/node_modules/@metro-labs/outlook/src/station.ts +15 -0
  260. package/runtime/node_modules/@metro-labs/outlook/src/trust.ts +70 -0
  261. package/runtime/node_modules/@metro-labs/telegram/package.json +3 -2
  262. package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +38 -96
  263. package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +214 -253
  264. package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +67 -108
  265. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/client.ts +6 -6
  266. package/runtime/node_modules/@metro-labs/telegram/src/format.ts +101 -147
  267. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/group.ts +4 -4
  268. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/history.ts +1 -1
  269. package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +57 -0
  270. package/runtime/node_modules/@metro-labs/telegram/src/index.ts +6 -102
  271. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/login.ts +20 -20
  272. package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +64 -151
  273. package/runtime/node_modules/@metro-labs/telegram/src/members.ts +61 -33
  274. package/runtime/node_modules/@metro-labs/telegram/src/profile.ts +70 -0
  275. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/reactions.ts +3 -3
  276. package/runtime/node_modules/@metro-labs/telegram/src/station.ts +11 -1
  277. package/runtime/node_modules/@metro-labs/telegram/src/types.ts +5 -47
  278. package/runtime/node_modules/@metro-labs/telegram-bot/package.json +25 -0
  279. package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +86 -0
  280. package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +240 -0
  281. package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +128 -0
  282. package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +170 -0
  283. package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +103 -0
  284. package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +90 -0
  285. package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +47 -0
  286. package/runtime/node_modules/@metro-labs/telegram-bot/src/profile.ts +85 -0
  287. package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +21 -0
  288. package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +56 -0
  289. package/runtime/node_modules/@metro-labs/threema/package.json +26 -0
  290. package/runtime/node_modules/@metro-labs/threema/src/accounts.ts +95 -0
  291. package/runtime/node_modules/@metro-labs/threema/src/actions.ts +124 -0
  292. package/runtime/node_modules/@metro-labs/threema/src/api.ts +152 -0
  293. package/runtime/node_modules/@metro-labs/threema/src/crypto.ts +100 -0
  294. package/runtime/node_modules/@metro-labs/threema/src/files.ts +47 -0
  295. package/runtime/node_modules/@metro-labs/threema/src/format.ts +164 -0
  296. package/runtime/node_modules/@metro-labs/threema/src/groups.ts +96 -0
  297. package/runtime/node_modules/@metro-labs/threema/src/ids.ts +21 -0
  298. package/runtime/node_modules/@metro-labs/threema/src/inbound.ts +89 -0
  299. package/runtime/node_modules/@metro-labs/threema/src/index.ts +24 -0
  300. package/runtime/node_modules/@metro-labs/threema/src/messages.ts +264 -0
  301. package/runtime/node_modules/@metro-labs/threema/src/outbound.ts +160 -0
  302. package/runtime/node_modules/@metro-labs/threema/src/station.ts +13 -0
  303. package/runtime/node_modules/@metro-labs/threema/src/verify.ts +117 -0
  304. package/runtime/node_modules/@metro-labs/webhook/package.json +1 -1
  305. package/runtime/node_modules/@metro-labs/webhook/src/station.ts +5 -8
  306. package/runtime/node_modules/@metro-labs/whatsapp/package.json +2 -5
  307. package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +6 -28
  308. package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +1 -1
  309. package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +54 -11
  310. package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +2 -2
  311. package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +1 -1
  312. package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +86 -4
  313. package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +7 -58
  314. package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +11 -28
  315. package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +4 -37
  316. package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +1 -1
  317. package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +1 -1
  318. package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +1 -1
  319. package/runtime/node_modules/@metro-labs/whatsapp/src/names.ts +75 -0
  320. package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +44 -0
  321. package/runtime/node_modules/@metro-labs/whatsapp/src/resolve.ts +52 -0
  322. package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +16 -1
  323. package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +5 -9
  324. package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +0 -1
  325. package/runtime/node_modules/@metro-labs/xmtp/package.json +3 -2
  326. package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +10 -20
  327. package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +2 -2
  328. package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +15 -204
  329. package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +4 -43
  330. package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +41 -219
  331. package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +3 -3
  332. package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +3 -3
  333. package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +7 -24
  334. package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +8 -18
  335. package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +1 -1
  336. package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +2 -2
  337. package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +30 -16
  338. package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +12 -20
  339. package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +1 -19
  340. package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +1 -1
  341. package/runtime/node_modules/@metro-labs/xmtp/src/names.ts +61 -0
  342. package/runtime/node_modules/@metro-labs/xmtp/src/profile.ts +153 -0
  343. package/runtime/node_modules/@metro-labs/xmtp/src/sender.ts +112 -0
  344. package/runtime/node_modules/@metro-labs/xmtp/src/smart.ts +72 -0
  345. package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +5 -1
  346. package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +4 -51
  347. package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +30 -44
  348. package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +4 -6
  349. package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +19 -5
  350. package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +14 -4
  351. package/runtime/runtime.json +1 -1
  352. package/runtime/server.ts +1 -0
  353. package/runtime/stations.json +37 -0
  354. package/dist/prompt.js +0 -10
  355. package/dist/store.js +0 -70
  356. package/runtime/node_modules/@metro-labs/discord/src/station.ts +0 -19
  357. package/runtime/node_modules/@metro-labs/discord/src/voice-speak.ts +0 -195
  358. package/runtime/node_modules/@metro-labs/discord/src/voice-transcribe.ts +0 -292
  359. package/runtime/node_modules/@metro-labs/discord/src/voice.ts +0 -197
  360. package/runtime/node_modules/@metro-labs/discord/src/wire.ts +0 -5
  361. package/runtime/node_modules/@metro-labs/mcp/package.json +0 -66
  362. package/runtime/node_modules/@metro-labs/mcp/src/channels/dedupe.ts +0 -24
  363. package/runtime/node_modules/@metro-labs/mcp/src/daemon/account-api.ts +0 -311
  364. package/runtime/node_modules/@metro-labs/mcp/src/daemon/agent-api.ts +0 -335
  365. package/runtime/node_modules/@metro-labs/mcp/src/daemon/api-http.ts +0 -129
  366. package/runtime/node_modules/@metro-labs/mcp/src/daemon/boot.ts +0 -322
  367. package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair-api.ts +0 -111
  368. package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair.ts +0 -20
  369. package/runtime/node_modules/@metro-labs/mcp/src/daemon/collection-api.ts +0 -202
  370. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-json.ts +0 -31
  371. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-tools.ts +0 -100
  372. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-url.ts +0 -57
  373. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-verify.ts +0 -333
  374. package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-auth.ts +0 -164
  375. package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-oauth.ts +0 -208
  376. package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity.ts +0 -79
  377. package/runtime/node_modules/@metro-labs/mcp/src/daemon/oauth-pending.ts +0 -65
  378. package/runtime/node_modules/@metro-labs/mcp/src/daemon/pair-codes.ts +0 -58
  379. package/runtime/node_modules/@metro-labs/mcp/src/daemon/project-api.ts +0 -214
  380. package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-api.ts +0 -125
  381. package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-pair.ts +0 -18
  382. package/runtime/node_modules/@metro-labs/mcp/src/daemon/runtime-source.ts +0 -105
  383. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session-apis.ts +0 -41
  384. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session.ts +0 -218
  385. package/runtime/node_modules/@metro-labs/mcp/src/daemon/tunnel.ts +0 -169
  386. package/runtime/node_modules/@metro-labs/mcp/src/db/account-attach.ts +0 -91
  387. package/runtime/node_modules/@metro-labs/mcp/src/db/agent-admin.ts +0 -215
  388. package/runtime/node_modules/@metro-labs/mcp/src/db/client.ts +0 -37
  389. package/runtime/node_modules/@metro-labs/mcp/src/db/connector-collections.ts +0 -218
  390. package/runtime/node_modules/@metro-labs/mcp/src/db/connectors.ts +0 -329
  391. package/runtime/node_modules/@metro-labs/mcp/src/db/materialize.ts +0 -364
  392. package/runtime/node_modules/@metro-labs/mcp/src/db/projects.ts +0 -300
  393. package/runtime/node_modules/@metro-labs/mcp/src/db/runtime-admin.ts +0 -31
  394. package/runtime/node_modules/@metro-labs/mcp/src/db/runtimes.ts +0 -105
  395. package/runtime/node_modules/@metro-labs/mcp/src/db/schema.ts +0 -131
  396. package/runtime/node_modules/@metro-labs/mcp/src/db/token-carry.ts +0 -45
  397. package/runtime/node_modules/@metro-labs/mcp/src/db/users.ts +0 -57
  398. package/runtime/node_modules/@metro-labs/mcp/src/db/whatsapp-login.ts +0 -18
  399. package/runtime/node_modules/@metro-labs/mcp/src/mcp/channel-owner.ts +0 -29
  400. package/runtime/node_modules/@metro-labs/mcp/src/mcp/frame-scope.ts +0 -21
  401. package/runtime/node_modules/@metro-labs/mcp/src/mcp/permission-relay.ts +0 -66
  402. package/runtime/node_modules/@metro-labs/mcp/src/mcp/request-identity.ts +0 -73
  403. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-registry.ts +0 -172
  404. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-route.ts +0 -43
  405. package/runtime/node_modules/@metro-labs/mcp/src/monitor/api.ts +0 -240
  406. package/runtime/node_modules/@metro-labs/mcp/src/server.ts +0 -2
  407. package/runtime/node_modules/@metro-labs/mcp/src/stations/account-store.ts +0 -80
  408. package/runtime/node_modules/@metro-labs/mcp/src/stations/messaging-normalize.ts +0 -88
  409. package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +0 -3
  410. package/runtime/node_modules/@metro-labs/telegram-user/src/accounts.ts +0 -81
  411. package/runtime/node_modules/@metro-labs/telegram-user/src/actions.ts +0 -254
  412. package/runtime/node_modules/@metro-labs/telegram-user/src/attachments.ts +0 -87
  413. package/runtime/node_modules/@metro-labs/telegram-user/src/format.ts +0 -141
  414. package/runtime/node_modules/@metro-labs/telegram-user/src/inbound.ts +0 -78
  415. package/runtime/node_modules/@metro-labs/telegram-user/src/index.ts +0 -46
  416. package/runtime/node_modules/@metro-labs/telegram-user/src/media-actions.ts +0 -80
  417. package/runtime/node_modules/@metro-labs/telegram-user/src/members.ts +0 -75
  418. package/runtime/node_modules/@metro-labs/telegram-user/src/normalize.ts +0 -22
  419. package/runtime/node_modules/@metro-labs/telegram-user/src/station.ts +0 -24
  420. package/runtime/node_modules/@metro-labs/telegram-user/src/types.ts +0 -7
  421. package/runtime/node_modules/@metro-labs/telegram-user/src/wire.ts +0 -1
  422. package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +0 -22
  423. package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +0 -5
  424. package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +0 -87
  425. package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +0 -55
  426. package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +0 -349
  427. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/log.ts +0 -0
  428. /package/runtime/node_modules/@metro-labs/{mcp/src/mcp → core/src}/str.ts +0 -0
  429. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/train-error.ts +0 -0
  430. /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/webhook-note.ts +0 -0
  431. /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/raw-get-stream.ts +0 -0
  432. /package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/api-base.ts +0 -0
  433. /package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/verify.ts +0 -0
  434. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/api-error.ts +0 -0
  435. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/cors.ts +0 -0
  436. /package/runtime/node_modules/@metro-labs/{telegram → telegram-bot}/src/verify.ts +0 -0
@@ -1,364 +0,0 @@
1
- import {
2
- existsSync,
3
- mkdirSync,
4
- readFileSync,
5
- rmSync,
6
- writeFileSync,
7
- } from 'node:fs';
8
- import { homedir } from 'node:os';
9
- import { ID_RE } from './ids.js';
10
- import { join } from 'node:path';
11
- import { eq } from 'drizzle-orm';
12
- import { log } from '../daemon/log.js';
13
- import { writeSecure } from '../daemon/secure-fs.js';
14
- import { closeDb, databaseUrl, getDb } from './client.js';
15
- import {
16
- setAgentMap,
17
- setAllowlistMap,
18
- type AgentMap,
19
- type AgentNameMap,
20
- type AllowlistMap,
21
- } from './agent-map.js';
22
- import { setKeyMap } from './key-map.js';
23
- import { carryTokenStores, PREVIOUS_ACCOUNT_ID } from './token-carry.js';
24
- import { STATIONS, stations, agents, type StationName } from './schema.js';
25
-
26
- interface StationTarget {
27
- file: string;
28
- fileEnv: string;
29
- trainImport: string | null;
30
- }
31
-
32
- export interface LoadedAccount {
33
- station: StationName;
34
- id: string;
35
- allowlist: string[] | null;
36
- config: Record<string, unknown>;
37
- }
38
-
39
- export interface LoadedAgent {
40
- id: string;
41
- name: string;
42
- accounts: LoadedAccount[];
43
- key: string | null;
44
- }
45
-
46
- const METRO_DIR = join(homedir(), '.metro');
47
- const TRAINS_DIR = process.env.METRO_TRAINS_DIR ?? join(METRO_DIR, 'trains');
48
-
49
- const STATION_TARGETS: Record<StationName, StationTarget> = {
50
- xmtp: {
51
- file: 'xmtp-accounts.json',
52
- fileEnv: 'XMTP_ACCOUNTS_FILE',
53
- trainImport: '@metro-labs/xmtp/train',
54
- },
55
- telegram: {
56
- file: 'telegram-accounts.json',
57
- fileEnv: 'TELEGRAM_ACCOUNTS_FILE',
58
- trainImport: '@metro-labs/telegram/train',
59
- },
60
- 'telegram-user': {
61
- file: 'telegram-user-accounts.json',
62
- fileEnv: 'TELEGRAM_USER_ACCOUNTS_FILE',
63
- trainImport: '@metro-labs/telegram-user/train',
64
- },
65
- discord: {
66
- file: 'discord-accounts.json',
67
- fileEnv: 'DISCORD_ACCOUNTS_FILE',
68
- trainImport: '@metro-labs/discord/train',
69
- },
70
- whatsapp: {
71
- file: 'whatsapp-accounts.json',
72
- fileEnv: 'WHATSAPP_ACCOUNTS_FILE',
73
- trainImport: '@metro-labs/whatsapp/train',
74
- },
75
- webhook: {
76
- file: 'webhook-accounts.json',
77
- fileEnv: 'WEBHOOK_ACCOUNTS_FILE',
78
- trainImport: null,
79
- },
80
- };
81
-
82
- function accountFilePath(station: StationName): string {
83
- const target = STATION_TARGETS[station];
84
- return process.env[target.fileEnv] ?? join(METRO_DIR, target.file);
85
- }
86
-
87
- function agentFilter(): string | undefined {
88
- const v = process.env.METRO_AGENT?.trim();
89
- if (!v) return undefined;
90
- if (!ID_RE.test(v))
91
- throw new Error(`METRO_AGENT must be an 11-character agent id, got '${v}'`);
92
- return v;
93
- }
94
-
95
- export type StationSource = () => Promise<LoadedAgent[]>;
96
-
97
- export const MOVABLE_STATIONS = new Set<StationName>(
98
- STATIONS.filter((s) => s !== 'webhook'),
99
- );
100
-
101
- export function unmovableStations(list: LoadedAccount[]): StationName[] {
102
- return [
103
- ...new Set(
104
- list
105
- .map((a) => a.station)
106
- .filter((station) => !MOVABLE_STATIONS.has(station)),
107
- ),
108
- ];
109
- }
110
-
111
- export interface StationRecord {
112
- id: string;
113
- agentId: string;
114
- station: StationName;
115
- }
116
-
117
- export async function listAllStations(): Promise<StationRecord[]> {
118
- if (!databaseUrl()) return [];
119
- const rows = await getDb()
120
- .select({
121
- id: stations.id,
122
- agentId: stations.agentId,
123
- station: stations.station,
124
- })
125
- .from(stations);
126
- return rows;
127
- }
128
-
129
- export async function loadAllStationsFor(
130
- agentId: string,
131
- ): Promise<LoadedAccount[]> {
132
- const rows = await getDb()
133
- .select()
134
- .from(stations)
135
- .where(eq(stations.agentId, agentId));
136
- return rows.map((r) => ({
137
- station: r.station,
138
- id: r.id,
139
- allowlist: r.allowlist,
140
- config: r.config as Record<string, unknown>,
141
- }));
142
- }
143
-
144
- export async function loadAgentForRuntime(
145
- agentId: string,
146
- ): Promise<LoadedAgent> {
147
- const db = getDb();
148
- const rows = await db.select().from(agents).where(eq(agents.id, agentId));
149
- const a = rows[0];
150
- if (a === undefined) throw new Error(`no such agent '${agentId}'`);
151
- const acctRows = await db
152
- .select()
153
- .from(stations)
154
- .where(eq(stations.agentId, a.id));
155
- return {
156
- id: a.id,
157
- name: a.name,
158
- key: a.key,
159
- accounts: acctRows
160
- .filter((r) => MOVABLE_STATIONS.has(r.station))
161
- .map((r) => ({
162
- station: r.station,
163
- id: r.id,
164
- allowlist: r.allowlist,
165
- config: r.config as Record<string, unknown>,
166
- })),
167
- };
168
- }
169
-
170
- export const pgSource: StationSource = () => loadAgents();
171
-
172
- async function loadAgents(): Promise<LoadedAgent[]> {
173
- const db = getDb();
174
- const only = agentFilter();
175
- const agentRows =
176
- only !== undefined
177
- ? await db.select().from(agents).where(eq(agents.id, only))
178
- : await db.select().from(agents);
179
- if (only !== undefined && agentRows.length === 0)
180
- throw new Error(`METRO_AGENT=${only} does not match any agent`);
181
-
182
- const out: LoadedAgent[] = [];
183
- for (const a of agentRows) {
184
- if (a.runtimeId !== null) {
185
- out.push({ id: a.id, name: a.name, accounts: [], key: null });
186
- continue;
187
- }
188
- const acctRows = await db
189
- .select()
190
- .from(stations)
191
- .where(eq(stations.agentId, a.id));
192
- out.push({
193
- id: a.id,
194
- name: a.name,
195
- accounts: acctRows.map((r) => ({
196
- station: r.station,
197
- id: r.id,
198
- allowlist: r.allowlist,
199
- config: r.config as Record<string, unknown>,
200
- })),
201
- key: a.key,
202
- });
203
- }
204
- return out;
205
- }
206
-
207
- function trainConfig(
208
- config: Record<string, unknown>,
209
- ): Record<string, unknown> {
210
- return Object.fromEntries(
211
- Object.entries(config).filter(([key]) => key !== PREVIOUS_ACCOUNT_ID),
212
- );
213
- }
214
-
215
- function trainStubPath(station: StationName): string {
216
- return join(TRAINS_DIR, `${station}.ts`);
217
- }
218
-
219
- function currentText(path: string): string | null {
220
- try {
221
- return readFileSync(path, 'utf8');
222
- } catch {
223
- return null;
224
- }
225
- }
226
-
227
- export function writeIfChanged(path: string, content: string): boolean {
228
- if (currentText(path) === content) return false;
229
- writeFileSync(path, content);
230
- return true;
231
- }
232
-
233
- export const isLocalRuntime = (): boolean =>
234
- (process.env.METRO_RUN_TOKEN?.trim() ?? '') !== '';
235
-
236
- export const stationRunsHere = (station: StationName): boolean =>
237
- isLocalRuntime() || !MOVABLE_STATIONS.has(station);
238
-
239
- function writeStations(list: LoadedAgent[]): Map<StationName, number> {
240
- mkdirSync(METRO_DIR, { recursive: true });
241
- mkdirSync(TRAINS_DIR, { recursive: true });
242
-
243
- const byStation = new Map<StationName, LoadedAccount[]>();
244
- const map: AgentMap = {};
245
- const names: AgentNameMap = {};
246
- const allow: AllowlistMap = {};
247
- for (const agent of list) {
248
- names[agent.id] = agent.name;
249
- for (const a of agent.accounts) {
250
- map[`${a.station}/${a.id}`] = agent.id;
251
- if (a.allowlist) allow[`${a.station}/${a.id}`] = a.allowlist;
252
- if (stationRunsHere(a.station)) {
253
- const cur = byStation.get(a.station);
254
- if (cur) cur.push(a);
255
- else byStation.set(a.station, [a]);
256
- }
257
- }
258
- }
259
- setAgentMap(map, names);
260
- setAllowlistMap(allow);
261
- carryTokenStores(list.flatMap((agent) => agent.accounts));
262
-
263
- const active = new Map<StationName, number>();
264
- for (const [station, accts] of byStation) {
265
- const records = accts.map((a) => ({ id: a.id, ...trainConfig(a.config) }));
266
- writeSecure(accountFilePath(station), JSON.stringify(records, null, 2));
267
- const { trainImport } = STATION_TARGETS[station];
268
- if (trainImport !== null)
269
- writeIfChanged(trainStubPath(station), `import '${trainImport}';\n`);
270
- active.set(station, accts.length);
271
- }
272
- return active;
273
- }
274
-
275
- function pruneStations(present: Map<StationName, number>): StationName[] {
276
- const removed: StationName[] = [];
277
- for (const station of Object.keys(STATION_TARGETS) as StationName[]) {
278
- if (present.has(station)) continue;
279
- const hasTrain = STATION_TARGETS[station].trainImport !== null;
280
- const stub = trainStubPath(station);
281
- if (
282
- (!hasTrain || !existsSync(stub)) &&
283
- !existsSync(accountFilePath(station))
284
- )
285
- continue;
286
- writeSecure(accountFilePath(station), '[]\n');
287
- if (hasTrain) rmSync(stub, { force: true });
288
- removed.push(station);
289
- }
290
- return removed;
291
- }
292
-
293
- const stationLabels = (m: Map<StationName, number>): string[] =>
294
- [...m].map(([station, n]) => `${station}(${n})`);
295
-
296
- function applyKeyMap(list: LoadedAgent[]): void {
297
- lastKey = list.find((a) => a.key !== null)?.key ?? null;
298
- setKeyMap(
299
- list.flatMap((agent) =>
300
- agent.key === null ? [] : [{ key: agent.key, agentId: agent.id }],
301
- ),
302
- );
303
- }
304
-
305
- let lastKey: string | null = null;
306
-
307
- export function localAgentKey(): string | null {
308
- return lastKey;
309
- }
310
-
311
- async function loadAndWrite(
312
- source: StationSource,
313
- ): Promise<{ active: Map<StationName, number>; agents: number }> {
314
- const list = await source();
315
- applyKeyMap(list);
316
- return { active: writeStations(list), agents: list.length };
317
- }
318
-
319
- export async function materializeFrom(source: StationSource): Promise<void> {
320
- const { active, agents: found } = await loadAndWrite(source);
321
- if (found === 0) throw new Error('no agents found — nothing to materialize');
322
- log.info(
323
- { stations: stationLabels(active), agents: found },
324
- 'materialized station accounts',
325
- );
326
- }
327
-
328
- export async function materializeFromDb(): Promise<void> {
329
- if (!databaseUrl())
330
- throw new Error('DATABASE_URL is not set — accounts load from Postgres');
331
- try {
332
- await materializeFrom(pgSource);
333
- } finally {
334
- await closeDb();
335
- }
336
- }
337
-
338
- export interface ReloadedStations {
339
- active: StationName[];
340
- removed: StationName[];
341
- }
342
-
343
- export async function reloadFrom(
344
- source: StationSource,
345
- ): Promise<ReloadedStations> {
346
- const { active } = await loadAndWrite(source);
347
- const removed = pruneStations(active);
348
- log.info(
349
- { stations: stationLabels(active), removed },
350
- 'reloaded station accounts',
351
- );
352
- return { active: [...active.keys()], removed };
353
- }
354
-
355
- export async function reloadAccountsFromDb(): Promise<ReloadedStations> {
356
- if (!databaseUrl())
357
- throw new Error('DATABASE_URL is not set — accounts load from Postgres');
358
- return reloadFrom(pgSource);
359
- }
360
-
361
- if (import.meta.main) {
362
- await materializeFromDb();
363
- process.exit(0);
364
- }
@@ -1,300 +0,0 @@
1
- import { ensureUser, normalizeEmail, userIdForEmail } from './users.js';
2
- import { and, asc, eq } from 'drizzle-orm';
3
- import { ApiError } from '../daemon/api-error.js';
4
- import { getDb } from './client.js';
5
- import { newId } from './ids.js';
6
- import { projectMembers, projects, users, type ProjectRole } from './schema.js';
7
-
8
- export class ProjectError extends ApiError {}
9
-
10
- export interface Project {
11
- id: string;
12
- name: string;
13
- isDefault: boolean;
14
- owner: boolean;
15
- role: ProjectRole;
16
- }
17
-
18
- export interface Member {
19
- id: string;
20
- email: string;
21
- role: ProjectRole;
22
- owner: boolean;
23
- }
24
-
25
- const NAME_MAX = 64;
26
- const CONTROL = /[\u0000-\u001f\u007f]/;
27
-
28
- const missing = (): ProjectError => new ProjectError('no such project', 404);
29
- const forbidden = (why: string): ProjectError => new ProjectError(why, 403);
30
-
31
- export function projectName(raw: unknown): string {
32
- const name = typeof raw === 'string' ? raw.trim() : '';
33
- if (name === '' || name.length > NAME_MAX)
34
- throw new ProjectError(
35
- `a project name is 1-${String(NAME_MAX)} characters`,
36
- 400,
37
- );
38
- if (CONTROL.test(name))
39
- throw new ProjectError('a project name cannot carry control characters', 400);
40
- return name;
41
- }
42
-
43
- export interface Access {
44
- userId: string;
45
- projectId: string;
46
- ownerId: string;
47
- isDefault: boolean;
48
- name: string;
49
- role: ProjectRole;
50
- }
51
-
52
- export async function memberAccessOrThrow(
53
- email: string,
54
- projectId: string,
55
- ): Promise<Access> {
56
- const userId = await userIdForEmail(email);
57
- if (userId === null) throw missing();
58
- const rows = await getDb()
59
- .select({
60
- id: projects.id,
61
- name: projects.name,
62
- ownerId: projects.ownerId,
63
- isDefault: projects.isDefault,
64
- role: projectMembers.role,
65
- })
66
- .from(projects)
67
- .innerJoin(projectMembers, eq(projectMembers.projectId, projects.id))
68
- .where(and(eq(projects.id, projectId), eq(projectMembers.userId, userId)));
69
- const row = rows[0];
70
- if (row === undefined) throw missing();
71
- return {
72
- userId,
73
- projectId: row.id,
74
- ownerId: row.ownerId,
75
- isDefault: row.isDefault,
76
- name: row.name,
77
- role: row.role,
78
- };
79
- }
80
-
81
- export async function projectIdOrThrow(
82
- email: string,
83
- projectId: string,
84
- ): Promise<string> {
85
- return (await memberAccessOrThrow(email, projectId)).projectId;
86
- }
87
-
88
- async function addMemberRow(
89
- projectId: string,
90
- userId: string,
91
- role: ProjectRole,
92
- ): Promise<void> {
93
- await getDb()
94
- .insert(projectMembers)
95
- .values({ id: newId(), projectId, userId, role })
96
- .onConflictDoNothing();
97
- }
98
-
99
- export async function ensureDefaultProject(userId: string): Promise<string> {
100
- const existing = await getDb()
101
- .select({ id: projects.id })
102
- .from(projects)
103
- .where(and(eq(projects.ownerId, userId), eq(projects.isDefault, true)));
104
- const found = existing[0];
105
- if (found !== undefined) return found.id;
106
- const id = newId();
107
- await getDb()
108
- .insert(projects)
109
- .values({ id, name: 'Personal', ownerId: userId, isDefault: true });
110
- await addMemberRow(id, userId, 'admin');
111
- return id;
112
- }
113
-
114
- export async function ensureUserWithProject(rawEmail: string): Promise<string> {
115
- const userId = await ensureUser(rawEmail);
116
- await ensureDefaultProject(userId);
117
- return userId;
118
- }
119
-
120
- export async function listProjectsForEmail(email: string): Promise<Project[]> {
121
- const userId = await userIdForEmail(email);
122
- if (userId === null) return [];
123
- const rows = await getDb()
124
- .select({
125
- id: projects.id,
126
- name: projects.name,
127
- isDefault: projects.isDefault,
128
- ownerId: projects.ownerId,
129
- role: projectMembers.role,
130
- })
131
- .from(projects)
132
- .innerJoin(projectMembers, eq(projectMembers.projectId, projects.id))
133
- .where(eq(projectMembers.userId, userId))
134
- .orderBy(asc(projects.id));
135
- return rows.map((r) => ({
136
- id: r.id,
137
- name: r.name,
138
- isDefault: r.isDefault,
139
- owner: r.ownerId === userId,
140
- role: r.role,
141
- }));
142
- }
143
-
144
- export async function createProjectForEmail(
145
- email: string,
146
- raw: unknown,
147
- ): Promise<Project> {
148
- const name = projectName(raw);
149
- const userId = await ensureUser(email);
150
- const id = newId();
151
- await getDb().insert(projects).values({ id, name, ownerId: userId });
152
- await addMemberRow(id, userId, 'admin');
153
- return { id, name, isDefault: false, owner: true, role: 'admin' };
154
- }
155
-
156
- export async function renameProjectForEmail(
157
- email: string,
158
- projectId: string,
159
- raw: unknown,
160
- ): Promise<Project> {
161
- const name = projectName(raw);
162
- const access = await memberAccessOrThrow(email, projectId);
163
- if (access.role !== 'admin')
164
- throw forbidden('only an admin can rename a project');
165
- await getDb()
166
- .update(projects)
167
- .set({ name })
168
- .where(eq(projects.id, access.projectId));
169
- return {
170
- id: access.projectId,
171
- name,
172
- isDefault: access.isDefault,
173
- owner: access.ownerId === access.userId,
174
- role: access.role,
175
- };
176
- }
177
-
178
- export async function deleteProjectForEmail(
179
- email: string,
180
- projectId: string,
181
- ): Promise<{ id: string; name: string }> {
182
- const access = await memberAccessOrThrow(email, projectId);
183
- if (access.ownerId !== access.userId)
184
- throw forbidden('only the owner can delete a project');
185
- if (access.isDefault)
186
- throw forbidden('your default project cannot be deleted');
187
- try {
188
- await getDb().delete(projects).where(eq(projects.id, access.projectId));
189
- } catch {
190
- throw new ProjectError(
191
- 'this project still holds agents, connectors or collections',
192
- 409,
193
- );
194
- }
195
- return { id: access.projectId, name: access.name };
196
- }
197
-
198
- export async function listMembersForEmail(
199
- email: string,
200
- projectId: string,
201
- ): Promise<Member[]> {
202
- const access = await memberAccessOrThrow(email, projectId);
203
- const rows = await getDb()
204
- .select({
205
- id: projectMembers.id,
206
- email: users.email,
207
- role: projectMembers.role,
208
- userId: projectMembers.userId,
209
- })
210
- .from(projectMembers)
211
- .innerJoin(users, eq(users.id, projectMembers.userId))
212
- .where(eq(projectMembers.projectId, access.projectId))
213
- .orderBy(asc(projectMembers.id));
214
- return rows.map((r) => ({
215
- id: r.id,
216
- email: r.email,
217
- role: r.role,
218
- owner: r.userId === access.ownerId,
219
- }));
220
- }
221
-
222
- function readRole(raw: unknown): ProjectRole {
223
- if (raw === 'admin' || raw === 'member') return raw;
224
- throw new ProjectError("a role is 'admin' or 'member'", 400);
225
- }
226
-
227
- async function adminAccessOrThrow(
228
- email: string,
229
- projectId: string,
230
- ): Promise<Access> {
231
- const access = await memberAccessOrThrow(email, projectId);
232
- if (access.role !== 'admin')
233
- throw forbidden('only an admin can manage members');
234
- return access;
235
- }
236
-
237
- export async function addMemberForEmail(
238
- email: string,
239
- projectId: string,
240
- raw: unknown,
241
- rawRole: unknown,
242
- ): Promise<Member[]> {
243
- const access = await adminAccessOrThrow(email, projectId);
244
- const role = readRole(rawRole);
245
- const invited = normalizeEmail(typeof raw === 'string' ? raw : '');
246
- if (invited === '') throw new ProjectError('an email is required', 400);
247
- const invitedId = await ensureUser(invited);
248
- await ensureDefaultProject(invitedId);
249
- await addMemberRow(access.projectId, invitedId, role);
250
- return listMembersForEmail(email, projectId);
251
- }
252
-
253
- async function memberRowOrThrow(
254
- projectId: string,
255
- memberId: string,
256
- ): Promise<{ userId: string }> {
257
- const rows = await getDb()
258
- .select({ userId: projectMembers.userId })
259
- .from(projectMembers)
260
- .where(
261
- and(
262
- eq(projectMembers.id, memberId),
263
- eq(projectMembers.projectId, projectId),
264
- ),
265
- );
266
- const row = rows[0];
267
- if (row === undefined) throw new ProjectError('no such member', 404);
268
- return row;
269
- }
270
-
271
- export async function setMemberRoleForEmail(
272
- email: string,
273
- projectId: string,
274
- memberId: string,
275
- rawRole: unknown,
276
- ): Promise<Member[]> {
277
- const access = await adminAccessOrThrow(email, projectId);
278
- const role = readRole(rawRole);
279
- const member = await memberRowOrThrow(access.projectId, memberId);
280
- if (member.userId === access.ownerId)
281
- throw forbidden('the owner is always an admin');
282
- await getDb()
283
- .update(projectMembers)
284
- .set({ role })
285
- .where(eq(projectMembers.id, memberId));
286
- return listMembersForEmail(email, projectId);
287
- }
288
-
289
- export async function removeMemberForEmail(
290
- email: string,
291
- projectId: string,
292
- memberId: string,
293
- ): Promise<Member[]> {
294
- const access = await adminAccessOrThrow(email, projectId);
295
- const member = await memberRowOrThrow(access.projectId, memberId);
296
- if (member.userId === access.ownerId)
297
- throw forbidden('the owner cannot be removed from their own project');
298
- await getDb().delete(projectMembers).where(eq(projectMembers.id, memberId));
299
- return listMembersForEmail(email, projectId);
300
- }
@@ -1,31 +0,0 @@
1
- import { ownedAgentOrThrow } from './agent-admin.js';
2
- import { ApiError } from '../daemon/api-error.js';
3
- import { mintRunCode } from '../daemon/run-pair.js';
4
- import { loadAllStationsFor, unmovableStations } from './materialize.js';
5
- import { releaseRuntime } from './runtimes.js';
6
-
7
- export async function mintRuntimeCodeForEmail(
8
- email: string,
9
- agentId: string,
10
- ): Promise<{ code: string; expiresAt: number }> {
11
- const { agent } = await ownedAgentOrThrow(email, agentId);
12
- const blocked = unmovableStations(await loadAllStationsFor(agent.id));
13
- if (blocked.length > 0)
14
- throw new ApiError(
15
- `'${agent.name}' holds ${blocked.join(', ')}, which only runs on metro ` +
16
- 'because a webhook url has to be publicly reachable. Its deliveries ' +
17
- 'would arrive at metro while this agent listens on your machine, so ' +
18
- 'they would be dropped. Detach it, or attach it to a second agent that ' +
19
- 'stays on metro, then authorize this one.',
20
- 409,
21
- );
22
- return mintRunCode({ email, agentId: agent.id });
23
- }
24
-
25
- export async function releaseRuntimeForEmail(
26
- email: string,
27
- agentId: string,
28
- ): Promise<void> {
29
- const { agent } = await ownedAgentOrThrow(email, agentId);
30
- await releaseRuntime(agent.id);
31
- }