@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
@@ -0,0 +1,60 @@
1
+ import type { ToolDef } from './tool-def.js';
2
+ import { Line } from '@metro-labs/core/lines';
3
+ import type { Station, ToolResult } from '@metro-labs/core/stations/types';
4
+ import { str } from '@metro-labs/core/str';
5
+ import { stationByName } from '../stations/registry.js';
6
+ import { errResult, makeCtx, okJson, toErr } from './ctx.js';
7
+
8
+ export const GET_PROFILE_TOOL: ToolDef = {
9
+ name: 'get_profile',
10
+ group: 'read',
11
+ description:
12
+ 'Who is this person? Give the `from` attribute of one of their messages verbatim ' +
13
+ '(`metro://<station>/<account>/user/<id>`) and get what their network says about them: ' +
14
+ '{id, name, display_name, about, avatar, address}. XMTP answers the Basename ' +
15
+ '(<label>.stage.base.eth), its name, description and avatar records, and the wallet address; ' +
16
+ 'WhatsApp the phone number, the name they last used, the about line and the picture; Telegram the handle, the name and the bio; Discord ' +
17
+ 'the username, the global name and the avatar. Fields the network does not have are absent. ' +
18
+ 'The answer is cached for ten minutes, so ask when you want to know someone, not on every message.',
19
+ inputSchema: {
20
+ type: 'object',
21
+ properties: {
22
+ from: { type: 'string', description: 'The `from` of a message, exactly as received.' },
23
+ },
24
+ required: ['from'],
25
+ },
26
+ };
27
+
28
+ export interface ProfileTarget {
29
+ station: Station;
30
+ account: string;
31
+ user: string;
32
+ }
33
+
34
+ export function profileTarget(a: Record<string, unknown>): ProfileTarget | { refused: string } {
35
+ const from = str(a.from);
36
+ if (!from) return { refused: 'get_profile requires `from`' };
37
+ const parsed = Line.parse(from);
38
+ const at = parsed?.path.indexOf('user') ?? -1;
39
+ if (parsed === null || at < 1 || at + 1 >= parsed.path.length) return { refused: `${from} is not a person: expected metro://<station>/<account>/user/<id>` };
40
+ const station = stationByName(parsed.station);
41
+ if (!station) return { refused: `no station named ${parsed.station}` };
42
+ if (station.readsProfiles !== true) return { refused: `${station.name} has no profile metro can read` };
43
+ return { station, account: parsed.path.slice(0, at).join('/'), user: parsed.path.slice(at + 1).join('/') };
44
+ }
45
+
46
+ export const profileScopeLine = (a: Record<string, unknown>): string | undefined => {
47
+ const target = profileTarget(a);
48
+ return 'refused' in target ? undefined : `metro://${target.station.name}/${target.account}/user/${target.user}`;
49
+ };
50
+
51
+ export async function dispatchGetProfile(a: Record<string, unknown>): Promise<ToolResult> {
52
+ const target = profileTarget(a);
53
+ if ('refused' in target) return errResult(target.refused);
54
+ try {
55
+ const { result } = await makeCtx(target.station.name).call('profile', { account: target.account, user: target.user });
56
+ return okJson(result);
57
+ } catch (e) {
58
+ return toErr('get_profile', e);
59
+ }
60
+ }
@@ -0,0 +1,96 @@
1
+ import type { ToolDef } from './tool-def.js';
2
+ import type { CanonicalAttachment, Station, ToolResult } from '@metro-labs/core/stations/types';
3
+ import { PROFILE_FIELDS, type ProfileField } from '@metro-labs/core/stations/profile';
4
+ import { str } from '@metro-labs/core/str';
5
+ import { STATIONS, stationByName } from '../stations/registry.js';
6
+ import { cleanupAttachments, resolveAttachments, type ResolvedAttachment } from '../stations/attach-resolve.js';
7
+ import { errResult, makeCtx, okJson, toErr } from './ctx.js';
8
+ import { allowedAgents, currentIdentity } from './request-identity.js';
9
+
10
+ const SOURCE = { type: 'string' };
11
+
12
+ export const SET_PROFILE_TOOL: ToolDef = {
13
+ name: 'set_profile',
14
+ group: 'write',
15
+ description:
16
+ 'Change how one of your accounts presents itself on its network: the display name, the bio ' +
17
+ '(about line) and the avatar. Args: station (required), account? (which account of that station; ' +
18
+ 'needed only when you have several), name?, bio?, avatar? (an image given like an attachment: ' +
19
+ 'exactly one of upload, url, path, data, plus mime and name). At least one of name, bio, avatar. ' +
20
+ 'Each station takes what its network allows (`list_accounts` reports the fields under ' +
21
+ '`profiles`); a field the station cannot set is refused by name, never dropped. Discord changes ' +
22
+ 'the bot username and app description (Discord allows two username changes an hour); Telegram ' +
23
+ 'bots set their name, description and photo; a Telegram user account sets its first name, bio ' +
24
+ '(70 chars) and photo; WhatsApp sets the profile name, about and picture; XMTP writes the ' +
25
+ 'name, description and avatar records of the account\'s <label>.stage.base.eth name on Base, ' +
26
+ 'so it needs a name first (claimed on the channel page, never by you). Visible to everyone ' +
27
+ 'who talks to the account, so do it when asked, not on your own. Returns {account, applied}.',
28
+ inputSchema: {
29
+ type: 'object',
30
+ properties: {
31
+ station: { type: 'string', description: 'discord-bot | telegram-bot | telegram | whatsapp | xmtp' },
32
+ account: { type: 'string', description: 'The account id on that station, from list_accounts.' },
33
+ name: { type: 'string', description: 'The display name.' },
34
+ bio: { type: 'string', description: 'The bio or about line.' },
35
+ avatar: {
36
+ type: 'object',
37
+ description: 'The new picture, as an attachment source.',
38
+ properties: { upload: SOURCE, url: SOURCE, path: SOURCE, data: SOURCE, mime: SOURCE, name: SOURCE },
39
+ },
40
+ },
41
+ required: ['station'],
42
+ },
43
+ };
44
+
45
+ export const profileCapabilities = (): Record<string, ProfileField[]> => {
46
+ const out: Record<string, ProfileField[]> = {};
47
+ for (const s of STATIONS) if (s.profileFields !== undefined) out[s.name] = [...s.profileFields];
48
+ return out;
49
+ };
50
+
51
+ const asked = (a: Record<string, unknown>): ProfileField[] => PROFILE_FIELDS.filter((f) => a[f] !== undefined);
52
+
53
+ type Target = { station: Station } | { refused: string };
54
+
55
+ function targetOf(a: Record<string, unknown>): Target {
56
+ const name = str(a.station);
57
+ if (!name) return { refused: 'set_profile requires `station`' };
58
+ const station = stationByName(name);
59
+ if (!station) return { refused: `no station named ${name}` };
60
+ const fields = station.profileFields;
61
+ if (fields === undefined) return { refused: `${name} accounts have no profile metro can set` };
62
+ const wanted = asked(a);
63
+ if (wanted.length === 0) return { refused: 'set_profile needs at least one of name, bio, avatar' };
64
+ const refused = wanted.filter((f) => !fields.has(f));
65
+ if (refused.length > 0) return { refused: `${name} cannot set ${refused.join(', ')}; it takes ${[...fields].join(', ')}` };
66
+ return { station };
67
+ }
68
+
69
+ function trainArgs(a: Record<string, unknown>, picture: ResolvedAttachment | undefined): Record<string, unknown> {
70
+ const args: Record<string, unknown> = {};
71
+ if (typeof a.account === 'string') args.account = a.account;
72
+ if (typeof a.name === 'string') args.name = a.name;
73
+ if (typeof a.bio === 'string') args.bio = a.bio;
74
+ if (picture !== undefined) args.avatar = { path: picture.path, mime: picture.mime, name: picture.name };
75
+ return args;
76
+ }
77
+
78
+ export async function dispatchSetProfile(a: Record<string, unknown>): Promise<ToolResult> {
79
+ const target = targetOf(a);
80
+ if ('refused' in target) return errResult(target.refused);
81
+ const avatar = a.avatar === undefined ? [] : [a.avatar as CanonicalAttachment];
82
+ let resolved: ResolvedAttachment[];
83
+ try {
84
+ resolved = await resolveAttachments(avatar, { allowed: allowedAgents(currentIdentity()) });
85
+ } catch (e) {
86
+ return toErr('set_profile', e);
87
+ }
88
+ try {
89
+ const { result } = await makeCtx(target.station.name).call('set_profile', trainArgs(a, resolved[0]));
90
+ return okJson(result);
91
+ } catch (e) {
92
+ return toErr('set_profile', e);
93
+ } finally {
94
+ await cleanupAttachments(resolved);
95
+ }
96
+ }
@@ -0,0 +1,87 @@
1
+ import { isRecord } from '@metro-labs/core/is-record';
2
+ import { str } from '@metro-labs/core/str';
3
+ import type { ReadFilter, Station, ToolResult } from '@metro-labs/core/stations/types';
4
+ import { agentIdForAccount, accountFromLine, knownAccounts } from '../agents/map.js';
5
+ import { attachmentUrl } from '../files/attach-serve.js';
6
+ import { stationByName } from '../stations/registry.js';
7
+ import { errResult, makeCtx, okJson, toErr } from './ctx.js';
8
+ import { agentUser } from '../agent-user/user.js';
9
+
10
+ const FILTERS: readonly (readonly [string, ReadFilter, string])[] = [
11
+ ['query', 'query', 'query'],
12
+ ['from', 'from', 'from'],
13
+ ['until', 'until', 'until'],
14
+ ['unread_only', 'unread_only', 'unreadOnly'],
15
+ ['message_id', 'message_id', 'messageId'],
16
+ ];
17
+
18
+ const given = (v: unknown): boolean => v !== undefined && v !== null && v !== '' && v !== false;
19
+
20
+ export function stationOfAccount(account: string): string | undefined {
21
+ const hits = knownAccounts().filter((a) => a.id === account);
22
+ return hits.length === 1 ? hits[0]?.station : undefined;
23
+ }
24
+
25
+ function readArgs(a: Record<string, unknown>): Record<string, unknown> {
26
+ const args: Record<string, unknown> = {};
27
+ if (str(a.line)) args.line = str(a.line);
28
+ if (str(a.account)) args.account = str(a.account);
29
+ if (typeof a.limit === 'number') args.limit = a.limit;
30
+ if (a.before) args.before = str(a.before);
31
+ if (a.since) args.since = str(a.since);
32
+ for (const [snake, , camel] of FILTERS)
33
+ if (given(a[snake])) args[camel] = typeof a[snake] === 'boolean' ? a[snake] : str(a[snake]);
34
+ return args;
35
+ }
36
+
37
+ function ignoredFilters(station: Station, a: Record<string, unknown>): string[] {
38
+ const supported = station.readFilters ?? new Set<ReadFilter>();
39
+ return FILTERS.filter(([snake, filter]) => given(a[snake]) && !supported.has(filter)).map(([snake]) => snake);
40
+ }
41
+
42
+ function withUrls(result: unknown, agentId: string | undefined): unknown {
43
+ if (agentId === undefined || !isRecord(result) || !isRecord(result.message)) return result;
44
+ const files = result.message.attachments;
45
+ if (!Array.isArray(files)) return result;
46
+ const attachments = files.map((f: unknown) => {
47
+ if (!isRecord(f) || typeof f.local_path !== 'string') return f;
48
+ const url = attachmentUrl(f.local_path, agentId);
49
+ const shown = agentUser() === null ? f : Object.fromEntries(Object.entries(f).filter(([key]) => key !== 'local_path'));
50
+ return url === null ? shown : { ...shown, url };
51
+ });
52
+ return { ...result, message: { ...result.message, attachments } };
53
+ }
54
+
55
+ function answer(result: unknown, ignored: string[]): unknown {
56
+ if (ignored.length === 0) return result;
57
+ return isRecord(result) && !Array.isArray(result) ? { ...result, ignored } : { result, ignored };
58
+ }
59
+
60
+ function accountOfCall(station: Station, a: Record<string, unknown>, result: unknown): string | undefined {
61
+ const named = str(a.account) || (isRecord(result) ? str(result.account) : '');
62
+ const account = named || accountFromLine(str(a.line))?.accountId;
63
+ return account === undefined ? undefined : agentIdForAccount(station.name, account);
64
+ }
65
+
66
+ export async function runRead(station: Station, a: Record<string, unknown>): Promise<ToolResult> {
67
+ try {
68
+ const response = await makeCtx(station.name).call('read', readArgs(a));
69
+ const result = withUrls(response.result, accountOfCall(station, a, response.result));
70
+ return okJson(answer(result, ignoredFilters(station, a)));
71
+ } catch (e) {
72
+ return toErr('read', e);
73
+ }
74
+ }
75
+
76
+ export function linelessRead(a: Record<string, unknown>): Promise<ToolResult> | ToolResult {
77
+ const account = str(a.account);
78
+ if (!account) return errResult('read requires `line` or `account`');
79
+ const name = stationOfAccount(account);
80
+ const station = name === undefined ? undefined : stationByName(name);
81
+ if (station === undefined) return errResult(`no account ${account} on this box; list_accounts names them`);
82
+ if (!station.messageVerbs.has('read'))
83
+ return errResult(`${station.name} does not support read; it supports ${[...station.messageVerbs].join(', ')}.`);
84
+ if (!station.readFilters?.has('account'))
85
+ return errResult(`${station.name} reads one conversation at a time; give a \`line\` instead of an account`);
86
+ return runRead(station, a);
87
+ }
@@ -0,0 +1,46 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ import type { IncomingMessage } from 'node:http';
3
+ import { agentIdForKey } from '../agents/keys.js';
4
+
5
+ export interface RequestIdentity {
6
+ kind: 'agent';
7
+ agentId: string;
8
+ }
9
+
10
+ const storage = new AsyncLocalStorage<RequestIdentity>();
11
+
12
+ export function runWithIdentity<T>(
13
+ identity: RequestIdentity,
14
+ fn: () => Promise<T>,
15
+ ): Promise<T> {
16
+ return storage.run(identity, fn);
17
+ }
18
+
19
+ export function currentIdentity(): RequestIdentity | undefined {
20
+ return storage.getStore();
21
+ }
22
+
23
+ export function extractToken(req: IncomingMessage): string | undefined {
24
+ const header = req.headers.authorization;
25
+ if (header?.startsWith('Bearer ')) {
26
+ const t = header.slice(7).trim();
27
+ if (t) return t;
28
+ }
29
+ const qt = new URL(req.url ?? '/', 'http://localhost').searchParams.get(
30
+ 'token',
31
+ );
32
+ return qt ?? undefined;
33
+ }
34
+
35
+ export function authenticate(req: IncomingMessage): RequestIdentity | null {
36
+ const token = extractToken(req);
37
+ if (!token) return null;
38
+ const agentId = agentIdForKey(token);
39
+ return agentId === undefined ? null : { kind: 'agent', agentId };
40
+ }
41
+
42
+ export function allowedAgents(
43
+ identity: RequestIdentity | undefined,
44
+ ): Set<string> {
45
+ return identity ? new Set([identity.agentId]) : new Set();
46
+ }
@@ -0,0 +1,48 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { currentBusSeq } from '@metro-labs/core/events';
3
+ import { newReplayLedger } from '../channels/relay.js';
4
+ import { McpSession, channelLog } from './session.js';
5
+ import { allowedAgents, type RequestIdentity } from './request-identity.js';
6
+
7
+ export class SessionSlot {
8
+ private session: McpSession | undefined;
9
+ private readonly ledger = newReplayLedger();
10
+ private started = false;
11
+
12
+ get current(): McpSession | undefined {
13
+ return this.session;
14
+ }
15
+
16
+ startInbound(): void {
17
+ if (this.started) return;
18
+ this.started = true;
19
+ if (this.ledger.startAt < 0) this.ledger.startAt = currentBusSeq();
20
+ this.session?.startChannel();
21
+ }
22
+
23
+ async open(
24
+ identity: RequestIdentity,
25
+ adoptId?: string,
26
+ ): Promise<McpSession> {
27
+ await this.session?.close();
28
+ if (this.ledger.startAt < 0) this.ledger.startAt = currentBusSeq();
29
+ const id = adoptId ?? randomUUID();
30
+ const session = await McpSession.open({
31
+ id,
32
+ scope: allowedAgents(identity),
33
+ adopted: adoptId !== undefined,
34
+ ledger: this.ledger,
35
+ onClosed: (s) => {
36
+ if (this.session === s) this.session = undefined;
37
+ },
38
+ });
39
+ this.session = session;
40
+ if (this.started) session.startChannel();
41
+ channelLog('session: opened', 'id', id, 'adopted', adoptId !== undefined);
42
+ return session;
43
+ }
44
+
45
+ async close(): Promise<void> {
46
+ await this.session?.close();
47
+ }
48
+ }
@@ -1,20 +1,17 @@
1
1
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
2
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
3
3
  import { InboundRelay } from '../channels/inbound.js';
4
+ import { answerPrompt, forgetPromptsOf, promptLine } from '../approvals/pending.js';
4
5
  import { ChannelRelay, type ReplayLedger } from '../channels/relay.js';
5
- import { errMsg } from '../daemon/log.js';
6
- import {
7
- allowlistForLine,
8
- senderMatchesAllowlist,
9
- } from '../db/agent-map.js';
10
- import { accountStationNames } from '../stations/registry.js';
11
- import { MCP_INSTRUCTIONS } from './tool-schemas.js';
12
- import { ChannelOwner } from './channel-owner.js';
6
+ import { errMsg } from '@metro-labs/core/log';
7
+ import { allowlistForLine, mayApprove, senderPermitted } from '../agents/map.js';
8
+ import { accountStationNames, stationByName } from '../stations/registry.js';
9
+ import { eventInScope } from '../agents/scope.js';
10
+ import { MCP_INSTRUCTIONS } from './instructions.js';
13
11
  import { BoundedEventStore } from './event-store.js';
14
12
  import { registerPermissionRelay } from './permission-relay.js';
15
13
  import { registerToolHandlers, toolSchemaSignature } from './tool-dispatch.js';
16
14
  import { web, type RawGetSink } from './raw-get-stream.js';
17
- import type { RequestIdentity } from './request-identity.js';
18
15
 
19
16
  export const channelLog = (...a: unknown[]): void => {
20
17
  console.error('[metro-mcp]', ...a);
@@ -22,10 +19,15 @@ export const channelLog = (...a: unknown[]): void => {
22
19
 
23
20
  const getStations = (): Set<string> => new Set(accountStationNames());
24
21
 
25
- const senderAllowed = (from: string, line: string): boolean => {
26
- const allowlist = allowlistForLine(line);
27
- return allowlist ? senderMatchesAllowlist(allowlist, from) : true;
28
- };
22
+ const senderAllowed = (from: string, line: string, verified?: boolean): boolean =>
23
+ senderPermitted(allowlistForLine(line), from, verified);
24
+
25
+ const approves = (station: string): boolean => stationByName(station)?.approvals !== false;
26
+
27
+ async function answerPermission(requestId: string, behavior: 'allow' | 'deny', line: string, from: string): Promise<boolean> {
28
+ if (promptLine(requestId) !== line || !mayApprove(line, from)) return false;
29
+ return (await answerPrompt(requestId, behavior, 'chat', line)) !== undefined;
30
+ }
29
31
 
30
32
  function makeTransport(
31
33
  id: string,
@@ -47,7 +49,7 @@ function makeTransport(
47
49
 
48
50
  export interface SessionInit {
49
51
  id: string;
50
- scopeKey: string;
52
+ scope: Set<string>;
51
53
  adopted: boolean;
52
54
  ledger: ReplayLedger;
53
55
  onClosed: (session: McpSession) => void;
@@ -55,14 +57,12 @@ export interface SessionInit {
55
57
 
56
58
  export class McpSession {
57
59
  readonly id: string;
58
- readonly scopeKey: string;
59
- readonly owner = new ChannelOwner();
60
+ readonly scope: Set<string>;
60
61
  readonly eventStore: BoundedEventStore;
61
62
  readonly transport: StreamableHTTPServerTransport;
62
63
  readonly server: Server;
63
64
  readonly relay: InboundRelay;
64
65
  readonly channel: ChannelRelay;
65
- lastSeenAt = Date.now();
66
66
  private sink: RawGetSink | undefined;
67
67
  private unsubscribe: (() => void) | undefined;
68
68
  private closed = false;
@@ -72,12 +72,10 @@ export class McpSession {
72
72
 
73
73
  private constructor(init: SessionInit) {
74
74
  this.id = init.id;
75
- this.scopeKey = init.scopeKey;
75
+ this.scope = init.scope;
76
76
  this.issuedSchema = init.adopted ? undefined : toolSchemaSignature();
77
77
  this.onClosed = init.onClosed;
78
- this.eventStore = new BoundedEventStore({
79
- scopeOf: () => this.owner.scope(),
80
- });
78
+ this.eventStore = new BoundedEventStore();
81
79
  this.transport = makeTransport(init.id, this.eventStore, init.adopted);
82
80
  this.server = new Server(
83
81
  { name: 'metro', version: '0.1.0' },
@@ -99,23 +97,29 @@ export class McpSession {
99
97
  deliver: (send): void => {
100
98
  this.deliverSchemaNotice(send, 'request');
101
99
  },
100
+ }, {
101
+ onSent: (id): void => {
102
+ this.relay.noteSent(id);
103
+ },
102
104
  });
103
105
  this.relay = new InboundRelay({
104
106
  mcp: this.server,
105
107
  log: channelLog,
106
108
  getStations,
107
109
  senderAllowed,
110
+ approves,
111
+ answerPermission,
108
112
  });
109
113
  registerPermissionRelay({
110
114
  mcp: this.server,
111
115
  relay: this.relay,
112
- owner: this.owner,
116
+ inScope: (line) => this.inScope(line),
113
117
  log: channelLog,
114
118
  });
115
119
  this.channel = new ChannelRelay({
116
120
  relay: this.relay,
117
121
  log: channelLog,
118
- inScope: (line) => this.owner.inScope(line),
122
+ inScope: (line) => this.inScope(line),
119
123
  ledger: init.ledger,
120
124
  });
121
125
  }
@@ -139,22 +143,17 @@ export class McpSession {
139
143
  return this.sink;
140
144
  }
141
145
 
142
- touch(): void {
143
- this.lastSeenAt = Date.now();
146
+ inScope(line: string): boolean {
147
+ return this.streamAttached && eventInScope(this.scope, line);
144
148
  }
145
149
 
146
150
  startChannel(): void {
147
151
  this.unsubscribe ??= this.channel.start();
148
152
  }
149
153
 
150
- bindSink(sink: RawGetSink | undefined, identity: RequestIdentity): void {
154
+ bindSink(sink: RawGetSink | undefined): void {
151
155
  this.sink = sink;
152
- if (sink === undefined) {
153
- this.owner.releaseStream();
154
- return;
155
- }
156
- this.owner.bindStream(identity);
157
- this.announceToolSchema();
156
+ if (sink !== undefined) this.announceToolSchema();
158
157
  }
159
158
 
160
159
  private get schemaNoticeDue(): boolean {
@@ -172,15 +171,7 @@ export class McpSession {
172
171
  private deliverSchemaNotice(send: () => Promise<void>, via: string): void {
173
172
  if (!this.schemaNoticeDue || this.announcing) return;
174
173
  this.announcing = true;
175
- channelLog(
176
- 'session: tool list changed',
177
- 'id',
178
- this.id,
179
- 'scope',
180
- this.scopeKey,
181
- 'via',
182
- via,
183
- );
174
+ channelLog('session: tool list changed', 'id', this.id, 'via', via);
184
175
  send()
185
176
  .then(() => {
186
177
  this.issuedSchema = toolSchemaSignature();
@@ -195,7 +186,6 @@ export class McpSession {
195
186
  dropStream(): void {
196
187
  const sink = this.sink;
197
188
  this.sink = undefined;
198
- this.owner.releaseStream();
199
189
  sink?.close();
200
190
  }
201
191
 
@@ -203,6 +193,7 @@ export class McpSession {
203
193
  if (this.closed) return;
204
194
  this.closed = true;
205
195
  this.onClosed(this);
196
+ forgetPromptsOf(this.server);
206
197
  this.dropStream();
207
198
  this.unsubscribe?.();
208
199
  this.unsubscribe = undefined;
@@ -0,0 +1,88 @@
1
+ import type { GroupOp, Station, StationTool, ToolGroup } from '@metro-labs/core/stations/types';
2
+ import { STATIONS } from '../stations/registry.js';
3
+ import { COMMON_TOOLS, LIST_ACCOUNTS_TOOL } from './tool-schemas.js';
4
+ import { SET_PROFILE_TOOL } from './profile-tool.js';
5
+ import { GET_PROFILE_TOOL } from './profile-lookup.js';
6
+ import type { ToolDef } from './tool-def.js';
7
+
8
+ const defOf = (tool: StationTool): ToolDef => ({
9
+ name: tool.name,
10
+ description: tool.description,
11
+ inputSchema: tool.inputSchema,
12
+ ...(tool.group === undefined ? {} : { group: tool.group }),
13
+ ...(tool.destructive === true ? { destructive: true } : {}),
14
+ });
15
+
16
+ export const TOOL_DEFS: ToolDef[] = [
17
+ ...COMMON_TOOLS,
18
+ ...STATIONS.flatMap((s) => s.tools.map(defOf)),
19
+ LIST_ACCOUNTS_TOOL,
20
+ SET_PROFILE_TOOL,
21
+ GET_PROFILE_TOOL,
22
+ ];
23
+
24
+ const BY_NAME = new Map(TOOL_DEFS.map((d) => [d.name, d] as const));
25
+
26
+ export const declaredGroup = (name: string): ToolGroup | undefined => BY_NAME.get(name)?.group;
27
+
28
+ export const toolGroupOf = (name: string): ToolGroup => declaredGroup(name) ?? 'write';
29
+
30
+ export interface ToolAnnotations {
31
+ readOnlyHint: boolean;
32
+ destructiveHint?: boolean;
33
+ }
34
+
35
+ export interface PublishedTool {
36
+ name: string;
37
+ description: string;
38
+ inputSchema: Record<string, unknown>;
39
+ annotations: ToolAnnotations;
40
+ }
41
+
42
+ const annotationsOf = (def: ToolDef): ToolAnnotations =>
43
+ toolGroupOf(def.name) === 'read'
44
+ ? { readOnlyHint: true }
45
+ : { readOnlyHint: false, destructiveHint: def.destructive === true };
46
+
47
+ export const listedTools = (): PublishedTool[] =>
48
+ TOOL_DEFS.map((def) => ({
49
+ name: def.name,
50
+ description: def.description,
51
+ inputSchema: def.inputSchema,
52
+ annotations: annotationsOf(def),
53
+ }));
54
+
55
+ const STATION_OF_TOOL = new Map(STATIONS.flatMap((s) => s.tools.map((t) => [t.name, s.name] as const)));
56
+
57
+ export const stationToolOwners = (): Record<string, string> => Object.fromEntries(STATION_OF_TOOL);
58
+
59
+ export function stationForTool(name: string, args: Record<string, unknown>): string | undefined {
60
+ if (name === 'create_group' || name === 'set_profile')
61
+ return typeof args.station === 'string' && args.station !== '' ? args.station : undefined;
62
+ return STATION_OF_TOOL.get(name);
63
+ }
64
+
65
+ const GROUP_OP_TOOLS: Record<GroupOp, string> = {
66
+ create_group: 'create_group',
67
+ add_members: 'add_members',
68
+ remove_members: 'remove_members',
69
+ invite_link: 'export_invite',
70
+ };
71
+
72
+ export interface GroupedTool {
73
+ name: string;
74
+ group: ToolGroup;
75
+ }
76
+
77
+ export const stationToolGroups = (): Record<string, GroupedTool[]> =>
78
+ Object.fromEntries(STATIONS.filter((s) => s.hasAccounts).map((s) => [s.name, channelToolsOf(s)]));
79
+
80
+ export function channelToolsOf(station: Station): GroupedTool[] {
81
+ const names: string[] = [...station.messageVerbs];
82
+ if (station.hasTrain && station.hasAccounts) names.push('list_members');
83
+ for (const op of station.groupOps ?? []) names.push(GROUP_OP_TOOLS[op]);
84
+ if ((station.profileFields?.size ?? 0) > 0) names.push('set_profile');
85
+ if (station.readsProfiles === true) names.push('get_profile');
86
+ names.push(...station.tools.map((t) => t.name));
87
+ return names.map((name) => ({ name, group: toolGroupOf(name) }));
88
+ }
@@ -0,0 +1,9 @@
1
+ import type { ToolGroup } from '@metro-labs/core/stations/types';
2
+
3
+ export interface ToolDef {
4
+ name: string;
5
+ description: string;
6
+ inputSchema: Record<string, unknown>;
7
+ group?: ToolGroup;
8
+ destructive?: boolean;
9
+ }