@stage-labs/metro 0.1.0-beta.23 → 0.1.0-beta.231

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (457) hide show
  1. package/dist/api.js +9 -101
  2. package/dist/background.js +123 -0
  3. package/dist/claude-settings.js +40 -0
  4. package/dist/claude.js +197 -0
  5. package/dist/cli.js +52 -110
  6. package/dist/control.js +19 -103
  7. package/dist/hold.js +210 -0
  8. package/dist/local.js +43 -0
  9. package/dist/mcp-config.js +25 -0
  10. package/dist/memory.js +222 -0
  11. package/dist/node-name.js +71 -0
  12. package/dist/onboarding.js +44 -0
  13. package/dist/provider-flags.js +9 -0
  14. package/dist/route.js +58 -0
  15. package/dist/runtime-install.js +96 -0
  16. package/dist/runtime.js +29 -52
  17. package/dist/serve.js +157 -0
  18. package/dist/service.js +304 -0
  19. package/dist/tail.js +119 -0
  20. package/dist/update.js +13 -1
  21. package/package.json +2 -23
  22. package/runtime/marketplace/.claude-plugin/marketplace.json +12 -0
  23. package/runtime/marketplace/plugin/.claude-plugin/plugin.json +17 -0
  24. package/runtime/marketplace/plugin/.mcp.json +1 -0
  25. package/runtime/marketplace/plugin/MEMORY.md +78 -0
  26. package/runtime/marketplace/plugin/METRO.md +26 -0
  27. package/runtime/marketplace/plugin/STAGE.md +42 -0
  28. package/runtime/marketplace/plugin/bin/guard.mjs +71 -0
  29. package/runtime/marketplace/plugin/bin/metro-plugin.mjs +30 -0
  30. package/runtime/marketplace/plugin/bin/policy.mjs +97 -0
  31. package/runtime/marketplace/plugin/bin/session-start.mjs +31 -0
  32. package/runtime/marketplace/plugin/hooks/hooks.json +25 -0
  33. package/runtime/node_modules/@metro-labs/core/package.json +51 -0
  34. package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
  35. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/events.ts +11 -7
  36. package/runtime/node_modules/@metro-labs/{mcp/src/db → core/src}/ids.ts +5 -0
  37. package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
  38. package/runtime/node_modules/@metro-labs/{mcp/src/stations → core/src}/lines.ts +22 -26
  39. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/protocol.ts +7 -4
  40. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/secure-fs.ts +17 -0
  41. package/runtime/node_modules/@metro-labs/core/src/station-names.ts +14 -0
  42. package/runtime/node_modules/@metro-labs/core/src/stations/account-files.ts +41 -0
  43. package/runtime/node_modules/@metro-labs/core/src/stations/account-store.ts +83 -0
  44. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/attachments.ts +0 -1
  45. package/runtime/node_modules/@metro-labs/core/src/stations/mail-text.ts +72 -0
  46. package/runtime/node_modules/@metro-labs/core/src/stations/mail-trust.ts +29 -0
  47. package/runtime/node_modules/@metro-labs/core/src/stations/mail.ts +212 -0
  48. package/runtime/node_modules/@metro-labs/core/src/stations/messaging-normalize.ts +16 -0
  49. package/runtime/node_modules/@metro-labs/core/src/stations/oauth.ts +126 -0
  50. package/runtime/node_modules/@metro-labs/core/src/stations/profile.ts +58 -0
  51. package/runtime/node_modules/@metro-labs/core/src/stations/sender-profile.ts +64 -0
  52. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/station-runtime.ts +6 -11
  53. package/runtime/node_modules/@metro-labs/core/src/stations/train-boot.ts +42 -0
  54. package/runtime/node_modules/@metro-labs/core/src/stations/train-events.ts +84 -0
  55. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/types.ts +18 -1
  56. package/runtime/node_modules/@metro-labs/core/src/tickets.ts +37 -0
  57. package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
  58. package/runtime/node_modules/@metro-labs/daemon/package.json +49 -0
  59. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/agent-fs.ts +134 -0
  60. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/crontab.ts +44 -0
  61. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files-api.ts +12 -0
  62. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files.ts +89 -0
  63. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/home-fs.ts +113 -0
  64. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/job-env.ts +39 -0
  65. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/provision.ts +80 -0
  66. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedule-detail.ts +99 -0
  67. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules-api.ts +27 -0
  68. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules.ts +144 -0
  69. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/unit-files.ts +43 -0
  70. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/user.ts +91 -0
  71. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/view.ts +87 -0
  72. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-attach.ts +19 -0
  73. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-lookups.ts +55 -0
  74. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-routes.ts +76 -0
  75. package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +357 -0
  76. package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +30 -0
  77. package/runtime/node_modules/@metro-labs/daemon/src/agents/allowlist.ts +59 -0
  78. package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +131 -0
  79. package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +132 -0
  80. package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +305 -0
  81. package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +142 -0
  82. package/runtime/node_modules/@metro-labs/{mcp/src/db/key-map.ts → daemon/src/agents/keys.ts} +1 -11
  83. package/runtime/node_modules/@metro-labs/daemon/src/agents/map.ts +133 -0
  84. package/runtime/node_modules/@metro-labs/daemon/src/agents/policy-route.ts +27 -0
  85. package/runtime/node_modules/@metro-labs/{mcp/src/db/agent-scope.ts → daemon/src/agents/scope.ts} +2 -2
  86. package/runtime/node_modules/@metro-labs/daemon/src/agents/sender-cards.ts +94 -0
  87. package/runtime/node_modules/@metro-labs/daemon/src/agents/senders.ts +38 -0
  88. package/runtime/node_modules/@metro-labs/daemon/src/approvals/api.ts +55 -0
  89. package/runtime/node_modules/@metro-labs/daemon/src/approvals/pending.ts +150 -0
  90. package/runtime/node_modules/@metro-labs/daemon/src/approvals/preview.ts +66 -0
  91. package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +223 -0
  92. package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +36 -0
  93. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/crash-guard.ts +1 -1
  94. package/runtime/node_modules/@metro-labs/daemon/src/boot/local-owner.ts +21 -0
  95. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/paths.ts +6 -34
  96. package/runtime/node_modules/@metro-labs/daemon/src/channels/addressed.ts +26 -0
  97. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/inbound.ts +75 -45
  98. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/media-note.ts +11 -7
  99. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/pending.ts +4 -1
  100. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/relay.ts +2 -2
  101. package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +380 -0
  102. package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +359 -0
  103. package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +208 -0
  104. package/runtime/node_modules/@metro-labs/daemon/src/claude/memory-routine.ts +114 -0
  105. package/runtime/node_modules/@metro-labs/daemon/src/claude/memory.ts +32 -0
  106. package/runtime/node_modules/@metro-labs/daemon/src/claude/onboarding.ts +60 -0
  107. package/runtime/node_modules/@metro-labs/daemon/src/claude/plugin-install.ts +149 -0
  108. package/runtime/node_modules/@metro-labs/daemon/src/claude/session-files.ts +75 -0
  109. package/runtime/node_modules/@metro-labs/daemon/src/claude/session.ts +295 -0
  110. package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +109 -0
  111. package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +346 -0
  112. package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +120 -0
  113. package/runtime/node_modules/@metro-labs/daemon/src/claude/usage-probe.ts +127 -0
  114. package/runtime/node_modules/@metro-labs/daemon/src/claude/version.ts +113 -0
  115. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-api.ts → daemon/src/connectors/api.ts} +79 -113
  116. package/runtime/node_modules/@metro-labs/{mcp/src/db/connector-config.ts → daemon/src/connectors/config.ts} +67 -41
  117. package/runtime/node_modules/@metro-labs/daemon/src/connectors/gates.ts +72 -0
  118. package/runtime/node_modules/@metro-labs/daemon/src/connectors/health.ts +18 -0
  119. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-client.ts +14 -17
  120. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-discovery.ts +33 -20
  121. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth-routes.ts → daemon/src/connectors/oauth-routes.ts} +30 -32
  122. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth.ts → daemon/src/connectors/oauth.ts} +61 -22
  123. package/runtime/node_modules/@metro-labs/daemon/src/connectors/plugin-sync.ts +131 -0
  124. package/runtime/node_modules/@metro-labs/daemon/src/connectors/reach.ts +27 -0
  125. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-policy.ts +90 -0
  126. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +347 -0
  127. package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +385 -0
  128. package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +81 -0
  129. package/runtime/node_modules/@metro-labs/daemon/src/connectors/transfer-api.ts +116 -0
  130. package/runtime/node_modules/@metro-labs/daemon/src/connectors/transfer-crypto.ts +44 -0
  131. package/runtime/node_modules/@metro-labs/daemon/src/connectors/transfer-store.ts +48 -0
  132. package/runtime/node_modules/@metro-labs/daemon/src/connectors/url.ts +37 -0
  133. package/runtime/node_modules/@metro-labs/daemon/src/connectors/verify.ts +106 -0
  134. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-grant.ts +4 -4
  135. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-owner.ts +3 -3
  136. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-reaper.ts +174 -0
  137. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-serve.ts +12 -13
  138. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-api.ts +10 -27
  139. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-store.ts +4 -4
  140. package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +233 -0
  141. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +214 -0
  142. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-device.ts +91 -0
  143. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +173 -0
  144. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +209 -0
  145. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-version.ts +44 -0
  146. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +155 -0
  147. package/runtime/node_modules/@metro-labs/daemon/src/gateway/effort.ts +93 -0
  148. package/runtime/node_modules/@metro-labs/daemon/src/gateway/eventstream.ts +123 -0
  149. package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +237 -0
  150. package/runtime/node_modules/@metro-labs/daemon/src/gateway/frames.ts +118 -0
  151. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +307 -0
  152. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-auth.ts +160 -0
  153. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-client.ts +46 -0
  154. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-setup.ts +150 -0
  155. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-stream.ts +139 -0
  156. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-translate.ts +235 -0
  157. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini.ts +208 -0
  158. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +203 -0
  159. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +285 -0
  160. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-lists.ts +57 -0
  161. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-signin.ts +161 -0
  162. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-store.ts +72 -0
  163. package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +104 -0
  164. package/runtime/node_modules/@metro-labs/daemon/src/gateway/pkce.ts +36 -0
  165. package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +118 -0
  166. package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +18 -0
  167. package/runtime/node_modules/@metro-labs/daemon/src/gateway/subscription.ts +120 -0
  168. package/runtime/node_modules/@metro-labs/daemon/src/gateway/text.ts +35 -0
  169. package/runtime/node_modules/@metro-labs/daemon/src/gateway/tool-search.ts +126 -0
  170. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage-refresh.ts +102 -0
  171. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +348 -0
  172. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/accounts.ts +28 -17
  173. package/runtime/node_modules/@metro-labs/daemon/src/mcp/attachment-schema.ts +91 -0
  174. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/call-tools.ts +49 -20
  175. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/ctx.ts +4 -4
  176. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/event-store.ts +15 -16
  177. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/group-tools.ts +2 -2
  178. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/index.ts +34 -80
  179. package/runtime/node_modules/@metro-labs/daemon/src/mcp/instructions.ts +19 -0
  180. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/member-tools.ts +2 -2
  181. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-prompt.ts +87 -0
  182. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +88 -0
  183. package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-gate.ts +82 -0
  184. package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-snapshot.ts +79 -0
  185. package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-lookup.ts +60 -0
  186. package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-tool.ts +96 -0
  187. package/runtime/node_modules/@metro-labs/daemon/src/mcp/read-tool.ts +87 -0
  188. package/runtime/node_modules/@metro-labs/daemon/src/mcp/request-identity.ts +46 -0
  189. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-slot.ts +71 -0
  190. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/session.ts +47 -44
  191. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-catalog.ts +93 -0
  192. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-def.ts +9 -0
  193. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-dispatch.ts +53 -40
  194. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-schemas.ts +64 -113
  195. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/upload-tool.ts +6 -11
  196. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/helper-script.ts +126 -0
  197. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/install.ts +37 -0
  198. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/privilege.ts +48 -0
  199. package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +132 -0
  200. package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +316 -0
  201. package/runtime/node_modules/@metro-labs/daemon/src/policy/policy.ts +118 -0
  202. package/runtime/node_modules/@metro-labs/daemon/src/routes/bearer.ts +35 -0
  203. package/runtime/node_modules/@metro-labs/daemon/src/routes/body.ts +24 -0
  204. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/routes}/http.ts +63 -51
  205. package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +209 -0
  206. package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +69 -0
  207. package/runtime/node_modules/@metro-labs/daemon/src/routes/session.ts +29 -0
  208. package/runtime/node_modules/@metro-labs/daemon/src/routes/threema-callback.ts +103 -0
  209. package/runtime/node_modules/@metro-labs/daemon/src/server/cloudwatch.ts +178 -0
  210. package/runtime/node_modules/@metro-labs/daemon/src/server/control.ts +39 -0
  211. package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +58 -0
  212. package/runtime/node_modules/@metro-labs/daemon/src/server/owner.ts +26 -0
  213. package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +90 -0
  214. package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
  215. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-browser.ts +102 -0
  216. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-driver.ts +42 -0
  217. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-inline.ts +29 -1
  218. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-interactive.ts +5 -31
  219. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-resolve.ts +38 -13
  220. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/attach-session.ts +32 -22
  221. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-xmtp.ts +8 -9
  222. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach.ts +69 -3
  223. package/runtime/node_modules/@metro-labs/{mcp/src/db → daemon/src/stations}/materialize.ts +60 -179
  224. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/registry.ts +20 -2
  225. package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +82 -0
  226. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor-io.ts +3 -3
  227. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor.ts +6 -9
  228. package/runtime/node_modules/@metro-labs/daemon/src/stations/threema-callbacks.ts +32 -0
  229. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/train-call.ts +1 -1
  230. package/runtime/node_modules/@metro-labs/daemon/src/stations/webhook-endpoints.ts +51 -0
  231. package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +84 -0
  232. package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +124 -0
  233. package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +15 -0
  234. package/runtime/node_modules/@metro-labs/daemon/src/vault/api.ts +45 -0
  235. package/runtime/node_modules/@metro-labs/daemon/src/vault/config.ts +51 -0
  236. package/runtime/node_modules/@metro-labs/daemon/src/vault/firewall.ts +9 -0
  237. package/runtime/node_modules/@metro-labs/daemon/src/vault/index.ts +96 -0
  238. package/runtime/node_modules/@metro-labs/daemon/src/vault/install.ts +56 -0
  239. package/runtime/node_modules/@metro-labs/daemon/src/vault/paths.ts +26 -0
  240. package/runtime/node_modules/@metro-labs/daemon/src/vault/proxy.ts +147 -0
  241. package/runtime/node_modules/@metro-labs/daemon/src/vault/store.ts +129 -0
  242. package/runtime/node_modules/@metro-labs/daemon/src/vault/trust.ts +44 -0
  243. package/runtime/node_modules/@metro-labs/discord-bot/package.json +2 -4
  244. package/runtime/node_modules/@metro-labs/discord-bot/src/accounts.ts +3 -23
  245. package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +19 -187
  246. package/runtime/node_modules/@metro-labs/discord-bot/src/attachments.ts +2 -2
  247. package/runtime/node_modules/@metro-labs/discord-bot/src/format.ts +26 -67
  248. package/runtime/node_modules/@metro-labs/discord-bot/src/group-actions.ts +1 -1
  249. package/runtime/node_modules/@metro-labs/discord-bot/src/group.ts +2 -2
  250. package/runtime/node_modules/@metro-labs/discord-bot/src/index.ts +8 -14
  251. package/runtime/node_modules/@metro-labs/discord-bot/src/members.ts +2 -2
  252. package/runtime/node_modules/@metro-labs/discord-bot/src/profile.ts +68 -0
  253. package/runtime/node_modules/@metro-labs/discord-bot/src/send-files.ts +12 -13
  254. package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +5 -1
  255. package/runtime/node_modules/@metro-labs/gmail/package.json +25 -0
  256. package/runtime/node_modules/@metro-labs/gmail/src/accounts.ts +81 -0
  257. package/runtime/node_modules/@metro-labs/gmail/src/actions.ts +14 -0
  258. package/runtime/node_modules/@metro-labs/gmail/src/api.ts +31 -0
  259. package/runtime/node_modules/@metro-labs/gmail/src/attachments.ts +35 -0
  260. package/runtime/node_modules/@metro-labs/gmail/src/auth.ts +105 -0
  261. package/runtime/node_modules/@metro-labs/gmail/src/config.ts +13 -0
  262. package/runtime/node_modules/@metro-labs/gmail/src/inbound.ts +96 -0
  263. package/runtime/node_modules/@metro-labs/gmail/src/index.ts +12 -0
  264. package/runtime/node_modules/@metro-labs/gmail/src/login.ts +37 -0
  265. package/runtime/node_modules/@metro-labs/gmail/src/message.ts +125 -0
  266. package/runtime/node_modules/@metro-labs/gmail/src/mime.ts +70 -0
  267. package/runtime/node_modules/@metro-labs/gmail/src/outbound.ts +124 -0
  268. package/runtime/node_modules/@metro-labs/gmail/src/query.ts +99 -0
  269. package/runtime/node_modules/@metro-labs/gmail/src/state.ts +24 -0
  270. package/runtime/node_modules/@metro-labs/gmail/src/station.ts +15 -0
  271. package/runtime/node_modules/@metro-labs/gmail/src/trust.ts +42 -0
  272. package/runtime/node_modules/@metro-labs/http/package.json +30 -0
  273. package/runtime/node_modules/@metro-labs/http/src/api-http.ts +135 -0
  274. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/session-api.ts → http/src/mode-api.ts} +13 -9
  275. package/runtime/node_modules/@metro-labs/http/src/return-to.ts +21 -0
  276. package/runtime/node_modules/@metro-labs/http/src/sigv4.ts +90 -0
  277. package/runtime/node_modules/@metro-labs/http/src/workos-token.ts +149 -0
  278. package/runtime/node_modules/@metro-labs/outlook/package.json +25 -0
  279. package/runtime/node_modules/@metro-labs/outlook/src/accounts.ts +78 -0
  280. package/runtime/node_modules/@metro-labs/outlook/src/actions.ts +14 -0
  281. package/runtime/node_modules/@metro-labs/outlook/src/attachments.ts +81 -0
  282. package/runtime/node_modules/@metro-labs/outlook/src/auth.ts +120 -0
  283. package/runtime/node_modules/@metro-labs/outlook/src/browser.ts +42 -0
  284. package/runtime/node_modules/@metro-labs/outlook/src/config.ts +23 -0
  285. package/runtime/node_modules/@metro-labs/outlook/src/format.ts +59 -0
  286. package/runtime/node_modules/@metro-labs/outlook/src/graph.ts +55 -0
  287. package/runtime/node_modules/@metro-labs/outlook/src/inbound.ts +96 -0
  288. package/runtime/node_modules/@metro-labs/outlook/src/index.ts +12 -0
  289. package/runtime/node_modules/@metro-labs/outlook/src/login.ts +129 -0
  290. package/runtime/node_modules/@metro-labs/outlook/src/me.ts +31 -0
  291. package/runtime/node_modules/@metro-labs/outlook/src/outbound.ts +103 -0
  292. package/runtime/node_modules/@metro-labs/outlook/src/query.ts +84 -0
  293. package/runtime/node_modules/@metro-labs/outlook/src/state.ts +28 -0
  294. package/runtime/node_modules/@metro-labs/outlook/src/station.ts +15 -0
  295. package/runtime/node_modules/@metro-labs/outlook/src/trust.ts +41 -0
  296. package/runtime/node_modules/@metro-labs/telegram/package.json +1 -3
  297. package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +5 -24
  298. package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +8 -6
  299. package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +1 -1
  300. package/runtime/node_modules/@metro-labs/telegram/src/client.ts +2 -2
  301. package/runtime/node_modules/@metro-labs/telegram/src/format.ts +19 -34
  302. package/runtime/node_modules/@metro-labs/telegram/src/group.ts +3 -3
  303. package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +13 -34
  304. package/runtime/node_modules/@metro-labs/telegram/src/index.ts +4 -43
  305. package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +2 -3
  306. package/runtime/node_modules/@metro-labs/telegram/src/members.ts +1 -1
  307. package/runtime/node_modules/@metro-labs/telegram/src/profile.ts +70 -0
  308. package/runtime/node_modules/@metro-labs/telegram/src/reactions.ts +2 -2
  309. package/runtime/node_modules/@metro-labs/telegram/src/station.ts +4 -1
  310. package/runtime/node_modules/@metro-labs/telegram/src/types.ts +0 -1
  311. package/runtime/node_modules/@metro-labs/telegram-bot/package.json +1 -1
  312. package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +7 -41
  313. package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +22 -77
  314. package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +2 -2
  315. package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +46 -48
  316. package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +15 -15
  317. package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +6 -82
  318. package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +1 -1
  319. package/runtime/node_modules/@metro-labs/telegram-bot/src/profile.ts +85 -0
  320. package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +5 -1
  321. package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +20 -12
  322. package/runtime/node_modules/@metro-labs/threema/package.json +26 -0
  323. package/runtime/node_modules/@metro-labs/threema/src/accounts.ts +96 -0
  324. package/runtime/node_modules/@metro-labs/threema/src/actions.ts +124 -0
  325. package/runtime/node_modules/@metro-labs/threema/src/api.ts +152 -0
  326. package/runtime/node_modules/@metro-labs/threema/src/crypto.ts +100 -0
  327. package/runtime/node_modules/@metro-labs/threema/src/files.ts +47 -0
  328. package/runtime/node_modules/@metro-labs/threema/src/format.ts +164 -0
  329. package/runtime/node_modules/@metro-labs/threema/src/groups.ts +96 -0
  330. package/runtime/node_modules/@metro-labs/threema/src/ids.ts +21 -0
  331. package/runtime/node_modules/@metro-labs/threema/src/inbound.ts +87 -0
  332. package/runtime/node_modules/@metro-labs/threema/src/index.ts +24 -0
  333. package/runtime/node_modules/@metro-labs/threema/src/messages.ts +264 -0
  334. package/runtime/node_modules/@metro-labs/threema/src/outbound.ts +160 -0
  335. package/runtime/node_modules/@metro-labs/threema/src/station.ts +13 -0
  336. package/runtime/node_modules/@metro-labs/threema/src/verify.ts +117 -0
  337. package/runtime/node_modules/@metro-labs/webhook/package.json +1 -1
  338. package/runtime/node_modules/@metro-labs/webhook/src/station.ts +5 -8
  339. package/runtime/node_modules/@metro-labs/whatsapp/package.json +2 -5
  340. package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +6 -28
  341. package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +1 -1
  342. package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +54 -11
  343. package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +2 -2
  344. package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +1 -1
  345. package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +86 -4
  346. package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +7 -58
  347. package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +11 -28
  348. package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +4 -37
  349. package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +1 -1
  350. package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +1 -1
  351. package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +1 -1
  352. package/runtime/node_modules/@metro-labs/whatsapp/src/names.ts +75 -0
  353. package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +44 -0
  354. package/runtime/node_modules/@metro-labs/whatsapp/src/resolve.ts +52 -0
  355. package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +16 -1
  356. package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +5 -9
  357. package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +0 -1
  358. package/runtime/node_modules/@metro-labs/xmtp/package.json +3 -2
  359. package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +10 -20
  360. package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +2 -2
  361. package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +15 -204
  362. package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +40 -53
  363. package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +72 -220
  364. package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +3 -3
  365. package/runtime/node_modules/@metro-labs/xmtp/src/codecs.ts +27 -0
  366. package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +11 -7
  367. package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +7 -24
  368. package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +8 -18
  369. package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +1 -1
  370. package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +2 -2
  371. package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +30 -16
  372. package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +12 -20
  373. package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +57 -33
  374. package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +1 -1
  375. package/runtime/node_modules/@metro-labs/xmtp/src/names.ts +61 -0
  376. package/runtime/node_modules/@metro-labs/xmtp/src/profile.ts +153 -0
  377. package/runtime/node_modules/@metro-labs/xmtp/src/resolve.ts +44 -0
  378. package/runtime/node_modules/@metro-labs/xmtp/src/sender.ts +112 -0
  379. package/runtime/node_modules/@metro-labs/xmtp/src/smart.ts +72 -0
  380. package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +7 -2
  381. package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +22 -58
  382. package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +55 -48
  383. package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +4 -6
  384. package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +19 -5
  385. package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +14 -4
  386. package/runtime/runtime.json +1 -1
  387. package/runtime/server.ts +1 -0
  388. package/runtime/stations.json +38 -0
  389. package/dist/prompt.js +0 -61
  390. package/dist/store.js +0 -70
  391. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-speak.ts +0 -195
  392. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-transcribe.ts +0 -292
  393. package/runtime/node_modules/@metro-labs/discord-bot/src/voice.ts +0 -197
  394. package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +0 -5
  395. package/runtime/node_modules/@metro-labs/mcp/package.json +0 -66
  396. package/runtime/node_modules/@metro-labs/mcp/src/channels/dedupe.ts +0 -24
  397. package/runtime/node_modules/@metro-labs/mcp/src/daemon/account-api.ts +0 -311
  398. package/runtime/node_modules/@metro-labs/mcp/src/daemon/agent-api.ts +0 -341
  399. package/runtime/node_modules/@metro-labs/mcp/src/daemon/api-http.ts +0 -129
  400. package/runtime/node_modules/@metro-labs/mcp/src/daemon/boot.ts +0 -320
  401. package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair-api.ts +0 -111
  402. package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair.ts +0 -20
  403. package/runtime/node_modules/@metro-labs/mcp/src/daemon/collection-api.ts +0 -202
  404. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-json.ts +0 -31
  405. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-tools.ts +0 -100
  406. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-url.ts +0 -57
  407. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-verify.ts +0 -333
  408. package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-auth.ts +0 -164
  409. package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-oauth.ts +0 -208
  410. package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity.ts +0 -79
  411. package/runtime/node_modules/@metro-labs/mcp/src/daemon/oauth-pending.ts +0 -65
  412. package/runtime/node_modules/@metro-labs/mcp/src/daemon/pair-codes.ts +0 -58
  413. package/runtime/node_modules/@metro-labs/mcp/src/daemon/project-api.ts +0 -214
  414. package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-api.ts +0 -125
  415. package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-pair.ts +0 -18
  416. package/runtime/node_modules/@metro-labs/mcp/src/daemon/runtime-source.ts +0 -105
  417. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session-apis.ts +0 -41
  418. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session.ts +0 -218
  419. package/runtime/node_modules/@metro-labs/mcp/src/daemon/tunnel.ts +0 -169
  420. package/runtime/node_modules/@metro-labs/mcp/src/db/account-attach.ts +0 -91
  421. package/runtime/node_modules/@metro-labs/mcp/src/db/agent-admin.ts +0 -215
  422. package/runtime/node_modules/@metro-labs/mcp/src/db/agent-map.ts +0 -71
  423. package/runtime/node_modules/@metro-labs/mcp/src/db/client.ts +0 -37
  424. package/runtime/node_modules/@metro-labs/mcp/src/db/connector-collections.ts +0 -218
  425. package/runtime/node_modules/@metro-labs/mcp/src/db/connectors.ts +0 -329
  426. package/runtime/node_modules/@metro-labs/mcp/src/db/projects.ts +0 -300
  427. package/runtime/node_modules/@metro-labs/mcp/src/db/runtime-admin.ts +0 -31
  428. package/runtime/node_modules/@metro-labs/mcp/src/db/runtimes.ts +0 -105
  429. package/runtime/node_modules/@metro-labs/mcp/src/db/schema.ts +0 -131
  430. package/runtime/node_modules/@metro-labs/mcp/src/db/token-carry.ts +0 -45
  431. package/runtime/node_modules/@metro-labs/mcp/src/db/users.ts +0 -57
  432. package/runtime/node_modules/@metro-labs/mcp/src/db/whatsapp-login.ts +0 -18
  433. package/runtime/node_modules/@metro-labs/mcp/src/mcp/channel-owner.ts +0 -29
  434. package/runtime/node_modules/@metro-labs/mcp/src/mcp/frame-scope.ts +0 -21
  435. package/runtime/node_modules/@metro-labs/mcp/src/mcp/permission-relay.ts +0 -66
  436. package/runtime/node_modules/@metro-labs/mcp/src/mcp/request-identity.ts +0 -73
  437. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-registry.ts +0 -172
  438. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-route.ts +0 -43
  439. package/runtime/node_modules/@metro-labs/mcp/src/monitor/api.ts +0 -240
  440. package/runtime/node_modules/@metro-labs/mcp/src/server.ts +0 -2
  441. package/runtime/node_modules/@metro-labs/mcp/src/stations/account-store.ts +0 -80
  442. package/runtime/node_modules/@metro-labs/mcp/src/stations/messaging-normalize.ts +0 -88
  443. package/runtime/node_modules/@metro-labs/telegram/src/normalize.ts +0 -22
  444. package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +0 -1
  445. package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +0 -3
  446. package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +0 -22
  447. package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +0 -5
  448. package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +0 -87
  449. package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +0 -55
  450. package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +0 -349
  451. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/log.ts +0 -0
  452. /package/runtime/node_modules/@metro-labs/{mcp/src/mcp → core/src}/str.ts +0 -0
  453. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/train-error.ts +0 -0
  454. /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/webhook-note.ts +0 -0
  455. /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/raw-get-stream.ts +0 -0
  456. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/api-error.ts +0 -0
  457. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/cors.ts +0 -0
@@ -0,0 +1,44 @@
1
+ import { IdentifierKind } from '@xmtp/node-sdk';
2
+ import { namehash, type Hex } from 'viem';
3
+ import { normalize } from 'viem/ens';
4
+ import { respond } from '@metro-labs/core/stations/station-runtime';
5
+ import { TrainError } from '@metro-labs/core/train-error';
6
+ import { accountForCall } from './accounts.js';
7
+ import { BASENAME_L2_RESOLVER, BASENAME_REGISTRY, REGISTRY_ABI } from './profile.js';
8
+ import { readerFor, type Reader } from './sender.js';
9
+
10
+ const ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
11
+ const INBOX_RE = /^[0-9a-f]{64}$/;
12
+ const NAME_RE = /^[a-z0-9-]+(\.[a-z0-9-]+)*\.eth$/i;
13
+ const ZERO = '0x0000000000000000000000000000000000000000';
14
+ const ADDR_ABI = [
15
+ { name: 'addr', type: 'function', stateMutability: 'view', inputs: [{ name: 'node', type: 'bytes32' }], outputs: [{ name: '', type: 'address' }] },
16
+ ] as const;
17
+
18
+ function refuse(query: string, why: string): never {
19
+ throw new TrainError('bad_request', `'${query}' ${why}`, { retryable: false });
20
+ }
21
+
22
+ async function addressOfName(name: string, client: Reader): Promise<string> {
23
+ const node = namehash(normalize(name));
24
+ const found: Hex = await client.readContract({ address: BASENAME_REGISTRY, abi: REGISTRY_ABI, functionName: 'resolver', args: [node] });
25
+ const resolver = found === ZERO ? BASENAME_L2_RESOLVER : found;
26
+ const address = await client.readContract({ address: resolver, abi: ADDR_ABI, functionName: 'addr', args: [node] });
27
+ if (address === ZERO) refuse(name, 'points to no address');
28
+ return address;
29
+ }
30
+
31
+ export async function addressOf(query: string, client: Reader = readerFor()): Promise<string> {
32
+ if (INBOX_RE.test(query)) refuse(query, 'is already an inbox id, so add it directly instead of looking it up');
33
+ if (ADDRESS_RE.test(query)) return query.toLowerCase();
34
+ if (NAME_RE.test(query)) return (await addressOfName(query.toLowerCase(), client)).toLowerCase();
35
+ refuse(query, 'is not a wallet address (0x followed by 40 characters) or a name ending in .eth');
36
+ }
37
+
38
+ export async function resolveSenderAction(id: string, args: Record<string, unknown>): Promise<void> {
39
+ const query = typeof args.query === 'string' ? args.query.trim() : '';
40
+ const acct = accountForCall({ account: typeof args.account === 'string' ? args.account : undefined });
41
+ const address = await addressOf(query);
42
+ const inboxId = await acct.client.fetchInboxIdByIdentifier({ identifier: address, identifierKind: IdentifierKind.Ethereum });
43
+ respond(id, { result: { account: acct.cfg.id, query, address, exists: inboxId !== null, id: inboxId } });
44
+ }
@@ -0,0 +1,112 @@
1
+ import { createPublicClient, http, namehash, type Hex } from 'viem';
2
+ import { base } from 'viem/chains';
3
+ import { normalize } from 'viem/ens';
4
+ import { makeProfileCache, type SenderProfile as Profile } from '@metro-labs/core/stations/sender-profile';
5
+ import { respond } from '@metro-labs/core/stations/station-runtime';
6
+ import { TrainError } from '@metro-labs/core/train-error';
7
+ import { accountForCall, accounts, type Account } from './accounts.js';
8
+ import { resolveAddresses } from './conv-helpers.js';
9
+ import { nameOf } from './names.js';
10
+ import { BASENAME_L2_RESOLVER, BASENAME_REGISTRY, NAME_ABI, REGISTRY_ABI, reverseNodeOf } from './profile.js';
11
+
12
+ export interface SenderProfile {
13
+ address: string;
14
+ name: string | null;
15
+ displayName: string | null;
16
+ about: string | null;
17
+ avatar: string | null;
18
+ }
19
+
20
+ const BASE_RPC = 'https://rpc.brovider.xyz/8453';
21
+ const ZERO = '0x0000000000000000000000000000000000000000';
22
+ const AVATAR_RE = /^(https?:\/\/|ipfs:\/\/|data:image\/)/i;
23
+
24
+ const TEXT_ABI = [
25
+ { name: 'addr', type: 'function', stateMutability: 'view', inputs: [{ name: 'node', type: 'bytes32' }], outputs: [{ name: '', type: 'address' }] },
26
+ {
27
+ name: 'text',
28
+ type: 'function',
29
+ stateMutability: 'view',
30
+ inputs: [{ name: 'node', type: 'bytes32' }, { name: 'key', type: 'string' }],
31
+ outputs: [{ name: '', type: 'string' }],
32
+ },
33
+ ] as const;
34
+
35
+ export const baseRpc = (): string => process.env.METRO_BASE_RPC ?? BASE_RPC;
36
+
37
+ const makeReader = (rpc: string) => createPublicClient({ chain: base, transport: http(rpc), batch: { multicall: true } });
38
+
39
+ export type Reader = ReturnType<typeof makeReader>;
40
+
41
+ let reader: Reader | null = null;
42
+ export const readerFor = (): Reader => (reader ??= makeReader(baseRpc()));
43
+
44
+ const trimmed = (v: string): string | null => (v.trim() === '' ? null : v.trim());
45
+
46
+ async function resolverOf(client: Reader, node: Hex): Promise<Hex> {
47
+ const found: Hex = await client.readContract({ address: BASENAME_REGISTRY, abi: REGISTRY_ABI, functionName: 'resolver', args: [node] });
48
+ return found === ZERO ? BASENAME_L2_RESOLVER : found;
49
+ }
50
+
51
+ async function primaryName(client: Reader, address: string): Promise<string | null> {
52
+ const node = reverseNodeOf(address);
53
+ const found = await client.readContract({ address: await resolverOf(client, node), abi: NAME_ABI, functionName: 'name', args: [node] });
54
+ return found === '' ? null : found;
55
+ }
56
+
57
+ async function recordsOf(client: Reader, name: string, address: string): Promise<SenderProfile | null> {
58
+ const node = namehash(normalize(name));
59
+ const resolver = { address: await resolverOf(client, node), abi: TEXT_ABI } as const;
60
+ const text = (key: string): Promise<string> => client.readContract({ ...resolver, functionName: 'text', args: [node, key] });
61
+ const [forward, displayName, about, avatar] = await Promise.all([
62
+ client.readContract({ ...resolver, functionName: 'addr', args: [node] }),
63
+ text('name'),
64
+ text('description'),
65
+ text('avatar'),
66
+ ]);
67
+ if (forward.toLowerCase() !== address.toLowerCase()) return null;
68
+ return { address, name, displayName: trimmed(displayName), about: trimmed(about), avatar: AVATAR_RE.test(avatar.trim()) ? avatar.trim() : null };
69
+ }
70
+
71
+ export async function profileOf(address: string, client: Reader = readerFor(), fetchImpl: typeof fetch = fetch): Promise<SenderProfile> {
72
+ const bare: SenderProfile = { address, name: null, displayName: null, about: null, avatar: null };
73
+ const name = (await primaryName(client, address)) ?? (await nameOf(address, fetchImpl));
74
+ if (name === null) return bare;
75
+ return (await recordsOf(client, name, address)) ?? bare;
76
+ }
77
+
78
+ const key = (acct: Account, inboxId: string): string => `${acct.cfg.id}:${inboxId}`;
79
+
80
+ const senders = makeProfileCache<SenderProfile>(
81
+ async (k) => {
82
+ const [accountId, inboxId] = k.split(':', 2) as [string, string];
83
+ const acct = accounts.get(accountId);
84
+ if (acct === undefined) return null;
85
+ const address = (await resolveAddresses(acct, [inboxId]))[inboxId];
86
+ return address === undefined ? null : profileOf(address);
87
+ },
88
+ { onError: (k, err) => process.stderr.write(`xmtp: could not resolve the sender ${k}: ${err instanceof Error ? err.message : String(err)}\n`) },
89
+ );
90
+
91
+ export const senderFields = (p: SenderProfile | null): Record<string, string> =>
92
+ p === null ? {} : { from_name: p.name ?? p.address, ...(p.displayName === null ? {} : { from_display_name: p.displayName }) };
93
+
94
+ export const senderFieldsNow = (acct: Account, inboxId: string): Record<string, string> => senderFields(senders.peek(key(acct, inboxId)));
95
+
96
+ export const senderProfile = (acct: Account, inboxId: string): Promise<SenderProfile | null> => senders.get(key(acct, inboxId));
97
+
98
+ export const profileView = (inboxId: string, p: SenderProfile | null): Profile => ({
99
+ id: inboxId,
100
+ ...(p === null ? {} : { address: p.address }),
101
+ ...(p?.name == null ? {} : { name: p.name }),
102
+ ...(p?.displayName == null ? {} : { display_name: p.displayName }),
103
+ ...(p?.about == null ? {} : { about: p.about }),
104
+ ...(p?.avatar == null ? {} : { avatar: p.avatar }),
105
+ });
106
+
107
+ export async function profileAction(id: string, args: Record<string, unknown>): Promise<void> {
108
+ const user = typeof args.user === 'string' ? args.user.trim() : '';
109
+ if (user === '') throw new TrainError('xmtp_user_required', 'profile needs the inbox id of the person', { retryable: false });
110
+ const acct = accountForCall({ account: typeof args.account === 'string' ? args.account : undefined });
111
+ respond(id, { result: profileView(user, await senderProfile(acct, user)) });
112
+ }
@@ -0,0 +1,72 @@
1
+ import { createPublicClient, http, type Hex } from 'viem';
2
+ import { privateKeyToAccount } from 'viem/accounts';
3
+ import { base } from 'viem/chains';
4
+ import {
5
+ createKernelAccount,
6
+ createKernelAccountClient,
7
+ createZeroDevPaymasterClient,
8
+ getUserOperationGasPrice,
9
+ type KernelAccountClient,
10
+ } from '@zerodev/sdk';
11
+ import { getEntryPoint, KERNEL_V3_1 } from '@zerodev/sdk/constants';
12
+ import { signerToEcdsaValidator } from '@zerodev/ecdsa-validator';
13
+
14
+ export const SMART_CHAIN_ID = 8453;
15
+ const STAGE_ZERODEV_PROJECT = 'c107f734-f7bb-48c1-a5d2-ceb3f70a42f6';
16
+ const ENTRY_POINT = getEntryPoint('0.7');
17
+
18
+ export const zerodevRpc = (): string =>
19
+ `https://rpc.zerodev.app/api/v3/${process.env.METRO_ZERODEV_PROJECT ?? STAGE_ZERODEV_PROJECT}/chain/${String(SMART_CHAIN_ID)}`;
20
+
21
+ export const makePublicClient = (rpc: string) => createPublicClient({ chain: base, transport: http(rpc) });
22
+
23
+ export type BaseClient = ReturnType<typeof makePublicClient>;
24
+
25
+ export interface SmartAccount {
26
+ address: Hex;
27
+ publicClient: BaseClient;
28
+ client: () => KernelAccountClient;
29
+ signMessage: (message: string) => Promise<Hex>;
30
+ deployed: () => Promise<boolean>;
31
+ }
32
+
33
+ export async function smartAccountFor(privateKey: string, rpc = zerodevRpc()): Promise<SmartAccount> {
34
+ const owner = privateKeyToAccount(privateKey as Hex);
35
+ const publicClient = makePublicClient(rpc);
36
+ const validator = await signerToEcdsaValidator(publicClient, { signer: owner, entryPoint: ENTRY_POINT, kernelVersion: KERNEL_V3_1 });
37
+ const account = await createKernelAccount(publicClient, { plugins: { sudo: validator }, entryPoint: ENTRY_POINT, kernelVersion: KERNEL_V3_1, index: 0n });
38
+ const paymaster = createZeroDevPaymasterClient({ chain: base, transport: http(rpc) });
39
+ const client = (): KernelAccountClient =>
40
+ createKernelAccountClient({
41
+ account,
42
+ chain: base,
43
+ bundlerTransport: http(rpc),
44
+ client: publicClient,
45
+ paymaster: { getPaymasterData: (userOperation) => paymaster.sponsorUserOperation({ userOperation }) },
46
+ userOperation: { estimateFeesPerGas: ({ bundlerClient }) => getUserOperationGasPrice(bundlerClient) },
47
+ });
48
+ return {
49
+ address: account.address,
50
+ publicClient,
51
+ client,
52
+ signMessage: (message) => account.signMessage({ message }),
53
+ deployed: async () => {
54
+ const code = await publicClient.getCode({ address: account.address });
55
+ return code !== undefined && code !== '0x';
56
+ },
57
+ };
58
+ }
59
+
60
+ export async function sendSponsored(smart: SmartAccount, to: Hex, data: Hex): Promise<Hex> {
61
+ const client = smart.client();
62
+ const hash = await client.sendTransaction({ to, data, value: 0n } as Parameters<typeof client.sendTransaction>[0]);
63
+ const receipt = await smart.publicClient.waitForTransactionReceipt({ hash });
64
+ if (receipt.status !== 'success') throw new Error(`the Base transaction ${hash} reverted`);
65
+ return hash;
66
+ }
67
+
68
+ export async function ensureDeployed(smart: SmartAccount): Promise<boolean> {
69
+ if (await smart.deployed()) return false;
70
+ await sendSponsored(smart, smart.address, '0x');
71
+ return true;
72
+ }
@@ -1,13 +1,18 @@
1
- import type { GroupOp, Station, Verb } from '@metro-labs/mcp/stations/types';
1
+ import type { GroupOp, Station, Verb } from '@metro-labs/core/stations/types';
2
+ import { PROFILE_FIELDS, type ProfileField } from '@metro-labs/core/stations/profile';
2
3
  import { XMTP_TOOLS, xmtpSendAttachments } from './tools.js';
3
4
 
4
5
  export const xmtpStation: Station = {
5
6
  name: 'xmtp',
6
7
  hasAccounts: true,
7
8
  hasTrain: true,
8
- messageVerbs: new Set<Verb>(['send', 'reply', 'react', 'unreact', 'read']),
9
+ messageVerbs: new Set<Verb>(['send', 'reply', 'react', 'unreact', 'delete', 'read']),
9
10
  groupOps: new Set<GroupOp>(['create_group', 'add_members', 'remove_members']),
10
11
  attachmentMode: 'native',
12
+ profileFields: new Set<ProfileField>(PROFILE_FIELDS),
13
+ readsProfiles: true,
14
+ resolvesSenders: true,
15
+ claimsName: true,
11
16
  sendAttachments: xmtpSendAttachments,
12
17
  tools: XMTP_TOOLS,
13
18
  };
@@ -1,59 +1,26 @@
1
- import type { CanonicalAttachment, ToolContext } from '@metro-labs/mcp/stations/types';
2
- import { TrainError } from '@metro-labs/mcp/train-error';
1
+ import type { CanonicalAttachment, ToolContext } from '@metro-labs/core/stations/types';
2
+ import { TrainError } from '@metro-labs/core/train-error';
3
+ import { metadataPatch, mergeAppData } from './labels.js';
3
4
  import {
4
5
  guessMime,
5
6
  isImageMime,
6
7
  isImageExt,
7
8
  kindOf,
8
- } from '@metro-labs/mcp/stations/attachments';
9
+ } from '@metro-labs/core/stations/attachments';
9
10
 
10
11
  export const str = (v: unknown): string => (typeof v === 'string' ? v : '');
11
12
 
12
- function strList(value: unknown): string[] {
13
- return (value as unknown[] | undefined)?.map(String).filter(Boolean) ?? [];
14
- }
15
-
16
- interface CreatedGroup {
17
- line?: string;
18
- id?: string;
19
- account?: string;
20
- }
21
-
22
- async function applyCreateLabels(
23
- line: string,
24
- labels: string[],
25
- ctx: ToolContext,
26
- ): Promise<unknown> {
27
- if (!labels.length) return undefined;
28
- return ctx.call('updateChannelMeta', { line, appData: { labels } });
29
- }
30
-
31
- export async function createChannel(
32
- a: Record<string, unknown>,
33
- ctx: ToolContext,
34
- ) {
35
- const addresses = strList(a.addresses);
36
- const channelName = str(a.name);
37
- const labels = strList(a.labels);
38
- const account = str(a.account) || undefined;
39
- if (!addresses.length)
40
- return ctx.err('create_channel requires a non-empty `addresses` array');
41
- if (!channelName) return ctx.err('create_channel requires `name`');
42
- const groupArgs: Record<string, unknown> = { addresses, name: channelName };
43
- if (account) groupArgs.account = account;
44
- const { result } = (await ctx.call('newGroup', groupArgs)) as {
45
- result: CreatedGroup | null;
46
- };
47
- const newLine = result?.line ?? '';
48
- const labelResult = newLine.length
49
- ? await applyCreateLabels(newLine, labels, ctx)
50
- : undefined;
51
- return ctx.okJson({
52
- line: newLine,
53
- convId: result?.id,
54
- account: result?.account,
55
- labels: labelResult,
56
- });
13
+ function channelAppData(a: Record<string, unknown>): Record<string, unknown> {
14
+ const appData = a.metadata === undefined ? {} : { ...metadataPatch(a.metadata) };
15
+ for (const key of ['labels', 'github', 'preview']) {
16
+ if (!Object.hasOwn(a, key)) continue;
17
+ if (Object.hasOwn(appData, key)) {
18
+ throw new TrainError('INVALID_ARGS', `Specify ${key} only once, inside metadata or at the top level`);
19
+ }
20
+ appData[key] = a[key];
21
+ }
22
+ mergeAppData(undefined, appData);
23
+ return appData;
57
24
  }
58
25
 
59
26
  export async function setChannelMetadata(
@@ -62,18 +29,15 @@ export async function setChannelMetadata(
62
29
  ) {
63
30
  const line = str(a.line);
64
31
  if (!line) return ctx.err('set_channel_metadata requires `line`');
65
- const labels = a.labels as unknown[] | undefined;
66
- const github = a.github as string | undefined;
67
- const preview = a.preview as string | undefined;
68
- const metaName = a.name as string | undefined;
69
- const appData: Record<string, unknown> = {};
70
- if (Array.isArray(labels)) appData.labels = labels.map(String);
71
- if (typeof github === 'string') appData.github = github;
72
- if (typeof preview === 'string') appData.preview = preview;
32
+ if (Object.hasOwn(a, 'name') && typeof a.name !== 'string') {
33
+ return ctx.err('set_channel_metadata name must be a string');
34
+ }
35
+ const appData = channelAppData(a);
36
+ const metaName = a.name;
73
37
  const hasName = typeof metaName === 'string' && metaName.length > 0;
74
38
  if (!hasName && Object.keys(appData).length === 0)
75
39
  return ctx.err(
76
- 'set_channel_metadata requires at least one of `labels`, `github`, `preview`, `name`',
40
+ 'set_channel_metadata requires at least one of `metadata`, `github`, `preview`, `name`, `labels`',
77
41
  );
78
42
  const callArgs: Record<string, unknown> = { line, appData };
79
43
  if (hasName) callArgs.name = metaName;
@@ -112,7 +76,7 @@ export async function xmtpSendAttachments(
112
76
  ): Promise<string[]> {
113
77
  const sent: string[] = [];
114
78
  for (const a of atts) {
115
- const src = a.path ?? a.url ?? '';
79
+ const src = a.path ?? '';
116
80
  if (!src) continue;
117
81
  const mime = a.mime ?? guessMime(src);
118
82
  if (isImageMime(mime) || isImageExt(src)) {
@@ -1,7 +1,6 @@
1
- import type { StationTool } from '@metro-labs/mcp/stations/types';
1
+ import type { StationTool } from '@metro-labs/core/stations/types';
2
2
  import {
3
3
  str,
4
- createChannel,
5
4
  setChannelMetadata,
6
5
  xmtpSendAttachments,
7
6
  } from './tools-handlers.js';
@@ -15,43 +14,9 @@ const lineProp = {
15
14
  } as const;
16
15
 
17
16
  export const XMTP_TOOLS: StationTool[] = [
18
- {
19
- name: 'create_channel',
20
- description:
21
- 'Create a new XMTP group conversation (channel). Args: addresses (required, array of ' +
22
- 'Ethereum 0x addresses to add as members), name (required, the group name), labels? ' +
23
- '(optional string[] status labels applied after creation), account? ' +
24
- '(defaults to your only XMTP account). Calls the daemon xmtp `newGroup`, then ' +
25
- '`updateChannelMeta` if labels ' +
26
- 'are given. Returns the new metro:// line and convId. This is an xmtp-only operation. ' +
27
- 'NOTE: there is no add-members verb on the daemon, so members must be supplied at ' +
28
- 'creation time.',
29
- inputSchema: {
30
- type: 'object',
31
- properties: {
32
- addresses: {
33
- type: 'array',
34
- description: 'Ethereum 0x addresses to add as group members.',
35
- items: { type: 'string' },
36
- },
37
- name: { type: 'string', description: 'The group/channel name.' },
38
- labels: {
39
- type: 'array',
40
- description: 'Optional status labels to apply after creation.',
41
- items: { type: 'string' },
42
- },
43
- account: {
44
- type: 'string',
45
- description:
46
- 'XMTP account to create under. Omit when you have only one.',
47
- },
48
- },
49
- required: ['addresses', 'name'],
50
- },
51
- handle: (a, ctx) => createChannel(a, ctx),
52
- },
53
17
  {
54
18
  name: 'ask',
19
+ group: 'write',
55
20
  description:
56
21
  'Ask a question as a poll in an XMTP conversation (mirrors Claude AskUserQuestion). ' +
57
22
  'Single-question form: question (required), options? (string[]), header?, multiSelect?, ' +
@@ -116,11 +81,12 @@ export const XMTP_TOOLS: StationTool[] = [
116
81
  },
117
82
  {
118
83
  name: 'dm',
84
+ group: 'write',
119
85
  description:
120
86
  'Open (or reuse) a 1:1 XMTP DM with an Ethereum address. Args: address (required, 0x...), ' +
121
87
  'account? (defaults to your only XMTP account). Returns the new metro:// line and ' +
122
88
  'convId. xmtp-only ' +
123
- '(daemon `newDm`). Use this instead of create_channel when there is a single recipient.',
89
+ '(daemon `newDm`). For a group, use create_group.',
124
90
  inputSchema: {
125
91
  type: 'object',
126
92
  properties: {
@@ -145,10 +111,13 @@ export const XMTP_TOOLS: StationTool[] = [
145
111
  },
146
112
  {
147
113
  name: 'group_info',
114
+ group: 'read',
148
115
  description:
149
116
  "Read an XMTP channel's current metadata + membership. Args: line (required). Returns " +
150
117
  '{line, id, account, version (dm|group), name, memberCount, labels, github, preview, ' +
151
- 'members:[{inboxId, address}]}. xmtp-only (daemon `groupInfo`). Use before ' +
118
+ 'assigned, appData (stored JSON object), rawAppData (stored JSON string), ' +
119
+ 'members:[{inboxId, address}]}. Syncs first and fails if metadata cannot be read. ' +
120
+ 'xmtp-only (daemon `groupInfo`). Use before ' +
152
121
  'set_channel_metadata/add_members to see current state.',
153
122
  inputSchema: {
154
123
  type: 'object',
@@ -163,35 +132,73 @@ export const XMTP_TOOLS: StationTool[] = [
163
132
  },
164
133
  {
165
134
  name: 'close_channel',
135
+ group: 'write',
136
+ destructive: true,
166
137
  description:
167
- 'Archive/close an XMTP group (removes members). Args: line (required). xmtp-only ' +
168
- '(daemon `closeGroup`). Irreversible-ish: members are removed from the group.',
138
+ 'Remove members from an XMTP group, and optionally leave it. Args: line (required), ' +
139
+ 'removeInboxIds? (inbox ids to remove; your own is ignored here), removeSelf? (true to ' +
140
+ 'leave the group yourself). With neither, nothing changes. xmtp-only (daemon ' +
141
+ '`closeGroup`). Returns {removed, leftSelf}.',
169
142
  inputSchema: {
170
143
  type: 'object',
171
- properties: { line: lineProp },
144
+ properties: {
145
+ line: lineProp,
146
+ removeInboxIds: {
147
+ type: 'array',
148
+ description: 'Inbox ids of the members to remove.',
149
+ items: { type: 'string' },
150
+ },
151
+ removeSelf: {
152
+ type: 'boolean',
153
+ description: 'Leave the group after removing the others.',
154
+ },
155
+ },
172
156
  required: ['line'],
173
157
  },
174
158
  async handle(a, ctx) {
175
159
  const line = str(a.line);
176
160
  if (!line) return ctx.err('close_channel requires `line`');
177
- return ctx.okJson(await ctx.call('closeGroup', { line }));
161
+ const args: Record<string, unknown> = { line };
162
+ if (Array.isArray(a.removeInboxIds)) args.removeInboxIds = a.removeInboxIds.map(String);
163
+ if (a.removeSelf === true) args.removeSelf = true;
164
+ return ctx.okJson(await ctx.call('closeGroup', args));
178
165
  },
179
166
  },
180
167
  {
181
168
  name: 'set_channel_metadata',
169
+ group: 'write',
182
170
  description:
183
171
  "Update an existing channel's metadata. Args: line (required, the metro:// line), and " +
184
- 'any of labels? (string[]), github? (url), preview? (url), name? (string). All provided ' +
185
- 'fields are applied together in one atomic updateChannelMeta daemon call (a single ' +
186
- 'appData merge plus name update). xmtp-only ' +
187
- '(channel metadata lives on xmtp groups). Returns the updated channel info.',
172
+ 'any of metadata? (JSON object), github? (url), preview? (url), name? (string). ' +
173
+ 'metadata is a shallow appData patch: omitted keys are preserved, supplied nested ' +
174
+ 'values replace that key, and null deletes custom keys. v is reserved. Put labels ' +
175
+ 'and assigned inside metadata. assigned replaces the array with normalized lowercase ' +
176
+ 'Ethereum addresses of current members. Read group_info and union existing IDs to ' +
177
+ 'add assignees. labels remains a legacy top-level alias. Duplicate top-level/metadata ' +
178
+ 'label/link aliases are refused. All fields use one updateChannelMeta call. xmtp-only. ' +
179
+ 'Returns updated metadata. Reread group_info to verify persistence.',
188
180
  inputSchema: {
189
181
  type: 'object',
190
182
  properties: {
191
183
  line: lineProp,
184
+ metadata: {
185
+ type: 'object',
186
+ description: 'Shallow JSON appData patch. Omitted keys stay unchanged. v is reserved.',
187
+ properties: {
188
+ labels: { type: 'array', items: { type: 'string' } },
189
+ assigned: {
190
+ type: 'array',
191
+ description: 'Replacement assignee list. Current member Ethereum addresses only. [] clears.',
192
+ items: { type: 'string', pattern: '^0x[0-9a-fA-F]{40}$' },
193
+ },
194
+ github: { type: 'string' },
195
+ preview: { type: 'string' },
196
+ },
197
+ additionalProperties: true,
198
+ },
192
199
  labels: {
193
200
  type: 'array',
194
- description: 'Status labels to set.',
201
+ description: 'Legacy alias. Prefer metadata.labels.',
195
202
  items: { type: 'string' },
196
203
  },
197
204
  github: {
@@ -1,7 +1,6 @@
1
- import { errMsg } from '@metro-labs/mcp/log';
2
- import { mintId, SELF_URI } from './wire.js';
3
-
4
- type EmitInbound = (accountId: string, e: Record<string, unknown>) => void;
1
+ import { errMsg } from '@metro-labs/core/log';
2
+ import { emitInbound, selfUri } from '@metro-labs/core/stations/train-events';
3
+ import { mintId } from '@metro-labs/core/stations/station-runtime';
5
4
 
6
5
  const WHISPER_BIN = process.env.METRO_WHISPER_BIN ?? 'whisper-cli';
7
6
  const WHISPER_MODEL =
@@ -14,7 +13,6 @@ export async function transcribeAndEmit(
14
13
  line: string,
15
14
  accountId: string,
16
15
  sourceMsgId: string,
17
- emitInbound: EmitInbound,
18
16
  ): Promise<void> {
19
17
  const {
20
18
  existsSync: ex,
@@ -69,7 +67,7 @@ export async function transcribeAndEmit(
69
67
  ts: new Date().toISOString(),
70
68
  station: 'xmtp',
71
69
  line,
72
- from: SELF_URI,
70
+ from: selfUri(),
73
71
  text: `🎙️ ${text}`,
74
72
  payload: {
75
73
  contentType: 'transcript',
@@ -1,7 +1,8 @@
1
1
  import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
2
  import { dirname } from 'node:path';
3
3
  import { Client, type ClientOptions, type Signer } from '@xmtp/node-sdk';
4
- import { expandHome, signerFor, XMTP_ENV } from './identity.js';
4
+ import { expandHome, identityFor, signerFor, XMTP_ENV } from './identity.js';
5
+ import { ensureDeployed } from './smart.js';
5
6
 
6
7
  export class XmtpVerifyError extends Error {}
7
8
 
@@ -10,6 +11,7 @@ export interface XmtpVerified {
10
11
  address: string;
11
12
  installationId: string;
12
13
  dbPath: string;
14
+ smart: boolean;
13
15
  }
14
16
 
15
17
  interface RegisteredClient {
@@ -34,15 +36,25 @@ const reason = (err: unknown): string =>
34
36
  export async function verifyXmtpKey(
35
37
  privateKey: string,
36
38
  dbPath: string,
39
+ smart = false,
37
40
  create: CreateXmtpClient = openInbox,
38
41
  ): Promise<XmtpVerified> {
39
- let signer: Signer;
40
- let address: string;
42
+ let identity: Awaited<ReturnType<typeof identityFor>>;
41
43
  try {
42
- ({ signer, address } = signerFor(privateKey));
44
+ signerFor(privateKey);
43
45
  } catch {
44
46
  throw new XmtpVerifyError('that is not a usable XMTP private key');
45
47
  }
48
+ try {
49
+ identity = await identityFor(privateKey, smart);
50
+ } catch (err) {
51
+ throw new XmtpVerifyError(`could not build the smart account on Base: ${reason(err)}`);
52
+ }
53
+ const { signer, address } = identity;
54
+ if (identity.smart !== null)
55
+ await ensureDeployed(identity.smart).catch((err: unknown) => {
56
+ throw new XmtpVerifyError(`could not deploy the smart account on Base (is the ZeroDev sponsorship still on?): ${reason(err)}`);
57
+ });
46
58
  const resolved = expandHome(dbPath);
47
59
  mkdirSync(dirname(resolved), { recursive: true });
48
60
  const client = await create(signer, resolved).catch((err: unknown) => {
@@ -59,6 +71,7 @@ export async function verifyXmtpKey(
59
71
  address,
60
72
  installationId: client.installationId,
61
73
  dbPath: resolved,
74
+ smart,
62
75
  };
63
76
  }
64
77
 
@@ -68,10 +81,11 @@ async function runCli(): Promise<void> {
68
81
  const input = JSON.parse(readFileSync(0, 'utf8')) as {
69
82
  privateKey?: unknown;
70
83
  dbPath?: unknown;
84
+ smart?: unknown;
71
85
  };
72
86
  if (typeof input.privateKey !== 'string' || typeof input.dbPath !== 'string')
73
87
  throw new XmtpVerifyError('xmtp verify needs a privateKey and a dbPath');
74
- out = { ok: true, ...(await verifyXmtpKey(input.privateKey, input.dbPath)) };
88
+ out = { ok: true, ...(await verifyXmtpKey(input.privateKey, input.dbPath, input.smart === true)) };
75
89
  } catch (err) {
76
90
  out = { ok: false, error: reason(err) };
77
91
  }
@@ -1,7 +1,3 @@
1
- export { emit, respond, mintId } from '@metro-labs/mcp/stations/station-runtime';
2
-
3
- export const SELF_URI = process.env.METRO_SELF_URI ?? '';
4
-
5
1
  const UID_MAP_MAX = 5000;
6
2
  const uidToXmtp = new Map<string, string>();
7
3
 
@@ -37,3 +33,17 @@ export function resolveMsgId(rawId: string): string {
37
33
  '(not seen by this train; pass the raw xmtp message_id)',
38
34
  );
39
35
  }
36
+
37
+ const SENT_MAX = 5000;
38
+ const sentIds = new Set<string>();
39
+
40
+ export function rememberSent(xmtpId: string | undefined): void {
41
+ if (!xmtpId) return;
42
+ sentIds.add(xmtpId);
43
+ if (sentIds.size > SENT_MAX) {
44
+ const oldest = sentIds.values().next().value;
45
+ if (oldest !== undefined) sentIds.delete(oldest);
46
+ }
47
+ }
48
+
49
+ export const sentByMe = (xmtpId: string): boolean => sentIds.has(xmtpId);
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "0.1.0-beta.23"
2
+ "version": "0.1.0-beta.231"
3
3
  }
@@ -0,0 +1 @@
1
+ import './node_modules/@metro-labs/daemon/src/server.ts';