@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
@@ -1,14 +1,20 @@
1
- import { ApiError } from '../daemon/api-error.js';
1
+ import { ApiError } from '@metro-labs/http/api-error';
2
+ import { stringOf } from '@metro-labs/http/api-http';
2
3
  import type {
3
4
  ConnectorAuth,
4
5
  VerifiedRecord,
5
6
  VerifiedServer,
6
- } from '../daemon/connector-verify.js';
7
- import { readStoredTools } from '../daemon/connector-tools.js';
7
+ } from './verify.js';
8
+ import type { OAuthClient } from './oauth-client.js';
9
+ import { isRecord } from '@metro-labs/core/is-record';
10
+ import type { ToolGroup } from '@metro-labs/core/stations/types';
11
+ import { parsePolicy, type ToolPolicy } from '../policy/policy.js';
8
12
 
9
13
  const CONNECTOR_NAME_MAX = 64;
10
14
  const HEADER_NAME_RE = /^[A-Za-z0-9!#$%&'*+.^_`|~-]{1,64}$/;
11
15
  const HEADER_VALUE_RE = /^[\x20-\x7e]{1,4096}$/;
16
+ const CLIENT_ID_RE = /^[\x21-\x7e]{1,256}$/;
17
+ const CLIENT_SECRET_RE = /^[\x21-\x7e]{1,1024}$/;
12
18
  const DEFAULT_HEADER = 'Authorization';
13
19
 
14
20
  export class ConnectorError extends ApiError {}
@@ -20,14 +26,9 @@ export interface ConnectorConfig {
20
26
  createdAt: string;
21
27
  verified: VerifiedRecord;
22
28
  oauth: boolean;
23
- }
24
-
25
- function isRecord(value: unknown): value is Record<string, unknown> {
26
- return typeof value === 'object' && value !== null && !Array.isArray(value);
27
- }
28
-
29
- function text(value: unknown): string {
30
- return typeof value === 'string' ? value : '';
29
+ client: OAuthClient | null;
30
+ policy?: ToolPolicy;
31
+ toolGroups?: Record<string, ToolGroup>;
31
32
  }
32
33
 
33
34
  function hasControlChar(value: string): boolean {
@@ -58,8 +59,8 @@ export function connectorAuth(
58
59
  rawHeader: unknown,
59
60
  rawValue: unknown,
60
61
  ): ConnectorAuth {
61
- const header = text(rawHeader).trim();
62
- const value = text(rawValue).trim();
62
+ const header = stringOf(rawHeader).trim();
63
+ const value = stringOf(rawValue).trim();
63
64
  if (header === '' && value === '') return { kind: 'none' };
64
65
  if (value === '')
65
66
  throw new ConnectorError(
@@ -74,22 +75,48 @@ export function connectorAuth(
74
75
  return { kind: 'header', name, value };
75
76
  }
76
77
 
78
+ export function connectorClient(
79
+ rawId: unknown,
80
+ rawSecret: unknown,
81
+ ): OAuthClient | null {
82
+ const clientId = stringOf(rawId).trim();
83
+ const clientSecret = stringOf(rawSecret).trim();
84
+ if (clientId === '' && clientSecret === '') return null;
85
+ if (clientId === '')
86
+ throw new ConnectorError('a client secret needs the client ID it belongs to', 400);
87
+ if (!CLIENT_ID_RE.test(clientId))
88
+ throw new ConnectorError('that is not a client ID Metro can send', 400);
89
+ if (clientSecret !== '' && !CLIENT_SECRET_RE.test(clientSecret))
90
+ throw new ConnectorError('that client secret is not sendable', 400);
91
+ return { clientId, ...(clientSecret === '' ? {} : { clientSecret }) };
92
+ }
93
+
94
+ function readClient(raw: unknown): OAuthClient | null {
95
+ if (!isRecord(raw)) return null;
96
+ const clientId = stringOf(raw.clientId);
97
+ if (clientId === '') return null;
98
+ const clientSecret = stringOf(raw.clientSecret);
99
+ return { clientId, ...(clientSecret === '' ? {} : { clientSecret }) };
100
+ }
101
+
77
102
  function readOAuth(raw: Record<string, unknown>): ConnectorAuth {
78
- const accessToken = text(raw.accessToken);
79
- const clientId = text(raw.clientId);
80
- const tokenEndpoint = text(raw.tokenEndpoint);
103
+ const accessToken = stringOf(raw.accessToken);
104
+ const clientId = stringOf(raw.clientId);
105
+ const tokenEndpoint = stringOf(raw.tokenEndpoint);
81
106
  if (accessToken === '' || clientId === '' || tokenEndpoint === '')
82
107
  return { kind: 'none' };
83
- const refreshToken = text(raw.refreshToken);
84
- const clientSecret = text(raw.clientSecret);
108
+ const refreshToken = stringOf(raw.refreshToken);
109
+ const clientSecret = stringOf(raw.clientSecret);
110
+ const scope = stringOf(raw.scope);
85
111
  return {
86
112
  kind: 'oauth',
87
113
  accessToken,
88
114
  clientId,
89
115
  tokenEndpoint,
90
- issuer: text(raw.issuer),
116
+ issuer: stringOf(raw.issuer),
91
117
  ...(refreshToken === '' ? {} : { refreshToken }),
92
118
  ...(clientSecret === '' ? {} : { clientSecret }),
119
+ ...(scope === '' ? {} : { scope }),
93
120
  ...(typeof raw.expiresAt === 'number' ? { expiresAt: raw.expiresAt } : {}),
94
121
  };
95
122
  }
@@ -98,34 +125,41 @@ function readAuth(raw: unknown): ConnectorAuth {
98
125
  if (!isRecord(raw)) return { kind: 'none' };
99
126
  if (raw.kind === 'oauth') return readOAuth(raw);
100
127
  if (raw.kind !== 'header') return { kind: 'none' };
101
- const name = text(raw.name);
102
- const value = text(raw.value);
128
+ const name = stringOf(raw.name);
129
+ const value = stringOf(raw.value);
103
130
  if (name === '' || value === '') return { kind: 'none' };
104
131
  return { kind: 'header', name, value };
105
132
  }
106
133
 
107
134
  function readVerified(raw: unknown): VerifiedRecord {
108
135
  const record = isRecord(raw) ? raw : {};
109
- const catalog = readStoredTools(record.catalog);
110
- return {
111
- at: text(record.at),
112
- server: text(record.server),
113
- version: text(record.version),
114
- protocol: text(record.protocol),
115
- icon: text(record.icon),
116
- tools: typeof record.tools === 'number' ? record.tools : 0,
117
- catalog,
118
- };
136
+ return { at: stringOf(record.at), server: stringOf(record.server) };
137
+ }
138
+
139
+ const TOOL_NAME_MAX = 128;
140
+ const TOOL_GROUPS_MAX = 1000;
141
+
142
+ function readToolGroups(raw: unknown): Record<string, ToolGroup> | undefined {
143
+ if (!isRecord(raw)) return undefined;
144
+ const kept = Object.entries(raw)
145
+ .filter((entry): entry is [string, ToolGroup] => entry[0].length <= TOOL_NAME_MAX && (entry[1] === 'read' || entry[1] === 'write'))
146
+ .slice(0, TOOL_GROUPS_MAX);
147
+ return kept.length > 0 ? Object.fromEntries(kept) : undefined;
119
148
  }
120
149
 
121
150
  export function readConfig(raw: unknown): ConnectorConfig {
122
151
  const record = isRecord(raw) ? raw : {};
123
152
  const auth = readAuth(record.auth);
153
+ const policy = parsePolicy(record.policy, 'connectors.json');
154
+ const toolGroups = readToolGroups(record.toolGroups);
124
155
  return {
125
156
  auth,
126
- createdAt: text(record.createdAt),
157
+ createdAt: stringOf(record.createdAt),
127
158
  verified: readVerified(record.verified),
128
159
  oauth: record.oauth === true || auth.kind === 'oauth',
160
+ client: readClient(record.client),
161
+ ...(policy === undefined || Object.keys(policy).length === 0 ? {} : { policy }),
162
+ ...(toolGroups === undefined ? {} : { toolGroups }),
129
163
  };
130
164
  }
131
165
 
@@ -135,13 +169,5 @@ export function signInState(config: ConnectorConfig): ConnectorSignIn {
135
169
  }
136
170
 
137
171
  export function stamp(server: VerifiedServer): VerifiedRecord {
138
- return {
139
- at: new Date().toISOString(),
140
- server: server.server,
141
- version: server.version,
142
- protocol: server.protocol,
143
- icon: server.icon,
144
- tools: server.tools,
145
- catalog: server.catalog,
146
- };
172
+ return { at: new Date().toISOString(), server: server.server };
147
173
  }
@@ -0,0 +1,72 @@
1
+ import type { ToolGroup } from '@metro-labs/core/stations/types';
2
+ import { policyFor, setPolicies, type PolicyTarget, type ToolPolicy } from '../policy/policy.js';
3
+ import { serverKeysOf } from './plugin-sync.js';
4
+ import { NEEDS_APPROVAL, settlePrompts, takeGrant } from '../approvals/pending.js';
5
+
6
+ interface GateRow {
7
+ id: string;
8
+ name: string;
9
+ config: { policy?: ToolPolicy; toolGroups?: Record<string, ToolGroup> };
10
+ }
11
+
12
+ export interface ConnectorGate {
13
+ id: string;
14
+ name: string;
15
+ server: string;
16
+ policy: ToolPolicy;
17
+ tools: Record<string, ToolGroup>;
18
+ }
19
+
20
+ let gates: ConnectorGate[] = [];
21
+
22
+ const normalized = (name: string): string => name.replace(/[^a-zA-Z0-9_-]/g, '_');
23
+
24
+ export function registerConnectors(rows: readonly GateRow[]): void {
25
+ const keys = serverKeysOf([...rows]);
26
+ gates = rows.map((row) => ({
27
+ id: row.id,
28
+ name: row.name,
29
+ server: keys.get(row.id) ?? '',
30
+ policy: row.config.policy ?? {},
31
+ tools: row.config.toolGroups ?? {},
32
+ }));
33
+ const entries = rows.flatMap((row): [PolicyTarget, ToolPolicy][] =>
34
+ row.config.policy === undefined ? [] : [[{ kind: 'connector', id: row.id }, row.config.policy]],
35
+ );
36
+ setPolicies('connector', entries);
37
+ }
38
+
39
+ export const connectorGates = (): readonly ConnectorGate[] => gates;
40
+
41
+ export const toolGroupOf = (gate: ConnectorGate, tool: string): ToolGroup => (gate.tools[tool] === 'read' ? 'read' : 'write');
42
+
43
+ const promptFor = (connectorId: string, tool: string) => (asked: string): boolean => {
44
+ const found = connectorToolOf(asked);
45
+ return found?.gate.id === connectorId && found.tool === tool;
46
+ };
47
+
48
+ export function blockedReason(connectorId: string, tool: string, args: Record<string, unknown> = {}): string | null {
49
+ const gate = gates.find((g) => g.id === connectorId);
50
+ if (gate === undefined) return null;
51
+ settlePrompts(promptFor(connectorId, tool), args);
52
+ const access = policyFor({ kind: 'connector', id: connectorId }, { name: tool, group: toolGroupOf(gate, tool) });
53
+ if (access === 'deny') return `Blocked by the owner's policy for ${gate.name} (${tool}).`;
54
+ if (access === 'allow' || takeGrant(promptFor(connectorId, tool), args)) return null;
55
+ return NEEDS_APPROVAL(gate.name, tool);
56
+ }
57
+
58
+ function prefixesOf(gate: ConnectorGate): string[] {
59
+ return [`mcp__plugin_metro_${gate.server}__`, `mcp__${gate.server}__`, `mcp__${normalized(`metro.box ${gate.name}`)}__`];
60
+ }
61
+
62
+ export function connectorToolOf(toolName: string): { gate: ConnectorGate; tool: string } | undefined {
63
+ if (toolName.startsWith('mcp__metro__')) return undefined;
64
+ for (const gate of gates)
65
+ for (const prefix of prefixesOf(gate))
66
+ if (toolName.startsWith(prefix) && toolName.length > prefix.length) {
67
+ const called = toolName.slice(prefix.length);
68
+ const known = [...Object.keys(gate.tools), ...Object.keys(gate.policy.tools ?? {})];
69
+ return { gate, tool: known.find((name) => name === called) ?? known.find((name) => normalized(name) === called) ?? called };
70
+ }
71
+ return undefined;
72
+ }
@@ -0,0 +1,18 @@
1
+ export interface ConnectorHealth {
2
+ ok: boolean;
3
+ reason: string | null;
4
+ at: string;
5
+ }
6
+
7
+ const seen = new Map<string, ConnectorHealth>();
8
+
9
+ export function noteHealth(id: string, ok: boolean, reason: string | null = null): void {
10
+ seen.set(id, { ok, reason: ok ? null : reason, at: new Date().toISOString() });
11
+ }
12
+
13
+ export const healthOf = (id: string): ConnectorHealth | null => seen.get(id) ?? null;
14
+
15
+ export function forgetHealth(id?: string): void {
16
+ if (id === undefined) seen.clear();
17
+ else seen.delete(id);
18
+ }
@@ -1,9 +1,8 @@
1
1
  import { createHash, randomBytes } from 'node:crypto';
2
- import {
3
- ConnectorVerifyError,
4
- type OAuthTokens,
5
- } from './connector-verify.js';
2
+ import { whyUnreachable } from './reach.js';
3
+ import { refused, type OAuthTokens } from './verify.js';
6
4
  import type { OAuthServer } from './oauth-discovery.js';
5
+ import { isRecord } from '@metro-labs/core/is-record';
7
6
 
8
7
  const TOKEN_TIMEOUT_MS = 15_000;
9
8
  const CLIENT_NAME = 'Metro';
@@ -13,14 +12,6 @@ export interface OAuthClient {
13
12
  clientSecret?: string;
14
13
  }
15
14
 
16
- function refused(message: string): ConnectorVerifyError {
17
- return new ConnectorVerifyError(message, 400);
18
- }
19
-
20
- function isRecord(value: unknown): value is Record<string, unknown> {
21
- return typeof value === 'object' && value !== null && !Array.isArray(value);
22
- }
23
-
24
15
  export function newVerifier(): string {
25
16
  return randomBytes(32).toString('base64url');
26
17
  }
@@ -35,7 +26,9 @@ export async function registerClient(
35
26
  ): Promise<OAuthClient> {
36
27
  if (server.registrationEndpoint === null)
37
28
  throw refused(
38
- 'That server requires OAuth but does not accept client registration, so Metro cannot sign in to it.',
29
+ 'That server signs in with OAuth but registers no clients on its own. ' +
30
+ `Register an app with it yourself, with ${redirectUri} as its redirect URL, ` +
31
+ "and add the connector again with that app's client ID.",
39
32
  );
40
33
  let res: Response;
41
34
  try {
@@ -52,8 +45,8 @@ export async function registerClient(
52
45
  token_endpoint_auth_method: 'none',
53
46
  }),
54
47
  });
55
- } catch {
56
- throw refused('Metro could not reach that server to register.');
48
+ } catch (err) {
49
+ throw refused(`Metro could not reach that server to register: ${whyUnreachable(err)}`);
57
50
  }
58
51
  const body: unknown = await res.json().catch(() => null);
59
52
  if (!res.ok || !isRecord(body) || typeof body.client_id !== 'string')
@@ -83,6 +76,8 @@ export function authorizeUrl(input: AuthorizeInput): string {
83
76
  url.searchParams.set('code_challenge', challengeOf(input.verifier));
84
77
  url.searchParams.set('code_challenge_method', 'S256');
85
78
  url.searchParams.set('resource', input.resource);
79
+ if (input.server.scopes.length > 0)
80
+ url.searchParams.set('scope', input.server.scopes.join(' '));
86
81
  return url.toString();
87
82
  }
88
83
 
@@ -125,8 +120,8 @@ async function postToken(
125
120
  },
126
121
  body: params.toString(),
127
122
  });
128
- } catch {
129
- throw refused('Metro could not reach that server to finish signing in.');
123
+ } catch (err) {
124
+ throw refused(`Metro could not reach that server to finish signing in: ${whyUnreachable(err)}`);
130
125
  }
131
126
  const body: unknown = await res.json().catch(() => null);
132
127
  if (!res.ok || !isRecord(body))
@@ -153,10 +148,12 @@ export function refreshTokens(
153
148
  client: OAuthClient,
154
149
  refreshToken: string,
155
150
  resource: string,
151
+ scope?: string,
156
152
  ): Promise<OAuthTokens> {
157
153
  return postToken(server, client, {
158
154
  grant_type: 'refresh_token',
159
155
  refresh_token: refreshToken,
160
156
  resource,
157
+ ...(scope === undefined ? {} : { scope }),
161
158
  });
162
159
  }
@@ -1,4 +1,6 @@
1
- import { ConnectorVerifyError, parseConnectorUrl } from './connector-verify.js';
1
+ import { parseConnectorUrl, refused } from './verify.js';
2
+ import { stringOf } from '@metro-labs/http/api-http';
3
+ import { isRecord } from '@metro-labs/core/is-record';
2
4
 
3
5
  const DISCOVERY_TIMEOUT_MS = 10_000;
4
6
 
@@ -8,19 +10,14 @@ export interface OAuthServer {
8
10
  tokenEndpoint: string;
9
11
  registrationEndpoint: string | null;
10
12
  supportsS256: boolean;
13
+ scopes: string[];
11
14
  }
12
15
 
13
- function refused(message: string): ConnectorVerifyError {
14
- return new ConnectorVerifyError(message, 400);
16
+ interface ResourceMetadata {
17
+ issuer: URL;
18
+ scopes: string[];
15
19
  }
16
20
 
17
- function isRecord(value: unknown): value is Record<string, unknown> {
18
- return typeof value === 'object' && value !== null && !Array.isArray(value);
19
- }
20
-
21
- const str = (value: unknown): string =>
22
- typeof value === 'string' ? value : '';
23
-
24
21
  async function getJson(url: URL): Promise<Record<string, unknown> | null> {
25
22
  let res: Response;
26
23
  try {
@@ -68,32 +65,48 @@ export async function advertisesOAuth(resource: URL): Promise<boolean> {
68
65
  return false;
69
66
  }
70
67
 
71
- async function authServerFor(resource: URL): Promise<URL> {
68
+ function scopesOf(body: Record<string, unknown> | null): string[] {
69
+ const raw: unknown = body?.scopes_supported;
70
+ if (!Array.isArray(raw)) return [];
71
+ const out: string[] = [];
72
+ for (const entry of raw) {
73
+ const scope = stringOf(entry).trim();
74
+ if (scope !== '' && !/\s/.test(scope) && !out.includes(scope)) out.push(scope);
75
+ }
76
+ return out;
77
+ }
78
+
79
+ async function resourceMetadata(resource: URL): Promise<ResourceMetadata> {
72
80
  for (const candidate of resourceMetadataUrls(resource)) {
73
81
  const body = await getJson(candidate);
74
82
  const servers: unknown = body?.authorization_servers;
75
83
  const first: unknown = Array.isArray(servers) ? servers[0] : undefined;
76
84
  if (typeof first === 'string' && first !== '')
77
- return parseConnectorUrl(first);
85
+ return { issuer: parseConnectorUrl(first), scopes: scopesOf(body) };
78
86
  }
79
- return parseConnectorUrl(resource.origin);
87
+ return { issuer: parseConnectorUrl(resource.origin), scopes: [] };
80
88
  }
81
89
 
82
- function toServer(body: Record<string, unknown>, issuer: URL): OAuthServer {
83
- const authorizationEndpoint = str(body.authorization_endpoint);
84
- const tokenEndpoint = str(body.token_endpoint);
90
+ function toServer(
91
+ body: Record<string, unknown>,
92
+ issuer: URL,
93
+ scopes: string[],
94
+ ): OAuthServer {
95
+ const authorizationEndpoint = stringOf(body.authorization_endpoint);
96
+ const tokenEndpoint = stringOf(body.token_endpoint);
85
97
  if (authorizationEndpoint === '' || tokenEndpoint === '')
86
98
  throw refused(
87
99
  `${issuer.hostname} advertises OAuth but not where to sign in.`,
88
100
  );
89
101
  const methods = body.code_challenge_methods_supported;
90
- const registration = str(body.registration_endpoint);
102
+ const registration = stringOf(body.registration_endpoint);
91
103
  return {
92
- issuer: str(body.issuer) === '' ? issuer.origin : str(body.issuer),
104
+ issuer: stringOf(body.issuer) === '' ? issuer.origin : stringOf(body.issuer),
93
105
  authorizationEndpoint,
94
106
  tokenEndpoint,
95
107
  registrationEndpoint: registration === '' ? null : registration,
96
108
  supportsS256: Array.isArray(methods) ? methods.includes('S256') : false,
109
+ scopes,
97
110
  };
98
111
  }
99
112
 
@@ -109,10 +122,10 @@ export function authServerMetadataUrls(issuer: URL): URL[] {
109
122
  }
110
123
 
111
124
  export async function discoverOAuth(resource: URL): Promise<OAuthServer> {
112
- const issuer = await authServerFor(resource);
125
+ const { issuer, scopes } = await resourceMetadata(resource);
113
126
  for (const candidate of authServerMetadataUrls(issuer)) {
114
127
  const body = await getJson(candidate);
115
- if (body !== null) return toServer(body, issuer);
128
+ if (body !== null) return toServer(body, issuer, scopes);
116
129
  }
117
130
  throw refused(
118
131
  `${resource.hostname} needs authorization, but publishes no OAuth metadata Metro can use.`,
@@ -1,18 +1,17 @@
1
1
  import type { IncomingMessage, ServerResponse } from 'node:http';
2
- import { errMsg, log } from './log.js';
3
- import { bodyField, readJsonBody, sendJson, type ApiSession } from './api-http.js';
2
+ import { errMsg, log } from '@metro-labs/core/log';
3
+ import { bodyField, readJsonBody, sendJson, stringOf } from '@metro-labs/http/api-http';
4
4
  import {
5
5
  beginOAuth,
6
6
  completeOAuth,
7
+ prepareOAuth,
7
8
  takePending,
8
9
  type PendingAuth,
9
- } from './connector-oauth.js';
10
- import { parseConnectorUrl } from './connector-verify.js';
11
- import type { OAuthAuth } from './connector-verify.js';
12
- import type { Connector } from '../db/connectors.js';
13
-
14
- const asText = (value: unknown): string =>
15
- typeof value === 'string' ? value : '';
10
+ } from './oauth.js';
11
+ import { connectorClient } from './config.js';
12
+ import { parseConnectorUrl } from './verify.js';
13
+ import type { OAuthAuth } from './verify.js';
14
+ import type { Connector, PendingConnectorInput } from './store.js';
16
15
 
17
16
  export function hostOf(url: string): string {
18
17
  try {
@@ -23,38 +22,37 @@ export function hostOf(url: string): string {
23
22
  }
24
23
 
25
24
  export interface OAuthRouteDeps {
26
- createPendingConnector: (
27
- email: string,
28
- project: string,
29
- input: { name: unknown; url: unknown },
30
- ) => Promise<Connector>;
31
- reconnectConnector: (
32
- email: string,
33
- id: string,
34
- auth: OAuthAuth,
35
- ) => Promise<Connector>;
36
- getConnector: (email: string, id: string) => Promise<Connector>;
25
+ createPendingConnector: (input: PendingConnectorInput) => Promise<Connector>;
26
+ reconnectConnector: (id: string, auth: OAuthAuth) => Promise<Connector>;
27
+ getConnector: (id: string) => Promise<Connector>;
37
28
  }
38
29
 
39
30
  export async function startOAuth(
40
31
  req: IncomingMessage,
41
32
  res: ServerResponse,
42
33
  deps: OAuthRouteDeps,
43
- session: ApiSession,
44
- project: string,
45
34
  body: unknown,
46
35
  payload: (row: Connector) => Record<string, unknown>,
47
36
  ): Promise<void> {
48
37
  const url = parseConnectorUrl(bodyField(body, 'url'));
49
- const row = await deps.createPendingConnector(session.email, project, {
38
+ const returnTo = stringOf(bodyField(body, 'returnTo'));
39
+ const clientId = bodyField(body, 'clientId');
40
+ const clientSecret = bodyField(body, 'clientSecret');
41
+ const prepared = await prepareOAuth({
42
+ url,
43
+ client: connectorClient(clientId, clientSecret),
44
+ returnTo,
45
+ });
46
+ const row = await deps.createPendingConnector({
50
47
  name: bodyField(body, 'name'),
51
48
  url: bodyField(body, 'url'),
49
+ clientId,
50
+ clientSecret,
52
51
  });
53
- const authorize = await beginOAuth({
54
- email: session.email,
52
+ const authorize = beginOAuth(prepared, {
55
53
  name: row.name,
56
54
  url,
57
- returnTo: asText(bodyField(body, 'returnTo')),
55
+ returnTo,
58
56
  connectorId: row.id,
59
57
  });
60
58
  log.info(
@@ -68,17 +66,17 @@ export async function handleConnect(
68
66
  req: IncomingMessage,
69
67
  res: ServerResponse,
70
68
  deps: OAuthRouteDeps,
71
- session: ApiSession,
72
69
  id: string,
73
70
  ): Promise<void> {
74
- const row = await deps.getConnector(session.email, id);
71
+ const row = await deps.getConnector(id);
75
72
  const url = parseConnectorUrl(row.url);
76
73
  const body = await readJsonBody(req);
77
- const authorize = await beginOAuth({
78
- email: session.email,
74
+ const returnTo = stringOf(bodyField(body, 'returnTo'));
75
+ const prepared = await prepareOAuth({ url, client: row.client, returnTo });
76
+ const authorize = beginOAuth(prepared, {
79
77
  name: row.name,
80
78
  url,
81
- returnTo: asText(bodyField(body, 'returnTo')),
79
+ returnTo,
82
80
  connectorId: row.id,
83
81
  });
84
82
  log.info(
@@ -110,7 +108,7 @@ async function saveOAuth(
110
108
  entry: PendingAuth,
111
109
  auth: OAuthAuth,
112
110
  ): Promise<Connector> {
113
- return deps.reconnectConnector(entry.email, entry.connectorId, auth);
111
+ return deps.reconnectConnector(entry.connectorId, auth);
114
112
  }
115
113
 
116
114
  async function settleCallback(