@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
@@ -0,0 +1,178 @@
1
+ import { readFile, statfs } from 'node:fs/promises';
2
+ import { uptime } from 'node:os';
3
+ import { errMsg, log } from '@metro-labs/core/log';
4
+ import { isRecord } from '@metro-labs/core/is-record';
5
+ import { signV4 } from '@metro-labs/http/sigv4';
6
+
7
+ const IMDS = 'http://169.254.169.254/latest';
8
+ const EVERY_MS = 60_000;
9
+ const FIRST_MS = 15_000;
10
+ const IMDS_TIMEOUT_MS = 2_000;
11
+ const SEND_TIMEOUT_MS = 15_000;
12
+ const NAMESPACE = 'CWAgent';
13
+ const CONTENT_TYPE = 'application/x-www-form-urlencoded; charset=utf-8';
14
+ const BOOT_WINDOW_S = 300;
15
+ const SENT = 'sending memory and disk to CloudWatch every minute';
16
+
17
+ export interface Readings {
18
+ memory: number;
19
+ disk: number;
20
+ }
21
+
22
+ export interface Started {
23
+ name: 'server_booted' | 'metro_started';
24
+ at: number;
25
+ }
26
+
27
+ interface RoleKeys {
28
+ accessKeyId: string;
29
+ secretAccessKey: string;
30
+ sessionToken: string;
31
+ }
32
+
33
+ interface Instance {
34
+ instanceId: string;
35
+ region: string;
36
+ keys: RoleKeys | null;
37
+ }
38
+
39
+ export interface PublisherDeps {
40
+ fetch: (url: string, init: RequestInit) => Promise<Response>;
41
+ readings: () => Promise<Readings | null>;
42
+ }
43
+
44
+ export function memoryPercent(meminfo: string): number | null {
45
+ const kb = (name: string): number | null => {
46
+ const match = new RegExp(`^${name}:\\s+(\\d+) kB`, 'm').exec(meminfo);
47
+ return match === null ? null : Number(match[1]);
48
+ };
49
+ const total = kb('MemTotal');
50
+ const available = kb('MemAvailable');
51
+ if (total === null || available === null || total <= 0) return null;
52
+ return ((total - available) / total) * 100;
53
+ }
54
+
55
+ export function diskPercent(fs: { blocks: number; bfree: number; bavail: number }): number | null {
56
+ const used = fs.blocks - fs.bfree;
57
+ const room = used + fs.bavail;
58
+ return room > 0 ? (used / room) * 100 : null;
59
+ }
60
+
61
+ async function liveReadings(): Promise<Readings | null> {
62
+ const memory = memoryPercent(await readFile('/proc/meminfo', 'utf8'));
63
+ const disk = diskPercent(await statfs('/'));
64
+ return memory === null || disk === null ? null : { memory, disk };
65
+ }
66
+
67
+ const LIVE: PublisherDeps = { fetch: (url, init) => fetch(url, init), readings: liveReadings };
68
+
69
+ async function imdsGet(deps: PublisherDeps, token: string, path: string): Promise<string> {
70
+ const res = await deps.fetch(`${IMDS}/${path}`, { headers: { 'x-aws-ec2-metadata-token': token }, signal: AbortSignal.timeout(IMDS_TIMEOUT_MS) });
71
+ return res.ok ? (await res.text()).trim() : '';
72
+ }
73
+
74
+ async function imdsToken(deps: PublisherDeps): Promise<string> {
75
+ try {
76
+ const res = await deps.fetch(`${IMDS}/api/token`, {
77
+ method: 'PUT',
78
+ headers: { 'x-aws-ec2-metadata-token-ttl-seconds': '300' },
79
+ signal: AbortSignal.timeout(IMDS_TIMEOUT_MS),
80
+ });
81
+ return res.ok ? (await res.text()).trim() : '';
82
+ } catch {
83
+ return '';
84
+ }
85
+ }
86
+
87
+ function keysOf(raw: string): RoleKeys | null {
88
+ const parsed: unknown = JSON.parse(raw);
89
+ if (!isRecord(parsed)) return null;
90
+ const { AccessKeyId: accessKeyId, SecretAccessKey: secretAccessKey, Token: sessionToken } = parsed;
91
+ if (typeof accessKeyId !== 'string' || typeof secretAccessKey !== 'string' || typeof sessionToken !== 'string') return null;
92
+ return { accessKeyId, secretAccessKey, sessionToken };
93
+ }
94
+
95
+ export async function thisInstance(deps: PublisherDeps): Promise<Instance | null> {
96
+ const token = await imdsToken(deps);
97
+ if (token === '') return null;
98
+ const instanceId = await imdsGet(deps, token, 'meta-data/instance-id');
99
+ const region = await imdsGet(deps, token, 'meta-data/placement/region');
100
+ if (instanceId === '' || region === '') return null;
101
+ const role = (await imdsGet(deps, token, 'meta-data/iam/security-credentials/')).split('\n')[0] ?? '';
102
+ if (role === '') return { instanceId, region, keys: null };
103
+ return { instanceId, region, keys: keysOf(await imdsGet(deps, token, `meta-data/iam/security-credentials/${role}`)) };
104
+ }
105
+
106
+ export function startedOf(nowMs: number, processSeconds: number, bootSeconds: number): Started {
107
+ const at = (secondsAgo: number): number => Math.round(nowMs / 1000 - secondsAgo);
108
+ return bootSeconds < BOOT_WINDOW_S ? { name: 'server_booted', at: at(bootSeconds) } : { name: 'metro_started', at: at(processSeconds) };
109
+ }
110
+
111
+ export function readingParams(instanceId: string, readings: Readings, started: Started | null = null): Record<string, string> {
112
+ const datum = (at: number, name: string, value: number, dims: [string, string][], unit = 'Percent'): [string, string][] => [
113
+ [`MetricData.member.${String(at)}.MetricName`, name],
114
+ [`MetricData.member.${String(at)}.Unit`, unit],
115
+ [`MetricData.member.${String(at)}.Value`, value.toFixed(2)],
116
+ ...dims.flatMap(([key, v], i): [string, string][] => [
117
+ [`MetricData.member.${String(at)}.Dimensions.member.${String(i + 1)}.Name`, key],
118
+ [`MetricData.member.${String(at)}.Dimensions.member.${String(i + 1)}.Value`, v],
119
+ ]),
120
+ ];
121
+ return Object.fromEntries([
122
+ ['Action', 'PutMetricData'],
123
+ ['Version', '2010-08-01'],
124
+ ['Namespace', NAMESPACE],
125
+ ...datum(1, 'mem_used_percent', readings.memory, [['InstanceId', instanceId]]),
126
+ ...datum(2, 'disk_used_percent', readings.disk, [
127
+ ['InstanceId', instanceId],
128
+ ['path', '/'],
129
+ ]),
130
+ ...(started === null ? [] : datum(3, started.name, started.at, [['InstanceId', instanceId]], 'Seconds')),
131
+ ]);
132
+ }
133
+
134
+ async function send(deps: PublisherDeps, instance: Instance, keys: RoleKeys, readings: Readings, started: Started | null): Promise<void> {
135
+ const url = `https://monitoring.${instance.region}.amazonaws.com/`;
136
+ const body = new URLSearchParams(readingParams(instance.instanceId, readings, started)).toString();
137
+ const signed = await signV4({ method: 'POST', url, headers: { 'content-type': CONTENT_TYPE }, body, region: instance.region, service: 'monitoring', ...keys });
138
+ const res = await deps.fetch(url, { method: 'POST', headers: signed.headers, body, signal: AbortSignal.timeout(SEND_TIMEOUT_MS) });
139
+ if (res.ok) return;
140
+ const text = await res.text();
141
+ const code = /<Code>([^<]+)<\/Code>/.exec(text)?.[1] ?? `HTTP ${String(res.status)}`;
142
+ const message = /<Message>([^<]+)<\/Message>/.exec(text)?.[1];
143
+ throw new Error(`CloudWatch refused the readings: ${code}${message === undefined ? '' : ` (${message})`}`);
144
+ }
145
+
146
+ export async function publishOnce(deps: PublisherDeps = LIVE, started: Started | null = null): Promise<string> {
147
+ const instance = await thisInstance(deps);
148
+ if (instance === null) return 'off: this server is not an EC2 instance';
149
+ if (instance.keys === null) return `waiting: instance ${instance.instanceId} has no IAM role, so memory and disk are not sent`;
150
+ const readings = await deps.readings();
151
+ if (readings === null) return 'skipped: could not read memory or disk';
152
+ await send(deps, instance, instance.keys, readings, started);
153
+ return SENT;
154
+ }
155
+
156
+ export function startCloudWatchPublisher(): void {
157
+ if (process.platform !== 'linux') return;
158
+ let started: Started | null = startedOf(Date.now(), process.uptime(), uptime());
159
+ let last = '';
160
+ const note = (status: string, warn: boolean): void => {
161
+ if (status === last) return;
162
+ last = status;
163
+ if (warn) log.warn({ status }, 'cloudwatch: could not send memory and disk');
164
+ else log.info({ status }, 'cloudwatch');
165
+ };
166
+ const run = (): void => {
167
+ publishOnce(LIVE, started)
168
+ .then((status) => {
169
+ if (status === SENT) started = null;
170
+ note(status, false);
171
+ })
172
+ .catch((err: unknown) => {
173
+ note(errMsg(err), true);
174
+ });
175
+ };
176
+ setTimeout(run, FIRST_MS).unref?.();
177
+ setInterval(run, EVERY_MS).unref?.();
178
+ }
@@ -0,0 +1,39 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { ApiError } from '@metro-labs/http/api-error';
3
+ import { sessionRoute } from '@metro-labs/http/api-http';
4
+ import { log } from '@metro-labs/core/log';
5
+
6
+ const STOP = '/api/stop';
7
+ const RESTART = '/api/restart';
8
+ const EXIT_DELAY_MS = 500;
9
+
10
+ export interface ControlApiDeps {
11
+ restart: () => void;
12
+ stop: () => void;
13
+ served?: () => boolean;
14
+ }
15
+
16
+ interface Action {
17
+ run: () => void;
18
+ body: Record<string, boolean>;
19
+ }
20
+
21
+ const servedByCli = (): boolean => (process.env.METRO_CLI_BIN?.trim() ?? '') !== '';
22
+
23
+ function actionFor(path: string, deps: ControlApiDeps): Action {
24
+ return path === STOP ? { run: deps.stop, body: { stopping: true } } : { run: deps.restart, body: { restarting: true } };
25
+ }
26
+
27
+ export function handleControlRequest(req: IncomingMessage, res: ServerResponse, deps: ControlApiDeps): boolean {
28
+ return sessionRoute(req, res, { methods: { [STOP]: ['POST'], [RESTART]: ['POST'] }, admin: true, label: 'control-api' }, async (session, path) => {
29
+ const action = actionFor(path, deps);
30
+ if (!(deps.served ?? servedByCli)())
31
+ throw new ApiError(
32
+ 'this daemon was not started by metro serve, so nothing on the machine would bring it back: use the shell instead',
33
+ 400,
34
+ );
35
+ log.info({ path, subject: session.subject }, 'control-api: requested from the page');
36
+ setTimeout(action.run, EXIT_DELAY_MS).unref();
37
+ return Promise.resolve(action.body);
38
+ });
39
+ }
@@ -0,0 +1,58 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { hostname, homedir } from 'node:os';
3
+ import { statfs } from 'node:fs/promises';
4
+ import { errMsg, log } from '@metro-labs/core/log';
5
+ import { sessionRoute } from '@metro-labs/http/api-http';
6
+ import { publicBaseUrl, webhookPort } from '../files/attach-serve.js';
7
+ import { claudeDir } from '../claude/files.js';
8
+ import { METRO_VERSION } from '@metro-labs/core/version';
9
+ import { agentsDir } from '../agents/files.js';
10
+ import { localOwner } from '../agents/file-admin.js';
11
+
12
+ const PATH = '/api/server';
13
+
14
+ export interface MachineApiDeps {
15
+ startedAt?: string;
16
+ }
17
+
18
+ const bootedAt = new Date(Date.now() - process.uptime() * 1000).toISOString();
19
+
20
+ interface Disk {
21
+ path: string;
22
+ totalBytes: number;
23
+ freeBytes: number;
24
+ }
25
+
26
+ async function diskInfo(path = homedir()): Promise<Disk | null> {
27
+ try {
28
+ const s = await statfs(path);
29
+ return { path, totalBytes: s.bsize * s.blocks, freeBytes: s.bsize * s.bavail };
30
+ } catch (err) {
31
+ log.warn({ err: errMsg(err), path }, 'machine: could not read the disk');
32
+ return null;
33
+ }
34
+ }
35
+
36
+ export async function machineInfo(startedAt = bootedAt): Promise<Record<string, unknown>> {
37
+ const store = process.env.METRO_RUNTIME_STORE?.trim() ?? '';
38
+ return {
39
+ disk: await diskInfo(),
40
+ version: METRO_VERSION,
41
+ owner: localOwner(),
42
+ hostname: hostname(),
43
+ platform: process.platform,
44
+ arch: process.arch,
45
+ port: webhookPort(),
46
+ publicUrl: publicBaseUrl(),
47
+ uptimeSeconds: Math.round(process.uptime()),
48
+ startedAt,
49
+ bun: process.versions.bun ?? null,
50
+ agentsDir: agentsDir(),
51
+ claudeDir: claudeDir(),
52
+ runtimeStore: store === '' ? null : store,
53
+ };
54
+ }
55
+
56
+ export function handleMachineRequest(req: IncomingMessage, res: ServerResponse, deps: MachineApiDeps): boolean {
57
+ return sessionRoute(req, res, { methods: { [PATH]: ['GET'] }, admin: false, label: 'machine-api' }, () => machineInfo(deps.startedAt));
58
+ }
@@ -0,0 +1,26 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { ApiError } from '@metro-labs/http/api-error';
3
+ import { readJsonBody, sessionRoute, type ApiSession } from '@metro-labs/http/api-http';
4
+ import { isOrganizationId } from '@metro-labs/http/workos-token';
5
+ import { isRecord } from '@metro-labs/core/is-record';
6
+ import { log } from '@metro-labs/core/log';
7
+
8
+ const PATH = '/api/owner';
9
+
10
+ export interface OwnerApiDeps {
11
+ setOwner: (owner: string) => string;
12
+ }
13
+
14
+ async function move(req: IncomingMessage, session: ApiSession, deps: OwnerApiDeps): Promise<{ owner: string }> {
15
+ const body = await readJsonBody(req);
16
+ const owner = isRecord(body) && typeof body.owner === 'string' ? body.owner.trim() : '';
17
+ if (!isOrganizationId(owner)) throw new ApiError('owner must be an organization id', 400);
18
+ if (owner === session.subject) throw new ApiError('this machine already belongs to that organization', 409);
19
+ const saved = deps.setOwner(owner);
20
+ log.info({ from: session.subject, to: saved }, 'owner: this machine moved to another organization');
21
+ return { owner: saved };
22
+ }
23
+
24
+ export function handleOwnerRequest(req: IncomingMessage, res: ServerResponse, deps: OwnerApiDeps): boolean {
25
+ return sessionRoute(req, res, { methods: { [PATH]: ['POST'] }, admin: true, label: 'owner-api' }, (session) => move(req, session, deps));
26
+ }
@@ -0,0 +1,90 @@
1
+ import { execFile } from 'node:child_process';
2
+ import type { IncomingMessage, ServerResponse } from 'node:http';
3
+ import { log } from '@metro-labs/core/log';
4
+ import { ApiError } from '@metro-labs/http/api-error';
5
+ import { sessionRoute } from '@metro-labs/http/api-http';
6
+ import { isRecord } from '@metro-labs/core/is-record';
7
+ import { METRO_VERSION } from '@metro-labs/core/version';
8
+
9
+ const PATH = '/api/update';
10
+ const CHECK_TTL_MS = 10 * 60_000;
11
+ const CHECK_TIMEOUT_MS = 30_000;
12
+ const UPDATE_TIMEOUT_MS = 5 * 60_000;
13
+ const RESTART_DELAY_MS = 500;
14
+ const OUTPUT_TAIL = 800;
15
+
16
+ interface UpdateCheck {
17
+ current: string;
18
+ latest: string;
19
+ newer: boolean;
20
+ }
21
+
22
+ interface UpdateResult {
23
+ updated: boolean;
24
+ version: string;
25
+ restarting: boolean;
26
+ }
27
+
28
+ export interface UpdateApiDeps {
29
+ restart: () => void;
30
+ cliBin?: () => string;
31
+ }
32
+
33
+ const cliBinFromEnv = (): string => process.env.METRO_CLI_BIN?.trim() ?? '';
34
+
35
+ function runCli(bin: string, args: string[], timeout: number): Promise<{ stdout: string; stderr: string }> {
36
+ return new Promise((resolve, reject) => {
37
+ execFile(process.execPath, [bin, ...args], { timeout, maxBuffer: 4 * 1024 * 1024 }, (err, stdout, stderr) => {
38
+ if (err === null) resolve({ stdout, stderr });
39
+ else reject(new ApiError(`metro update failed: ${(stderr || err.message).trim().slice(-OUTPUT_TAIL)}`, 502));
40
+ });
41
+ });
42
+ }
43
+
44
+ let cached: { at: number; check: UpdateCheck } | null = null;
45
+
46
+ function parseCheck(raw: string): UpdateCheck {
47
+ let body: unknown;
48
+ try {
49
+ body = JSON.parse(raw.trim().split('\n').at(-1) ?? '');
50
+ } catch {
51
+ throw new ApiError('metro update --check returned no report', 502);
52
+ }
53
+ if (!isRecord(body) || typeof body.current !== 'string' || typeof body.latest !== 'string')
54
+ throw new ApiError('metro update --check returned an unexpected report', 502);
55
+ return { current: body.current, latest: body.latest, newer: body.newer === true };
56
+ }
57
+
58
+ async function check(bin: string, now = Date.now()): Promise<UpdateCheck> {
59
+ if (cached !== null && now - cached.at < CHECK_TTL_MS) return cached.check;
60
+ const out = await runCli(bin, ['update', '--check'], CHECK_TIMEOUT_MS);
61
+ cached = { at: now, check: parseCheck(out.stdout) };
62
+ return cached.check;
63
+ }
64
+
65
+ async function apply(bin: string, deps: UpdateApiDeps): Promise<UpdateResult> {
66
+ const before = await check(bin);
67
+ if (!before.newer) return { updated: false, version: before.current, restarting: false };
68
+ const out = await runCli(bin, ['update'], UPDATE_TIMEOUT_MS);
69
+ cached = null;
70
+ log.info({ from: before.current, to: before.latest, output: out.stderr.trim().slice(-OUTPUT_TAIL) }, 'update-api: metro updated, restarting');
71
+ setTimeout(() => {
72
+ deps.restart();
73
+ }, RESTART_DELAY_MS).unref();
74
+ return { updated: true, version: before.latest, restarting: true };
75
+ }
76
+
77
+ function binOrThrow(deps: UpdateApiDeps): string {
78
+ const bin = (deps.cliBin ?? cliBinFromEnv)();
79
+ if (bin === '')
80
+ throw new ApiError('this daemon was not started by metro serve, so it cannot update itself: run metro update on the machine', 400);
81
+ return bin;
82
+ }
83
+
84
+ export function handleUpdateRequest(req: IncomingMessage, res: ServerResponse, deps: UpdateApiDeps): boolean {
85
+ return sessionRoute(req, res, { methods: { [PATH]: ['GET', 'POST'] }, admin: ['POST'], label: 'update-api' }, async () => {
86
+ const bin = binOrThrow(deps);
87
+ if (req.method === 'GET') return { ...(await check(bin)), running: METRO_VERSION };
88
+ return apply(bin, deps);
89
+ });
90
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ import './boot/boot.js';
@@ -0,0 +1,102 @@
1
+ import { SignInError, parseMailbox } from '@metro-labs/core/stations/oauth';
2
+ import { StationAttachError } from './attach.js';
3
+ import type { AttachOutcome, DriverHooks, StartedAttach, StepInput } from './attach-driver.js';
4
+
5
+ const OUTLOOK_PROMPT =
6
+ 'Sign in with Microsoft in a new tab, with the mailbox this agent should read. This page updates on its own once you are done.';
7
+ const GMAIL_PROMPT =
8
+ 'Sign in with Google in a new tab, with the mailbox this agent should read. This page updates on its own once you are done.';
9
+ const DEVICE_PROMPT =
10
+ 'Open the Microsoft sign-in page, type this code, and sign in with the mailbox this agent should read.';
11
+ const OTHER_ATTEMPT = 'This sign-in link belongs to another attempt. Start again from the Channels page.';
12
+ const BROWSER_TTL_MS = 15 * 60_000;
13
+
14
+ interface BrowserLogin {
15
+ state: string;
16
+ authorizeUrl: string;
17
+ finish: (code: string, state: string) => Promise<AttachOutcome>;
18
+ }
19
+
20
+ interface BrowserAttach {
21
+ provider: string;
22
+ prompt: string;
23
+ failure: (body: Record<string, unknown>) => string;
24
+ device?: () => Promise<void>;
25
+ cancel?: () => Promise<void>;
26
+ }
27
+
28
+ const text = (v: unknown): string => (typeof v === 'string' ? v.trim() : '');
29
+
30
+ const said = (err: unknown, fallback: string): string => (err instanceof SignInError && err.message !== '' ? err.message : fallback);
31
+
32
+ function refused(err: unknown, provider: string): StationAttachError {
33
+ return new StationAttachError(said(err, `${provider} refused to start the sign-in`), 400);
34
+ }
35
+
36
+ function browserAttach(login: BrowserLogin, hooks: DriverHooks, how: BrowserAttach): StartedAttach {
37
+ const finish = async (input: StepInput): Promise<void> => {
38
+ const state = text(input.state);
39
+ if (state !== login.state) throw new StationAttachError(OTHER_ATTEMPT, 400);
40
+ const error = text(input.error);
41
+ if (error !== '') {
42
+ hooks.fail(how.failure({ error, error_description: text(input.errorDescription) }));
43
+ return;
44
+ }
45
+ const code = text(input.code);
46
+ if (code === '') throw new StationAttachError(`${how.provider} did not send a sign-in code back`, 400);
47
+ try {
48
+ hooks.done(await login.finish(code, state));
49
+ } catch (err) {
50
+ hooks.fail(said(err, `Metro could not finish the ${how.provider} sign-in.`));
51
+ }
52
+ };
53
+ const device = how.device;
54
+ return {
55
+ prompt: { step: 'browser', prompt: how.prompt, authorizeUrl: login.authorizeUrl },
56
+ expiresAt: Date.now() + BROWSER_TTL_MS,
57
+ driver: {
58
+ cancel: () => how.cancel?.() ?? Promise.resolve(),
59
+ submit: (input) => (input.mode === 'device' && device !== undefined ? device() : finish(input)),
60
+ },
61
+ };
62
+ }
63
+
64
+ export async function startOutlook(input: Record<string, unknown>, hooks: DriverHooks): Promise<StartedAttach> {
65
+ const { OutlookBrowserLogin, OutlookLogin: DeviceLogin, failureOf } = await import('@metro-labs/outlook/login');
66
+ const { browser, mailbox } = (() => {
67
+ try {
68
+ const wanted = parseMailbox(input.mailbox);
69
+ return { browser: new OutlookBrowserLogin({ mailbox: wanted }), mailbox: wanted };
70
+ } catch (err) {
71
+ throw refused(err, 'Microsoft');
72
+ }
73
+ })();
74
+ let device: InstanceType<typeof DeviceLogin> | null = null;
75
+ const toDevice = async (): Promise<void> => {
76
+ if (device !== null) return;
77
+ const login = new DeviceLogin({ onDone: hooks.done, onFailed: hooks.fail }, { mailbox });
78
+ const code = await login.start().catch((err: unknown) => {
79
+ throw refused(err, 'Microsoft');
80
+ });
81
+ device = login;
82
+ hooks.prompt({ step: 'device', prompt: DEVICE_PROMPT, userCode: code.userCode, verificationUri: code.verificationUri });
83
+ };
84
+ return browserAttach(browser, hooks, {
85
+ provider: 'Microsoft',
86
+ prompt: OUTLOOK_PROMPT,
87
+ failure: (body) => failureOf(body),
88
+ device: toDevice,
89
+ cancel: () => device?.cancel() ?? Promise.resolve(),
90
+ });
91
+ }
92
+
93
+ export async function startGmail(input: Record<string, unknown>, hooks: DriverHooks): Promise<StartedAttach> {
94
+ const { GmailBrowserLogin, failureOf } = await import('@metro-labs/gmail/login');
95
+ let login;
96
+ try {
97
+ login = new GmailBrowserLogin({ clientId: input.clientId, clientSecret: input.clientSecret, mailbox: input.mailbox });
98
+ } catch (err) {
99
+ throw refused(err, 'Google');
100
+ }
101
+ return browserAttach(login, hooks, { provider: 'Google', prompt: GMAIL_PROMPT, failure: failureOf });
102
+ }
@@ -0,0 +1,42 @@
1
+ export type AttachStep = 'code' | 'password' | 'scan' | 'pair' | 'device' | 'browser';
2
+
3
+ export interface AttachPrompt {
4
+ step: AttachStep;
5
+ prompt: string;
6
+ qr?: string;
7
+ pairingCode?: string;
8
+ userCode?: string;
9
+ verificationUri?: string;
10
+ authorizeUrl?: string;
11
+ }
12
+
13
+ export interface AttachOutcome {
14
+ config: Record<string, unknown>;
15
+ identity: Record<string, string>;
16
+ }
17
+
18
+ export interface DriverHooks {
19
+ prompt: (p: AttachPrompt) => void;
20
+ done: (o: AttachOutcome) => void;
21
+ fail: (message: string) => void;
22
+ }
23
+
24
+ export interface StepInput {
25
+ code?: unknown;
26
+ password?: unknown;
27
+ state?: unknown;
28
+ mode?: unknown;
29
+ error?: unknown;
30
+ errorDescription?: unknown;
31
+ }
32
+
33
+ export interface AttachDriver {
34
+ submit: (input: StepInput) => Promise<void>;
35
+ cancel: () => Promise<void>;
36
+ }
37
+
38
+ export interface StartedAttach {
39
+ driver: AttachDriver;
40
+ prompt: AttachPrompt;
41
+ expiresAt?: number;
42
+ }
@@ -1,4 +1,5 @@
1
- import { mkdtemp, rm, writeFile } from 'node:fs/promises';
1
+ import { mkdtemp, open, rm, writeFile } from 'node:fs/promises';
2
+ import { assertAttachmentSize } from '@metro-labs/core/stations/attachments';
2
3
  import { tmpdir } from 'node:os';
3
4
  import { join } from 'node:path';
4
5
 
@@ -98,3 +99,30 @@ export async function writeInlineTemp(
98
99
 
99
100
  export const removeInlineTemp = (dir: string): Promise<void> =>
100
101
  rm(dir, { recursive: true, force: true });
102
+
103
+ export async function streamToTemp(
104
+ body: ReadableStream<Uint8Array>,
105
+ name: string | undefined,
106
+ ): Promise<InlineTemp & { bytes: number }> {
107
+ const dir = await mkdtemp(join(tmpdir(), INLINE_TEMP_PREFIX));
108
+ const path = join(dir, safeFileName(name));
109
+ const handle = await open(path, 'wx', 0o600);
110
+ const reader = body.getReader();
111
+ let bytes = 0;
112
+ try {
113
+ for (;;) {
114
+ const { done, value } = await reader.read();
115
+ if (done) break;
116
+ bytes += value.length;
117
+ assertAttachmentSize(bytes);
118
+ await handle.write(value);
119
+ }
120
+ } catch (err) {
121
+ await reader.cancel().catch(() => undefined);
122
+ await handle.close();
123
+ await removeInlineTemp(dir);
124
+ throw err;
125
+ }
126
+ await handle.close();
127
+ return { dir, path, bytes };
128
+ }
@@ -1,39 +1,11 @@
1
1
  import { StationAttachError } from './attach.js';
2
+ import type { DriverHooks, StartedAttach } from './attach-driver.js';
3
+ import { startGmail, startOutlook } from './attach-browser.js';
2
4
 
3
- export const INTERACTIVE_STATIONS = ['telegram', 'whatsapp'] as const;
5
+ export const INTERACTIVE_STATIONS = ['telegram', 'whatsapp', 'outlook', 'gmail'] as const;
4
6
 
5
7
  export type InteractiveStation = (typeof INTERACTIVE_STATIONS)[number];
6
8
 
7
- export type AttachStep = 'code' | 'password' | 'scan' | 'pair';
8
-
9
- export interface AttachPrompt {
10
- step: AttachStep;
11
- prompt: string;
12
- qr?: string;
13
- pairingCode?: string;
14
- }
15
-
16
- export interface AttachOutcome {
17
- config: Record<string, unknown>;
18
- identity: Record<string, string>;
19
- }
20
-
21
- export interface DriverHooks {
22
- prompt: (p: AttachPrompt) => void;
23
- done: (o: AttachOutcome) => void;
24
- fail: (message: string) => void;
25
- }
26
-
27
- export interface AttachDriver {
28
- submit: (input: { code?: unknown; password?: unknown }) => Promise<void>;
29
- cancel: () => Promise<void>;
30
- }
31
-
32
- export interface StartedAttach {
33
- driver: AttachDriver;
34
- prompt: AttachPrompt;
35
- }
36
-
37
9
  const CODE_PROMPT =
38
10
  'Telegram sent a login code to that number. Enter it here.';
39
11
  const PASSWORD_PROMPT =
@@ -155,6 +127,8 @@ export async function startInteractiveAttach(
155
127
  input: Record<string, unknown>,
156
128
  hooks: DriverHooks,
157
129
  ): Promise<StartedAttach> {
130
+ if (station === 'outlook') return startOutlook(input, hooks);
131
+ if (station === 'gmail') return startGmail(input, hooks);
158
132
  return station === 'telegram'
159
133
  ? startTelegramUser(input, hooks)
160
134
  : startWhatsapp(input, hooks);