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

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 +284 -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,333 +0,0 @@
1
- import { errMsg, log } from './log.js';
2
- import {
3
- ConnectorNotMcp,
4
- ConnectorUnauthorized,
5
- refused,
6
- safeIconSrc,
7
- } from './connector-url.js';
8
- import { toToolList, type ToolInfo } from './connector-tools.js';
9
-
10
- export {
11
- ConnectorUnauthorized,
12
- ConnectorVerifyError,
13
- connectorUrlText,
14
- parseConnectorUrl,
15
- } from './connector-url.js';
16
-
17
- export interface OAuthTokens {
18
- accessToken: string;
19
- refreshToken?: string;
20
- expiresAt?: number;
21
- }
22
-
23
- export interface OAuthAuth extends OAuthTokens {
24
- kind: 'oauth';
25
- issuer: string;
26
- tokenEndpoint: string;
27
- clientId: string;
28
- clientSecret?: string;
29
- }
30
-
31
- export type ConnectorAuth =
32
- | { kind: 'none' }
33
- | { kind: 'header'; name: string; value: string }
34
- | OAuthAuth;
35
-
36
- export interface VerifiedServer {
37
- server: string;
38
- version: string;
39
- protocol: string;
40
- icon: string;
41
- tools: number;
42
- catalog: ToolInfo[];
43
- }
44
-
45
- export interface VerifiedRecord extends VerifiedServer {
46
- at: string;
47
- }
48
-
49
- const PROTOCOL_VERSIONS = ['2025-11-25', '2025-06-18'] as const;
50
- const MAX_TOOL_PAGES = 10;
51
-
52
- function notMcp(url: URL): ConnectorNotMcp {
53
- return new ConnectorNotMcp(
54
- `${url.hostname} answered, but it does not speak MCP.`,
55
- 400,
56
- );
57
- }
58
- const PROBE_TIMEOUT_MS = 10_000;
59
- const ACCEPT = 'application/json, text/event-stream';
60
-
61
- function isRecord(value: unknown): value is Record<string, unknown> {
62
- return typeof value === 'object' && value !== null && !Array.isArray(value);
63
- }
64
-
65
- async function discard(res: Response): Promise<void> {
66
- await res.body?.cancel().catch((err: unknown) => {
67
- log.debug(
68
- { err: errMsg(err) },
69
- 'connector-verify: could not discard a response body',
70
- );
71
- });
72
- }
73
-
74
- function authHeaders(auth: ConnectorAuth): Record<string, string> {
75
- if (auth.kind === 'header') return { [auth.name]: auth.value };
76
- if (auth.kind === 'oauth')
77
- return { authorization: `Bearer ${auth.accessToken}` };
78
- return {};
79
- }
80
-
81
- async function frame(
82
- url: URL,
83
- auth: ConnectorAuth,
84
- extra: Record<string, string>,
85
- body: unknown,
86
- signal: AbortSignal,
87
- ): Promise<Response> {
88
- let res: Response;
89
- try {
90
- res = await fetch(url, {
91
- method: 'POST',
92
- redirect: 'manual',
93
- signal,
94
- headers: {
95
- 'content-type': 'application/json',
96
- accept: ACCEPT,
97
- ...authHeaders(auth),
98
- ...extra,
99
- },
100
- body: JSON.stringify(body),
101
- });
102
- } catch {
103
- throw refused(`Metro could not reach ${url.hostname}.`);
104
- }
105
- if (res.status >= 300 && res.status < 400) {
106
- await discard(res);
107
- throw refused('that url redirects — use the url it redirects to');
108
- }
109
- return res;
110
- }
111
-
112
- function sseData(body: string): string {
113
- for (const line of body.replace(/\r\n/g, '\n').split('\n'))
114
- if (line.startsWith('data:')) return line.slice(5).trim();
115
- return '';
116
- }
117
-
118
- async function payloadOf(res: Response): Promise<string> {
119
- const contentType = res.headers.get('content-type') ?? '';
120
- const text = await res.text().catch(() => '');
121
- return contentType.includes('text/event-stream') ? sseData(text) : text;
122
- }
123
-
124
- async function resultOrNull(
125
- res: Response,
126
- ): Promise<Record<string, unknown> | null> {
127
- const payload = await payloadOf(res);
128
- let parsed: unknown;
129
- try {
130
- parsed = JSON.parse(payload);
131
- } catch {
132
- return null;
133
- }
134
- if (!isRecord(parsed) || !isRecord(parsed.result)) return null;
135
- return parsed.result;
136
- }
137
-
138
- function initializeBody(version: string): unknown {
139
- return {
140
- jsonrpc: '2.0',
141
- id: 1,
142
- method: 'initialize',
143
- params: {
144
- protocolVersion: version,
145
- capabilities: {},
146
- clientInfo: { name: 'metro', version: '0.1.0' },
147
- },
148
- };
149
- }
150
-
151
- function iconOf(info: Record<string, unknown>): string {
152
- const icons = info.icons;
153
- if (!Array.isArray(icons)) return '';
154
- for (const entry of icons) {
155
- if (!isRecord(entry)) continue;
156
- const src = safeIconSrc(entry.src);
157
- if (src !== '') return src;
158
- }
159
- return '';
160
- }
161
-
162
- function serverFrom(url: URL, result: Record<string, unknown>): VerifiedServer {
163
- const protocol = result.protocolVersion;
164
- if (typeof protocol !== 'string') throw notMcp(url);
165
- const info = isRecord(result.serverInfo) ? result.serverInfo : {};
166
- const title = typeof info.title === 'string' ? info.title : '';
167
- return {
168
- server:
169
- title !== ''
170
- ? title
171
- : typeof info.name === 'string'
172
- ? info.name
173
- : url.hostname,
174
- version: typeof info.version === 'string' ? info.version : '',
175
- protocol,
176
- icon: iconOf(info),
177
- tools: 0,
178
- catalog: [],
179
- };
180
- }
181
-
182
- async function initialize(
183
- url: URL,
184
- auth: ConnectorAuth,
185
- signal: AbortSignal,
186
- version: string,
187
- ): Promise<{ session: string | null; server: VerifiedServer }> {
188
- const res = await frame(url, auth, {}, initializeBody(version), signal);
189
- if (res.status === 401 || res.status === 403) {
190
- await discard(res);
191
- throw new ConnectorUnauthorized(
192
- auth.kind === 'none'
193
- ? `${url.hostname} requires authorization.`
194
- : `${url.hostname} rejected that credential.`,
195
- 400,
196
- );
197
- }
198
- if (res.status === 404 || res.status === 405) {
199
- await discard(res);
200
- throw refused(
201
- `${url.hostname} did not accept an MCP initialize over HTTP POST. ` +
202
- 'If it is a legacy SSE server, Metro cannot verify it yet.',
203
- );
204
- }
205
- if (!res.ok) {
206
- await discard(res);
207
- throw notMcp(url);
208
- }
209
- const result = await resultOrNull(res);
210
- if (result === null) throw notMcp(url);
211
- return {
212
- session: res.headers.get('mcp-session-id'),
213
- server: serverFrom(url, result),
214
- };
215
- }
216
-
217
- function sessionHeaders(
218
- session: string | null,
219
- version: string,
220
- ): Record<string, string> {
221
- const headers: Record<string, string> = {
222
- 'mcp-protocol-version': version,
223
- };
224
- if (session !== null && session !== '') headers['mcp-session-id'] = session;
225
- return headers;
226
- }
227
-
228
- async function announce(
229
- url: URL,
230
- auth: ConnectorAuth,
231
- headers: Record<string, string>,
232
- signal: AbortSignal,
233
- ): Promise<void> {
234
- const res = await frame(
235
- url,
236
- auth,
237
- headers,
238
- { jsonrpc: '2.0', method: 'notifications/initialized' },
239
- signal,
240
- );
241
- await discard(res);
242
- }
243
-
244
- async function toolPage(
245
- url: URL,
246
- auth: ConnectorAuth,
247
- headers: Record<string, string>,
248
- signal: AbortSignal,
249
- cursor: string,
250
- ): Promise<Record<string, unknown> | null> {
251
- const params = cursor === '' ? {} : { cursor };
252
- const res = await frame(
253
- url,
254
- auth,
255
- headers,
256
- { jsonrpc: '2.0', id: 2, method: 'tools/list', params },
257
- signal,
258
- );
259
- if (!res.ok) {
260
- await discard(res);
261
- return null;
262
- }
263
- return resultOrNull(res);
264
- }
265
-
266
- async function listTools(
267
- url: URL,
268
- auth: ConnectorAuth,
269
- headers: Record<string, string>,
270
- signal: AbortSignal,
271
- ): Promise<ToolInfo[]> {
272
- const tools: ToolInfo[] = [];
273
- let cursor = '';
274
- for (let page = 0; page < MAX_TOOL_PAGES; page += 1) {
275
- const result = await toolPage(url, auth, headers, signal, cursor);
276
- if (result === null) break;
277
- tools.push(...toToolList(result.tools));
278
- const next = result.nextCursor;
279
- if (typeof next !== 'string' || next === '' || next === cursor) break;
280
- cursor = next;
281
- }
282
- return tools;
283
- }
284
-
285
- async function terminate(
286
- url: URL,
287
- auth: ConnectorAuth,
288
- headers: Record<string, string>,
289
- signal: AbortSignal,
290
- ): Promise<void> {
291
- const res = await fetch(url, {
292
- method: 'DELETE',
293
- redirect: 'manual',
294
- signal,
295
- headers: { ...authHeaders(auth), ...headers },
296
- });
297
- await discard(res);
298
- }
299
-
300
- async function probeWith(
301
- url: URL,
302
- auth: ConnectorAuth,
303
- version: string,
304
- ): Promise<VerifiedServer> {
305
- const signal = AbortSignal.timeout(PROBE_TIMEOUT_MS);
306
- const { session, server } = await initialize(url, auth, signal, version);
307
- const headers = sessionHeaders(session, server.protocol);
308
- await announce(url, auth, headers, signal);
309
- const catalog = await listTools(url, auth, headers, signal);
310
- await terminate(url, auth, headers, signal).catch((err: unknown) => {
311
- log.debug(
312
- { host: url.hostname, err: errMsg(err) },
313
- 'connector-verify: the remote declined to end the session',
314
- );
315
- });
316
- return { ...server, tools: catalog.length, catalog };
317
- }
318
-
319
- export async function verifyRemoteMcp(
320
- url: URL,
321
- auth: ConnectorAuth,
322
- ): Promise<VerifiedServer> {
323
- let last: unknown;
324
- for (const version of PROTOCOL_VERSIONS) {
325
- try {
326
- return await probeWith(url, auth, version);
327
- } catch (err) {
328
- if (!(err instanceof ConnectorNotMcp)) throw err;
329
- last = err;
330
- }
331
- }
332
- throw last;
333
- }
@@ -1,164 +0,0 @@
1
- import {
2
- createPublicKey,
3
- verify as cryptoVerify,
4
- type JsonWebKey as CryptoJsonWebKey,
5
- } from 'node:crypto';
6
-
7
- export class GoogleAuthError extends Error {}
8
-
9
- interface GoogleClaims {
10
- email: string;
11
- emailVerified: boolean;
12
- aud: string;
13
- iss: string;
14
- exp: number;
15
- }
16
-
17
- interface Jwk {
18
- kid: string;
19
- kty: string;
20
- alg?: string;
21
- n: string;
22
- e: string;
23
- }
24
-
25
- interface VerifyOptions {
26
- clientId: string;
27
- now?: number;
28
- fetchCerts?: () => Promise<Jwk[]>;
29
- clockToleranceSec?: number;
30
- expectedNonce?: string;
31
- }
32
-
33
- const DEFAULT_CERTS_URL = 'https://www.googleapis.com/oauth2/v3/certs';
34
- const certsUrl = (): string => {
35
- const v = process.env.GOOGLE_OAUTH_JWKS_URL?.trim();
36
- return v !== undefined && v !== '' ? v : DEFAULT_CERTS_URL;
37
- };
38
- const GOOGLE_ISSUERS = new Set([
39
- 'https://accounts.google.com',
40
- 'accounts.google.com',
41
- ]);
42
-
43
- const decodeSegment = (seg: string): Buffer =>
44
- Buffer.from(seg.replace(/-/g, '+').replace(/_/g, '/'), 'base64');
45
-
46
- const decodeJson = (seg: string): unknown => {
47
- try {
48
- return JSON.parse(decodeSegment(seg).toString('utf8'));
49
- } catch {
50
- throw new GoogleAuthError('malformed token segment');
51
- }
52
- };
53
-
54
- let certCache: { keys: Jwk[]; expiresAt: number } | null = null;
55
-
56
- async function fetchGoogleCerts(): Promise<Jwk[]> {
57
- const res = await fetch(certsUrl());
58
- if (!res.ok)
59
- throw new GoogleAuthError(`google certs fetch failed: ${res.status}`);
60
- const body = (await res.json()) as { keys?: Jwk[] };
61
- const maxAge = /max-age=(\d+)/.exec(res.headers.get('cache-control') ?? '');
62
- const ttlMs = maxAge ? Number(maxAge[1]) * 1000 : 3600_000;
63
- const keys = body.keys ?? [];
64
- certCache = { keys, expiresAt: Date.now() + ttlMs };
65
- return keys;
66
- }
67
-
68
- async function loadCerts(
69
- fetcher: () => Promise<Jwk[]>,
70
- ): Promise<Jwk[]> {
71
- if (certCache && certCache.expiresAt > Date.now()) return certCache.keys;
72
- return fetcher();
73
- }
74
-
75
- function jwkPublicKey(jwk: Jwk): ReturnType<typeof createPublicKey> {
76
- return createPublicKey({
77
- key: jwk as unknown as CryptoJsonWebKey,
78
- format: 'jwk',
79
- });
80
- }
81
-
82
- function verifySignature(token: string, jwk: Jwk): boolean {
83
- const parts = token.split('.');
84
- const signingInput = `${parts[0]}.${parts[1]}`;
85
- const signature = decodeSegment(parts[2] ?? '');
86
- return cryptoVerify(
87
- 'RSA-SHA256',
88
- Buffer.from(signingInput),
89
- jwkPublicKey(jwk),
90
- signature,
91
- );
92
- }
93
-
94
- interface Header {
95
- alg?: string;
96
- kid?: string;
97
- }
98
-
99
- interface Payload {
100
- iss?: string;
101
- aud?: string;
102
- exp?: number;
103
- email?: string;
104
- email_verified?: boolean | string;
105
- nonce?: string;
106
- }
107
-
108
- function assertHeader(header: Header): asserts header is Header & { kid: string } {
109
- if (header.alg !== 'RS256')
110
- throw new GoogleAuthError(`unsupported alg ${String(header.alg)}`);
111
- if (!header.kid) throw new GoogleAuthError('missing kid');
112
- }
113
-
114
- function assertNotExpired(payload: Payload, opts: VerifyOptions): number {
115
- const now = Math.floor((opts.now ?? Date.now()) / 1000);
116
- const skew = opts.clockToleranceSec ?? 60;
117
- if (typeof payload.exp !== 'number' || payload.exp + skew < now)
118
- throw new GoogleAuthError('token expired');
119
- return payload.exp;
120
- }
121
-
122
- function verifiedEmail(payload: Payload): string {
123
- const verified =
124
- payload.email_verified === true || payload.email_verified === 'true';
125
- if (!payload.email || !verified)
126
- throw new GoogleAuthError('email not verified');
127
- return payload.email.toLowerCase();
128
- }
129
-
130
- function validateClaims(payload: Payload, opts: VerifyOptions): GoogleClaims {
131
- if (!payload.iss || !GOOGLE_ISSUERS.has(payload.iss))
132
- throw new GoogleAuthError(`unexpected issuer ${String(payload.iss)}`);
133
- if (payload.aud !== opts.clientId)
134
- throw new GoogleAuthError('audience mismatch');
135
- if (opts.expectedNonce !== undefined && payload.nonce !== opts.expectedNonce)
136
- throw new GoogleAuthError('nonce mismatch');
137
- const exp = assertNotExpired(payload, opts);
138
- return {
139
- email: verifiedEmail(payload),
140
- emailVerified: true,
141
- aud: payload.aud,
142
- iss: payload.iss,
143
- exp,
144
- };
145
- }
146
-
147
- export async function verifyGoogleIdToken(
148
- token: string,
149
- opts: VerifyOptions,
150
- ): Promise<GoogleClaims> {
151
- const parts = token.split('.');
152
- if (parts.length !== 3) throw new GoogleAuthError('not a JWT');
153
- const header = decodeJson(parts[0] ?? '') as Header;
154
- const payload = decodeJson(parts[1] ?? '') as Payload;
155
- assertHeader(header);
156
-
157
- const keys = await loadCerts(opts.fetchCerts ?? fetchGoogleCerts);
158
- const jwk = keys.find((k) => k.kid === header.kid);
159
- if (!jwk) throw new GoogleAuthError('signing key not found');
160
- if (!verifySignature(token, jwk))
161
- throw new GoogleAuthError('invalid signature');
162
-
163
- return validateClaims(payload, opts);
164
- }
@@ -1,208 +0,0 @@
1
- import type { IncomingMessage, ServerResponse } from 'node:http';
2
- import { errMsg, log } from './log.js';
3
- import { verifyGoogleIdToken } from './google-auth.js';
4
- import { newNonce, signSession, signState, verifyState } from './session.js';
5
- import { ensureUserWithProject } from '../db/projects.js';
6
-
7
- export interface OAuthConfig {
8
- clientId: string;
9
- clientSecret: string;
10
- redirectUri: string;
11
- authUrl: string;
12
- tokenUrl: string;
13
- sessionSecret: string;
14
- sessionTtlSec: number;
15
- }
16
-
17
- const DEFAULT_REDIRECT_URI = 'https://mcp.metro.box/auth/google/callback';
18
- const DEFAULT_AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth';
19
- const DEFAULT_TOKEN_URL = 'https://oauth2.googleapis.com/token';
20
- const PREVIEW = /^([a-z0-9-]+--)?metro-ui\.netlify\.app$/;
21
-
22
- const DEFAULT_SESSION_TTL_SEC = 30 * 24 * 3600;
23
-
24
- const envOr = (name: string, def: string): string => {
25
- const v = process.env[name]?.trim();
26
- return v !== undefined && v !== '' ? v : def;
27
- };
28
-
29
- export function sessionTtlFromEnv(): number {
30
- const ttl = Number(process.env.METRO_SESSION_TTL_SEC);
31
- return Number.isFinite(ttl) && ttl > 0 ? ttl : DEFAULT_SESSION_TTL_SEC;
32
- }
33
-
34
- function oauthConfigFromEnv(): OAuthConfig | null {
35
- const clientId = process.env.GOOGLE_OAUTH_CLIENT_ID?.trim() ?? '';
36
- const clientSecret = process.env.GOOGLE_OAUTH_CLIENT_SECRET?.trim() ?? '';
37
- const sessionSecret = process.env.METRO_SESSION_SECRET?.trim() ?? '';
38
- if (clientId === '' || clientSecret === '' || sessionSecret === '') return null;
39
- return {
40
- clientId,
41
- clientSecret,
42
- sessionSecret,
43
- redirectUri: envOr('GOOGLE_OAUTH_REDIRECT_URI', DEFAULT_REDIRECT_URI),
44
- authUrl: envOr('GOOGLE_OAUTH_AUTH_URL', DEFAULT_AUTH_URL),
45
- tokenUrl: envOr('GOOGLE_OAUTH_TOKEN_URL', DEFAULT_TOKEN_URL),
46
- sessionTtlSec: sessionTtlFromEnv(),
47
- };
48
- }
49
-
50
- export function validateReturnTo(returnTo: string): boolean {
51
- let url: URL;
52
- try {
53
- url = new URL(returnTo);
54
- } catch {
55
- return false;
56
- }
57
- const host = url.hostname;
58
- if (url.protocol === 'http:' && (host === 'localhost' || host === '127.0.0.1'))
59
- return true;
60
- if (url.protocol !== 'https:') return false;
61
- if (host === 'metro.box' || host === 'localhost') return true;
62
- return PREVIEW.test(host);
63
- }
64
-
65
- export function buildStartRedirect(
66
- cfg: OAuthConfig,
67
- returnTo: string,
68
- now?: number,
69
- ): string {
70
- if (!validateReturnTo(returnTo)) throw new Error('invalid return_to');
71
- const nonce = newNonce();
72
- const state = signState(
73
- { return_to: returnTo, nonce },
74
- cfg.sessionSecret,
75
- { now },
76
- );
77
- const u = new URL(cfg.authUrl);
78
- u.searchParams.set('client_id', cfg.clientId);
79
- u.searchParams.set('redirect_uri', cfg.redirectUri);
80
- u.searchParams.set('response_type', 'code');
81
- u.searchParams.set('scope', 'openid email');
82
- u.searchParams.set('state', state);
83
- u.searchParams.set('nonce', nonce);
84
- u.searchParams.set('prompt', 'select_account');
85
- return u.toString();
86
- }
87
-
88
- function withFragment(returnTo: string, frag: string): string {
89
- return `${returnTo.split('#')[0]}#${frag}`;
90
- }
91
-
92
- export interface CallbackDeps {
93
- exchangeCode: (code: string) => Promise<{ id_token?: string }>;
94
- verifyIdToken: (idToken: string, nonce: string) => Promise<{ email: string }>;
95
- ensureUser: (email: string) => Promise<string>;
96
- }
97
-
98
- export async function completeCallback(
99
- cfg: OAuthConfig,
100
- params: { code?: string; state?: string },
101
- deps: CallbackDeps,
102
- now?: number,
103
- ): Promise<string> {
104
- if (!params.state) throw new Error('missing state');
105
- const { return_to, nonce } = verifyState(params.state, cfg.sessionSecret, now);
106
- if (!validateReturnTo(return_to)) throw new Error('invalid return_to');
107
- if (!params.code) return withFragment(return_to, 'error=exchange');
108
-
109
- const tokens = await deps.exchangeCode(params.code);
110
- if (!tokens.id_token) return withFragment(return_to, 'error=exchange');
111
-
112
- let email: string;
113
- try {
114
- ({ email } = await deps.verifyIdToken(tokens.id_token, nonce));
115
- } catch {
116
- return withFragment(return_to, 'error=verify');
117
- }
118
-
119
- const userId = await deps.ensureUser(email);
120
- const agentIds: string[] = [];
121
- log.info({ userId }, 'google auth: session issued');
122
-
123
- const session = signSession({ email, agentIds }, cfg.sessionSecret, {
124
- ttlSec: cfg.sessionTtlSec,
125
- now,
126
- });
127
- return withFragment(return_to, `session=${encodeURIComponent(session)}`);
128
- }
129
-
130
- async function exchangeCode(
131
- cfg: OAuthConfig,
132
- code: string,
133
- ): Promise<{ id_token?: string }> {
134
- const res = await fetch(cfg.tokenUrl, {
135
- method: 'POST',
136
- headers: { 'content-type': 'application/x-www-form-urlencoded' },
137
- body: new URLSearchParams({
138
- code,
139
- client_id: cfg.clientId,
140
- client_secret: cfg.clientSecret,
141
- redirect_uri: cfg.redirectUri,
142
- grant_type: 'authorization_code',
143
- }),
144
- });
145
- if (!res.ok) throw new Error(`token exchange failed: ${res.status}`);
146
- return (await res.json()) as { id_token?: string };
147
- }
148
-
149
- function defaultDeps(cfg: OAuthConfig): CallbackDeps {
150
- return {
151
- exchangeCode: (code) => exchangeCode(cfg, code),
152
- verifyIdToken: (idToken, nonce) =>
153
- verifyGoogleIdToken(idToken, {
154
- clientId: cfg.clientId,
155
- expectedNonce: nonce,
156
- }).then((c) => ({ email: c.email })),
157
- ensureUser: ensureUserWithProject,
158
-
159
- };
160
- }
161
-
162
- function serveStart(cfg: OAuthConfig, url: URL, res: ServerResponse): void {
163
- const redirect = buildStartRedirect(cfg, url.searchParams.get('return_to') ?? '');
164
- res.writeHead(302, { location: redirect }).end();
165
- }
166
-
167
- async function serveCallback(
168
- cfg: OAuthConfig,
169
- url: URL,
170
- res: ServerResponse,
171
- ): Promise<void> {
172
- const redirect = await completeCallback(
173
- cfg,
174
- {
175
- code: url.searchParams.get('code') ?? undefined,
176
- state: url.searchParams.get('state') ?? undefined,
177
- },
178
- defaultDeps(cfg),
179
- );
180
- res.writeHead(302, { location: redirect }).end();
181
- }
182
-
183
- export async function handleGoogleAuthRequest(
184
- req: IncomingMessage,
185
- res: ServerResponse,
186
- ): Promise<boolean> {
187
- const url = new URL(req.url ?? '/', 'http://localhost');
188
- const path = url.pathname;
189
- if (path !== '/auth/google/start' && path !== '/auth/google/callback')
190
- return false;
191
- if (req.method !== 'GET') {
192
- res.writeHead(405).end();
193
- return true;
194
- }
195
- const cfg = oauthConfigFromEnv();
196
- if (!cfg) {
197
- res.writeHead(503).end('google login not configured');
198
- return true;
199
- }
200
- try {
201
- if (path === '/auth/google/start') serveStart(cfg, url, res);
202
- else await serveCallback(cfg, url, res);
203
- } catch (e) {
204
- log.warn({ err: errMsg(e) }, 'google auth request failed');
205
- res.writeHead(400).end('bad request');
206
- }
207
- return true;
208
- }