@stage-labs/metro 0.1.0-beta.20 → 0.1.0-beta.201

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 (442) hide show
  1. package/dist/api.js +9 -101
  2. package/dist/claude-settings.js +40 -0
  3. package/dist/claude.js +163 -0
  4. package/dist/cli.js +50 -109
  5. package/dist/control.js +47 -75
  6. package/dist/hold.js +211 -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 +97 -0
  14. package/dist/runtime.js +32 -52
  15. package/dist/serve.js +158 -0
  16. package/dist/service.js +243 -0
  17. package/dist/tail.js +119 -0
  18. package/dist/update.js +13 -1
  19. package/package.json +1 -22
  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 +24 -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 +8 -6
  32. package/runtime/node_modules/@metro-labs/core/src/identity.ts +7 -0
  33. package/runtime/node_modules/@metro-labs/{mcp/src/db → core/src}/ids.ts +5 -0
  34. package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
  35. package/runtime/node_modules/@metro-labs/{mcp/src/stations → core/src}/lines.ts +12 -3
  36. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/protocol.ts +7 -4
  37. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/secure-fs.ts +17 -0
  38. package/runtime/node_modules/@metro-labs/core/src/station-names.ts +13 -0
  39. package/runtime/node_modules/@metro-labs/core/src/stations/account-files.ts +41 -0
  40. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/account-store.ts +4 -24
  41. package/runtime/node_modules/@metro-labs/core/src/stations/profile.ts +58 -0
  42. package/runtime/node_modules/@metro-labs/core/src/stations/sender-profile.ts +64 -0
  43. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/station-runtime.ts +3 -6
  44. package/runtime/node_modules/@metro-labs/core/src/stations/train-boot.ts +42 -0
  45. package/runtime/node_modules/@metro-labs/core/src/stations/train-events.ts +89 -0
  46. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/types.ts +16 -0
  47. package/runtime/node_modules/@metro-labs/core/src/tickets.ts +37 -0
  48. package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
  49. package/runtime/node_modules/@metro-labs/daemon/package.json +48 -0
  50. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/agent-fs.ts +134 -0
  51. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files-api.ts +12 -0
  52. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files.ts +119 -0
  53. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/home-fs.ts +113 -0
  54. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/job-env.ts +51 -0
  55. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/provision.ts +99 -0
  56. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedule-detail.ts +100 -0
  57. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules-api.ts +27 -0
  58. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules.ts +252 -0
  59. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/unit-files.ts +61 -0
  60. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/user.ts +91 -0
  61. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/view.ts +87 -0
  62. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-attach.ts +19 -0
  63. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-lookups.ts +55 -0
  64. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-routes.ts +76 -0
  65. package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +357 -0
  66. package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +30 -0
  67. package/runtime/node_modules/@metro-labs/daemon/src/agents/allowlist.ts +59 -0
  68. package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +131 -0
  69. package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +132 -0
  70. package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +305 -0
  71. package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +168 -0
  72. package/runtime/node_modules/@metro-labs/{mcp/src/db/key-map.ts → daemon/src/agents/keys.ts} +1 -11
  73. package/runtime/node_modules/@metro-labs/{mcp/src/db/agent-map.ts → daemon/src/agents/map.ts} +58 -1
  74. package/runtime/node_modules/@metro-labs/daemon/src/agents/policy-route.ts +27 -0
  75. package/runtime/node_modules/@metro-labs/{mcp/src/db/agent-scope.ts → daemon/src/agents/scope.ts} +2 -2
  76. package/runtime/node_modules/@metro-labs/daemon/src/agents/sender-cards.ts +86 -0
  77. package/runtime/node_modules/@metro-labs/daemon/src/agents/senders.ts +38 -0
  78. package/runtime/node_modules/@metro-labs/daemon/src/approvals/api.ts +55 -0
  79. package/runtime/node_modules/@metro-labs/daemon/src/approvals/needs.ts +2 -0
  80. package/runtime/node_modules/@metro-labs/daemon/src/approvals/pending.ts +149 -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 +221 -0
  83. package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +39 -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/daemon/src/channels/dedupe.ts +12 -0
  89. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/inbound.ts +47 -44
  90. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/media-note.ts +9 -4
  91. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/pending.ts +4 -1
  92. package/runtime/node_modules/@metro-labs/daemon/src/channels/react-note.ts +13 -0
  93. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/relay.ts +2 -2
  94. package/runtime/node_modules/@metro-labs/daemon/src/channels/reply-id.ts +1 -0
  95. package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +355 -0
  96. package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +359 -0
  97. package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +208 -0
  98. package/runtime/node_modules/@metro-labs/daemon/src/claude/memory.ts +82 -0
  99. package/runtime/node_modules/@metro-labs/daemon/src/claude/onboarding.ts +60 -0
  100. package/runtime/node_modules/@metro-labs/daemon/src/claude/plugin-install.ts +149 -0
  101. package/runtime/node_modules/@metro-labs/daemon/src/claude/session-files.ts +75 -0
  102. package/runtime/node_modules/@metro-labs/daemon/src/claude/session.ts +283 -0
  103. package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +109 -0
  104. package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +271 -0
  105. package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +120 -0
  106. package/runtime/node_modules/@metro-labs/daemon/src/claude/version.ts +113 -0
  107. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-api.ts → daemon/src/connectors/api.ts} +77 -109
  108. package/runtime/node_modules/@metro-labs/{mcp/src/db/connector-config.ts → daemon/src/connectors/config.ts} +55 -26
  109. package/runtime/node_modules/@metro-labs/daemon/src/connectors/gates.ts +72 -0
  110. package/runtime/node_modules/@metro-labs/daemon/src/connectors/health.ts +18 -0
  111. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-client.ts +14 -17
  112. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-discovery.ts +28 -13
  113. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth-routes.ts → daemon/src/connectors/oauth-routes.ts} +30 -29
  114. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth.ts → daemon/src/connectors/oauth.ts} +61 -22
  115. package/runtime/node_modules/@metro-labs/daemon/src/connectors/plugin-sync.ts +131 -0
  116. package/runtime/node_modules/@metro-labs/daemon/src/connectors/reach.ts +27 -0
  117. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-policy.ts +90 -0
  118. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-target.ts +29 -0
  119. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +348 -0
  120. package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +358 -0
  121. package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +81 -0
  122. package/runtime/node_modules/@metro-labs/daemon/src/connectors/url.ts +37 -0
  123. package/runtime/node_modules/@metro-labs/daemon/src/connectors/verify.ts +106 -0
  124. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-grant.ts +4 -4
  125. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-owner.ts +3 -3
  126. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-reaper.ts +174 -0
  127. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-serve.ts +11 -12
  128. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-api.ts +10 -27
  129. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-store.ts +2 -2
  130. package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +233 -0
  131. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +208 -0
  132. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-device.ts +91 -0
  133. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +173 -0
  134. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +194 -0
  135. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +137 -0
  136. package/runtime/node_modules/@metro-labs/daemon/src/gateway/effort.ts +77 -0
  137. package/runtime/node_modules/@metro-labs/daemon/src/gateway/eventstream.ts +123 -0
  138. package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +237 -0
  139. package/runtime/node_modules/@metro-labs/daemon/src/gateway/frames.ts +118 -0
  140. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +274 -0
  141. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-auth.ts +160 -0
  142. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-client.ts +46 -0
  143. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-setup.ts +150 -0
  144. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-stream.ts +139 -0
  145. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-translate.ts +223 -0
  146. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini.ts +208 -0
  147. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +199 -0
  148. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +299 -0
  149. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-signin.ts +193 -0
  150. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-store.ts +70 -0
  151. package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +90 -0
  152. package/runtime/node_modules/@metro-labs/daemon/src/gateway/pkce.ts +36 -0
  153. package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +66 -0
  154. package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +18 -0
  155. package/runtime/node_modules/@metro-labs/daemon/src/gateway/subscription.ts +120 -0
  156. package/runtime/node_modules/@metro-labs/daemon/src/gateway/text.ts +15 -0
  157. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +244 -0
  158. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/accounts.ts +59 -18
  159. package/runtime/node_modules/@metro-labs/daemon/src/mcp/attachment-schema.ts +91 -0
  160. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/call-tools.ts +43 -20
  161. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/ctx.ts +4 -4
  162. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/event-store.ts +15 -16
  163. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/group-tools.ts +2 -2
  164. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/index.ts +24 -79
  165. package/runtime/node_modules/@metro-labs/daemon/src/mcp/instructions.ts +19 -0
  166. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/member-tools.ts +2 -2
  167. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-prompt.ts +87 -0
  168. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +79 -0
  169. package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-gate.ts +83 -0
  170. package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-snapshot.ts +79 -0
  171. package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-lookup.ts +60 -0
  172. package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-tool.ts +96 -0
  173. package/runtime/node_modules/@metro-labs/daemon/src/mcp/read-tool.ts +87 -0
  174. package/runtime/node_modules/@metro-labs/daemon/src/mcp/request-identity.ts +46 -0
  175. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-slot.ts +48 -0
  176. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/session.ts +33 -42
  177. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-catalog.ts +88 -0
  178. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-def.ts +9 -0
  179. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-dispatch.ts +53 -40
  180. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-schemas.ts +55 -119
  181. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/upload-tool.ts +6 -11
  182. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/api.ts +43 -0
  183. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/helper-script.ts +126 -0
  184. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/move.ts +165 -0
  185. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/privilege.ts +48 -0
  186. package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +132 -0
  187. package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +316 -0
  188. package/runtime/node_modules/@metro-labs/daemon/src/policy/policy.ts +118 -0
  189. package/runtime/node_modules/@metro-labs/daemon/src/routes/bearer.ts +35 -0
  190. package/runtime/node_modules/@metro-labs/daemon/src/routes/body.ts +24 -0
  191. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/routes}/http.ts +59 -51
  192. package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +208 -0
  193. package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +71 -0
  194. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/session-api.ts → daemon/src/routes/session.ts} +9 -7
  195. package/runtime/node_modules/@metro-labs/daemon/src/routes/threema-callback.ts +103 -0
  196. package/runtime/node_modules/@metro-labs/daemon/src/server/control.ts +39 -0
  197. package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +58 -0
  198. package/runtime/node_modules/@metro-labs/daemon/src/server/owner.ts +26 -0
  199. package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +90 -0
  200. package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
  201. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-driver.ts +42 -0
  202. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-inline.ts +29 -1
  203. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-interactive.ts +9 -36
  204. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-outlook.ts +63 -0
  205. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-resolve.ts +38 -13
  206. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/attach-session.ts +30 -20
  207. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-xmtp.ts +2 -2
  208. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach.ts +75 -9
  209. package/runtime/node_modules/@metro-labs/daemon/src/stations/materialize.ts +265 -0
  210. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/registry.ts +22 -6
  211. package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +82 -0
  212. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor-io.ts +2 -2
  213. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor.ts +5 -8
  214. package/runtime/node_modules/@metro-labs/daemon/src/stations/threema-callbacks.ts +32 -0
  215. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/train-call.ts +1 -1
  216. package/runtime/node_modules/@metro-labs/daemon/src/stations/webhook-endpoints.ts +51 -0
  217. package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +84 -0
  218. package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +124 -0
  219. package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +15 -0
  220. package/runtime/node_modules/@metro-labs/daemon/src/vault/api.ts +45 -0
  221. package/runtime/node_modules/@metro-labs/daemon/src/vault/config.ts +51 -0
  222. package/runtime/node_modules/@metro-labs/daemon/src/vault/firewall.ts +48 -0
  223. package/runtime/node_modules/@metro-labs/daemon/src/vault/index.ts +96 -0
  224. package/runtime/node_modules/@metro-labs/daemon/src/vault/install.ts +56 -0
  225. package/runtime/node_modules/@metro-labs/daemon/src/vault/paths.ts +26 -0
  226. package/runtime/node_modules/@metro-labs/daemon/src/vault/proxy.ts +148 -0
  227. package/runtime/node_modules/@metro-labs/daemon/src/vault/store.ts +130 -0
  228. package/runtime/node_modules/@metro-labs/daemon/src/vault/trust.ts +61 -0
  229. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/package.json +3 -5
  230. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/accounts.ts +11 -13
  231. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/actions.ts +6 -154
  232. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/attachments.ts +3 -3
  233. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/format.ts +28 -64
  234. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/group-actions.ts +1 -1
  235. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/group.ts +2 -2
  236. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/index.ts +14 -19
  237. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/members.ts +2 -2
  238. package/runtime/node_modules/@metro-labs/discord-bot/src/profile.ts +68 -0
  239. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/send-files.ts +1 -1
  240. package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +22 -0
  241. package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +1 -0
  242. package/runtime/node_modules/@metro-labs/http/package.json +29 -0
  243. package/runtime/node_modules/@metro-labs/http/src/api-http.ts +138 -0
  244. package/runtime/node_modules/@metro-labs/http/src/mode-api.ts +32 -0
  245. package/runtime/node_modules/@metro-labs/http/src/return-to.ts +21 -0
  246. package/runtime/node_modules/@metro-labs/http/src/workos-token.ts +149 -0
  247. package/runtime/node_modules/@metro-labs/{telegram-user → outlook}/package.json +2 -5
  248. package/runtime/node_modules/@metro-labs/outlook/src/accounts.ts +107 -0
  249. package/runtime/node_modules/@metro-labs/outlook/src/actions.ts +20 -0
  250. package/runtime/node_modules/@metro-labs/outlook/src/attachments.ts +97 -0
  251. package/runtime/node_modules/@metro-labs/outlook/src/auth.ts +150 -0
  252. package/runtime/node_modules/@metro-labs/outlook/src/browser.ts +53 -0
  253. package/runtime/node_modules/@metro-labs/outlook/src/config.ts +36 -0
  254. package/runtime/node_modules/@metro-labs/outlook/src/format.ts +141 -0
  255. package/runtime/node_modules/@metro-labs/outlook/src/graph.ts +60 -0
  256. package/runtime/node_modules/@metro-labs/outlook/src/html.ts +72 -0
  257. package/runtime/node_modules/@metro-labs/outlook/src/inbound.ts +104 -0
  258. package/runtime/node_modules/@metro-labs/outlook/src/index.ts +12 -0
  259. package/runtime/node_modules/@metro-labs/outlook/src/login.ts +150 -0
  260. package/runtime/node_modules/@metro-labs/outlook/src/me.ts +41 -0
  261. package/runtime/node_modules/@metro-labs/outlook/src/outbound.ts +116 -0
  262. package/runtime/node_modules/@metro-labs/outlook/src/query.ts +119 -0
  263. package/runtime/node_modules/@metro-labs/outlook/src/state.ts +43 -0
  264. package/runtime/node_modules/@metro-labs/outlook/src/station.ts +15 -0
  265. package/runtime/node_modules/@metro-labs/outlook/src/trust.ts +70 -0
  266. package/runtime/node_modules/@metro-labs/telegram/package.json +3 -2
  267. package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +48 -88
  268. package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +214 -253
  269. package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +67 -108
  270. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/client.ts +6 -6
  271. package/runtime/node_modules/@metro-labs/telegram/src/format.ts +102 -146
  272. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/group.ts +4 -4
  273. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/history.ts +1 -1
  274. package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +57 -0
  275. package/runtime/node_modules/@metro-labs/telegram/src/index.ts +6 -102
  276. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/login.ts +20 -20
  277. package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +65 -151
  278. package/runtime/node_modules/@metro-labs/telegram/src/members.ts +61 -33
  279. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/normalize.ts +1 -1
  280. package/runtime/node_modules/@metro-labs/telegram/src/profile.ts +70 -0
  281. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/reactions.ts +2 -2
  282. package/runtime/node_modules/@metro-labs/telegram/src/station.ts +11 -1
  283. package/runtime/node_modules/@metro-labs/telegram/src/types.ts +5 -47
  284. package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +1 -3
  285. package/runtime/node_modules/@metro-labs/telegram-bot/package.json +25 -0
  286. package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +119 -0
  287. package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +246 -0
  288. package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +128 -0
  289. package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +173 -0
  290. package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +103 -0
  291. package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +95 -0
  292. package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +47 -0
  293. package/runtime/node_modules/@metro-labs/telegram-bot/src/profile.ts +65 -0
  294. package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +20 -0
  295. package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +56 -0
  296. package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +1 -0
  297. package/runtime/node_modules/@metro-labs/threema/package.json +26 -0
  298. package/runtime/node_modules/@metro-labs/threema/src/accounts.ts +106 -0
  299. package/runtime/node_modules/@metro-labs/threema/src/actions.ts +134 -0
  300. package/runtime/node_modules/@metro-labs/threema/src/api.ts +152 -0
  301. package/runtime/node_modules/@metro-labs/threema/src/crypto.ts +100 -0
  302. package/runtime/node_modules/@metro-labs/threema/src/files.ts +58 -0
  303. package/runtime/node_modules/@metro-labs/threema/src/format.ts +169 -0
  304. package/runtime/node_modules/@metro-labs/threema/src/groups.ts +96 -0
  305. package/runtime/node_modules/@metro-labs/threema/src/ids.ts +21 -0
  306. package/runtime/node_modules/@metro-labs/threema/src/inbound.ts +89 -0
  307. package/runtime/node_modules/@metro-labs/threema/src/index.ts +24 -0
  308. package/runtime/node_modules/@metro-labs/threema/src/messages.ts +264 -0
  309. package/runtime/node_modules/@metro-labs/threema/src/outbound.ts +160 -0
  310. package/runtime/node_modules/@metro-labs/threema/src/station.ts +13 -0
  311. package/runtime/node_modules/@metro-labs/threema/src/verify.ts +117 -0
  312. package/runtime/node_modules/@metro-labs/webhook/package.json +1 -1
  313. package/runtime/node_modules/@metro-labs/webhook/src/station.ts +5 -8
  314. package/runtime/node_modules/@metro-labs/whatsapp/package.json +1 -3
  315. package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +1 -2
  316. package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +1 -1
  317. package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +40 -5
  318. package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +2 -2
  319. package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +1 -1
  320. package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +74 -4
  321. package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +7 -56
  322. package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +10 -27
  323. package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +4 -37
  324. package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +1 -1
  325. package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +1 -1
  326. package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +1 -1
  327. package/runtime/node_modules/@metro-labs/whatsapp/src/names.ts +28 -0
  328. package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +1 -1
  329. package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +44 -0
  330. package/runtime/node_modules/@metro-labs/whatsapp/src/resolve.ts +52 -0
  331. package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +8 -1
  332. package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +5 -9
  333. package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +0 -1
  334. package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +1 -5
  335. package/runtime/node_modules/@metro-labs/xmtp/package.json +3 -2
  336. package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +9 -8
  337. package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +1 -1
  338. package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +3 -201
  339. package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +3 -42
  340. package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +12 -143
  341. package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +3 -3
  342. package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +3 -3
  343. package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +7 -24
  344. package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +7 -16
  345. package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +1 -1
  346. package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +2 -2
  347. package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +30 -16
  348. package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +11 -14
  349. package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +1 -19
  350. package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +1 -1
  351. package/runtime/node_modules/@metro-labs/xmtp/src/names.ts +61 -0
  352. package/runtime/node_modules/@metro-labs/xmtp/src/profile.ts +153 -0
  353. package/runtime/node_modules/@metro-labs/xmtp/src/sender.ts +112 -0
  354. package/runtime/node_modules/@metro-labs/xmtp/src/smart.ts +72 -0
  355. package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +5 -1
  356. package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +3 -50
  357. package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +30 -44
  358. package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +4 -6
  359. package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +19 -5
  360. package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +15 -3
  361. package/runtime/runtime.json +1 -1
  362. package/runtime/server.ts +1 -0
  363. package/runtime/stations.json +37 -0
  364. package/dist/prompt.js +0 -10
  365. package/dist/store.js +0 -70
  366. package/runtime/node_modules/@metro-labs/discord/src/station.ts +0 -19
  367. package/runtime/node_modules/@metro-labs/discord/src/voice-speak.ts +0 -195
  368. package/runtime/node_modules/@metro-labs/discord/src/voice-transcribe.ts +0 -292
  369. package/runtime/node_modules/@metro-labs/discord/src/voice.ts +0 -197
  370. package/runtime/node_modules/@metro-labs/discord/src/wire.ts +0 -5
  371. package/runtime/node_modules/@metro-labs/mcp/package.json +0 -66
  372. package/runtime/node_modules/@metro-labs/mcp/src/channels/dedupe.ts +0 -24
  373. package/runtime/node_modules/@metro-labs/mcp/src/daemon/account-api.ts +0 -311
  374. package/runtime/node_modules/@metro-labs/mcp/src/daemon/agent-api.ts +0 -335
  375. package/runtime/node_modules/@metro-labs/mcp/src/daemon/api-http.ts +0 -129
  376. package/runtime/node_modules/@metro-labs/mcp/src/daemon/boot.ts +0 -322
  377. package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair-api.ts +0 -111
  378. package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair.ts +0 -20
  379. package/runtime/node_modules/@metro-labs/mcp/src/daemon/collection-api.ts +0 -202
  380. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-json.ts +0 -31
  381. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-tools.ts +0 -100
  382. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-url.ts +0 -57
  383. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-verify.ts +0 -333
  384. package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-auth.ts +0 -164
  385. package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-oauth.ts +0 -208
  386. package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity.ts +0 -79
  387. package/runtime/node_modules/@metro-labs/mcp/src/daemon/oauth-pending.ts +0 -65
  388. package/runtime/node_modules/@metro-labs/mcp/src/daemon/pair-codes.ts +0 -58
  389. package/runtime/node_modules/@metro-labs/mcp/src/daemon/project-api.ts +0 -214
  390. package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-api.ts +0 -125
  391. package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-pair.ts +0 -18
  392. package/runtime/node_modules/@metro-labs/mcp/src/daemon/runtime-source.ts +0 -105
  393. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session-apis.ts +0 -41
  394. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session.ts +0 -218
  395. package/runtime/node_modules/@metro-labs/mcp/src/daemon/tunnel.ts +0 -169
  396. package/runtime/node_modules/@metro-labs/mcp/src/db/account-attach.ts +0 -91
  397. package/runtime/node_modules/@metro-labs/mcp/src/db/agent-admin.ts +0 -215
  398. package/runtime/node_modules/@metro-labs/mcp/src/db/client.ts +0 -37
  399. package/runtime/node_modules/@metro-labs/mcp/src/db/connector-collections.ts +0 -218
  400. package/runtime/node_modules/@metro-labs/mcp/src/db/connectors.ts +0 -329
  401. package/runtime/node_modules/@metro-labs/mcp/src/db/materialize.ts +0 -340
  402. package/runtime/node_modules/@metro-labs/mcp/src/db/projects.ts +0 -300
  403. package/runtime/node_modules/@metro-labs/mcp/src/db/runtime-admin.ts +0 -28
  404. package/runtime/node_modules/@metro-labs/mcp/src/db/runtimes.ts +0 -105
  405. package/runtime/node_modules/@metro-labs/mcp/src/db/schema.ts +0 -131
  406. package/runtime/node_modules/@metro-labs/mcp/src/db/token-carry.ts +0 -45
  407. package/runtime/node_modules/@metro-labs/mcp/src/db/users.ts +0 -57
  408. package/runtime/node_modules/@metro-labs/mcp/src/db/whatsapp-login.ts +0 -18
  409. package/runtime/node_modules/@metro-labs/mcp/src/mcp/channel-owner.ts +0 -29
  410. package/runtime/node_modules/@metro-labs/mcp/src/mcp/frame-scope.ts +0 -21
  411. package/runtime/node_modules/@metro-labs/mcp/src/mcp/permission-relay.ts +0 -66
  412. package/runtime/node_modules/@metro-labs/mcp/src/mcp/request-identity.ts +0 -73
  413. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-registry.ts +0 -172
  414. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-route.ts +0 -43
  415. package/runtime/node_modules/@metro-labs/mcp/src/monitor/api.ts +0 -240
  416. package/runtime/node_modules/@metro-labs/mcp/src/server.ts +0 -2
  417. package/runtime/node_modules/@metro-labs/telegram-user/src/accounts.ts +0 -81
  418. package/runtime/node_modules/@metro-labs/telegram-user/src/actions.ts +0 -254
  419. package/runtime/node_modules/@metro-labs/telegram-user/src/attachments.ts +0 -87
  420. package/runtime/node_modules/@metro-labs/telegram-user/src/format.ts +0 -141
  421. package/runtime/node_modules/@metro-labs/telegram-user/src/inbound.ts +0 -78
  422. package/runtime/node_modules/@metro-labs/telegram-user/src/index.ts +0 -46
  423. package/runtime/node_modules/@metro-labs/telegram-user/src/media-actions.ts +0 -80
  424. package/runtime/node_modules/@metro-labs/telegram-user/src/members.ts +0 -75
  425. package/runtime/node_modules/@metro-labs/telegram-user/src/station.ts +0 -24
  426. package/runtime/node_modules/@metro-labs/telegram-user/src/types.ts +0 -7
  427. package/runtime/node_modules/@metro-labs/telegram-user/src/wire.ts +0 -1
  428. package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +0 -87
  429. package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +0 -55
  430. package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +0 -349
  431. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/log.ts +0 -0
  432. /package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/attachments.ts +0 -0
  433. /package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/messaging-normalize.ts +0 -0
  434. /package/runtime/node_modules/@metro-labs/{mcp/src/mcp → core/src}/str.ts +0 -0
  435. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/train-error.ts +0 -0
  436. /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/webhook-note.ts +0 -0
  437. /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/raw-get-stream.ts +0 -0
  438. /package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/api-base.ts +0 -0
  439. /package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/verify.ts +0 -0
  440. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/api-error.ts +0 -0
  441. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/cors.ts +0 -0
  442. /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 < 0 || 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: at === 0 ? 'default' : 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
+ export 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
+ export 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
+ }