@stage-labs/metro 0.1.0-beta.15 → 0.1.0-beta.151

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 (327) hide show
  1. package/dist/api.js +9 -0
  2. package/dist/claude-settings.js +40 -0
  3. package/dist/claude.js +182 -0
  4. package/dist/cli.js +86 -0
  5. package/dist/control.js +74 -0
  6. package/dist/hold.js +211 -0
  7. package/dist/local.js +77 -0
  8. package/dist/mcp-config.js +25 -0
  9. package/dist/node-name.js +71 -0
  10. package/dist/onboarding.js +43 -0
  11. package/dist/provider-flags.js +9 -0
  12. package/dist/route.js +50 -0
  13. package/dist/runtime-install.js +97 -0
  14. package/dist/runtime.js +74 -0
  15. package/dist/serve.js +155 -0
  16. package/dist/service.js +242 -0
  17. package/dist/tail.js +119 -0
  18. package/dist/update.js +45 -0
  19. package/dist/version.js +97 -0
  20. package/package.json +14 -28
  21. package/runtime/marketplace/.claude-plugin/marketplace.json +12 -0
  22. package/runtime/marketplace/plugin/.claude-plugin/plugin.json +18 -0
  23. package/runtime/marketplace/plugin/.mcp.json +1 -0
  24. package/runtime/marketplace/plugin/bin/guard.mjs +55 -0
  25. package/runtime/marketplace/plugin/bin/metro-plugin.mjs +40 -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 +16 -0
  29. package/runtime/node_modules/@metro-labs/core/package.json +43 -0
  30. package/runtime/node_modules/@metro-labs/core/src/address.ts +6 -0
  31. package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
  32. package/runtime/node_modules/@metro-labs/core/src/events.ts +120 -0
  33. package/runtime/node_modules/@metro-labs/core/src/identity.ts +7 -0
  34. package/runtime/node_modules/@metro-labs/core/src/ids.ts +21 -0
  35. package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
  36. package/runtime/node_modules/@metro-labs/core/src/lines.ts +87 -0
  37. package/runtime/node_modules/@metro-labs/core/src/log.ts +42 -0
  38. package/runtime/node_modules/@metro-labs/core/src/protocol.ts +226 -0
  39. package/runtime/node_modules/@metro-labs/core/src/secure-fs.ts +57 -0
  40. package/runtime/node_modules/@metro-labs/core/src/station-names.ts +13 -0
  41. package/runtime/node_modules/@metro-labs/core/src/stations/account-store.ts +60 -0
  42. package/runtime/node_modules/@metro-labs/core/src/stations/attachments.ts +196 -0
  43. package/runtime/node_modules/@metro-labs/core/src/stations/messaging-normalize.ts +88 -0
  44. package/runtime/node_modules/@metro-labs/core/src/stations/station-runtime.ts +64 -0
  45. package/runtime/node_modules/@metro-labs/core/src/stations/types.ts +108 -0
  46. package/runtime/node_modules/@metro-labs/core/src/str.ts +5 -0
  47. package/runtime/node_modules/@metro-labs/core/src/train-error.ts +53 -0
  48. package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
  49. package/runtime/node_modules/@metro-labs/daemon/package.json +47 -0
  50. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-attach.ts +19 -0
  51. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-routes.ts +70 -0
  52. package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +365 -0
  53. package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +39 -0
  54. package/runtime/node_modules/@metro-labs/daemon/src/agents/allowlist.ts +37 -0
  55. package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +225 -0
  56. package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +122 -0
  57. package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +364 -0
  58. package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +185 -0
  59. package/runtime/node_modules/@metro-labs/daemon/src/agents/keys.ts +40 -0
  60. package/runtime/node_modules/@metro-labs/daemon/src/agents/map.ts +95 -0
  61. package/runtime/node_modules/@metro-labs/daemon/src/agents/scope.ts +64 -0
  62. package/runtime/node_modules/@metro-labs/daemon/src/agents/senders.ts +38 -0
  63. package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +200 -0
  64. package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +39 -0
  65. package/runtime/node_modules/@metro-labs/daemon/src/boot/crash-guard.ts +49 -0
  66. package/runtime/node_modules/@metro-labs/daemon/src/boot/local-owner.ts +30 -0
  67. package/runtime/node_modules/@metro-labs/daemon/src/boot/paths.ts +106 -0
  68. package/runtime/node_modules/@metro-labs/daemon/src/channels/addressed.ts +25 -0
  69. package/runtime/node_modules/@metro-labs/daemon/src/channels/dedupe.ts +24 -0
  70. package/runtime/node_modules/@metro-labs/daemon/src/channels/inbound.ts +380 -0
  71. package/runtime/node_modules/@metro-labs/daemon/src/channels/media-note.ts +85 -0
  72. package/runtime/node_modules/@metro-labs/daemon/src/channels/pending.ts +75 -0
  73. package/runtime/node_modules/@metro-labs/daemon/src/channels/relay.ts +129 -0
  74. package/runtime/node_modules/@metro-labs/daemon/src/channels/webhook-note.ts +51 -0
  75. package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +354 -0
  76. package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +358 -0
  77. package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +169 -0
  78. package/runtime/node_modules/@metro-labs/daemon/src/claude/onboarding.ts +56 -0
  79. package/runtime/node_modules/@metro-labs/daemon/src/claude/plugin-install.ts +140 -0
  80. package/runtime/node_modules/@metro-labs/daemon/src/claude/session-files.ts +90 -0
  81. package/runtime/node_modules/@metro-labs/daemon/src/claude/session.ts +253 -0
  82. package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +117 -0
  83. package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +263 -0
  84. package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +118 -0
  85. package/runtime/node_modules/@metro-labs/daemon/src/claude/version.ts +109 -0
  86. package/runtime/node_modules/@metro-labs/daemon/src/connectors/api.ts +313 -0
  87. package/runtime/node_modules/@metro-labs/daemon/src/connectors/config.ts +157 -0
  88. package/runtime/node_modules/@metro-labs/daemon/src/connectors/health.ts +18 -0
  89. package/runtime/node_modules/@metro-labs/daemon/src/connectors/model.ts +69 -0
  90. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-client.ts +166 -0
  91. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-discovery.ts +139 -0
  92. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-pending.ts +65 -0
  93. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-routes.ts +171 -0
  94. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth.ts +155 -0
  95. package/runtime/node_modules/@metro-labs/daemon/src/connectors/plugin-sync.ts +122 -0
  96. package/runtime/node_modules/@metro-labs/daemon/src/connectors/reach.ts +27 -0
  97. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-target.ts +39 -0
  98. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +304 -0
  99. package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +299 -0
  100. package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +108 -0
  101. package/runtime/node_modules/@metro-labs/daemon/src/connectors/url.ts +59 -0
  102. package/runtime/node_modules/@metro-labs/daemon/src/connectors/verify.ts +101 -0
  103. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-grant.ts +99 -0
  104. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-owner.ts +32 -0
  105. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-serve.ts +121 -0
  106. package/runtime/node_modules/@metro-labs/daemon/src/files/upload-api.ts +294 -0
  107. package/runtime/node_modules/@metro-labs/daemon/src/files/upload-store.ts +181 -0
  108. package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +259 -0
  109. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +231 -0
  110. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-device.ts +91 -0
  111. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +288 -0
  112. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +203 -0
  113. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +231 -0
  114. package/runtime/node_modules/@metro-labs/daemon/src/gateway/eventstream.ts +123 -0
  115. package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +187 -0
  116. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +247 -0
  117. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-auth.ts +182 -0
  118. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-client.ts +46 -0
  119. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-setup.ts +150 -0
  120. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-stream.ts +148 -0
  121. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-translate.ts +201 -0
  122. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini.ts +257 -0
  123. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +353 -0
  124. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +232 -0
  125. package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +90 -0
  126. package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +65 -0
  127. package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +17 -0
  128. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +242 -0
  129. package/runtime/node_modules/@metro-labs/daemon/src/mcp/accounts.ts +151 -0
  130. package/runtime/node_modules/@metro-labs/daemon/src/mcp/call-tools.ts +216 -0
  131. package/runtime/node_modules/@metro-labs/daemon/src/mcp/channel-owner.ts +29 -0
  132. package/runtime/node_modules/@metro-labs/daemon/src/mcp/ctx.ts +62 -0
  133. package/runtime/node_modules/@metro-labs/daemon/src/mcp/event-store.ts +91 -0
  134. package/runtime/node_modules/@metro-labs/daemon/src/mcp/frame-scope.ts +21 -0
  135. package/runtime/node_modules/@metro-labs/daemon/src/mcp/group-tools.ts +129 -0
  136. package/runtime/node_modules/@metro-labs/daemon/src/mcp/index.ts +186 -0
  137. package/runtime/node_modules/@metro-labs/daemon/src/mcp/member-tools.ts +72 -0
  138. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +66 -0
  139. package/runtime/node_modules/@metro-labs/daemon/src/mcp/raw-get-stream.ts +207 -0
  140. package/runtime/node_modules/@metro-labs/daemon/src/mcp/request-identity.ts +47 -0
  141. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-registry.ts +172 -0
  142. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-route.ts +43 -0
  143. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session.ts +215 -0
  144. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-dispatch.ts +215 -0
  145. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-schemas.ts +400 -0
  146. package/runtime/node_modules/@metro-labs/daemon/src/mcp/upload-tool.ts +66 -0
  147. package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +237 -0
  148. package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +389 -0
  149. package/runtime/node_modules/@metro-labs/daemon/src/routes/bearer.ts +35 -0
  150. package/runtime/node_modules/@metro-labs/daemon/src/routes/body.ts +24 -0
  151. package/runtime/node_modules/@metro-labs/daemon/src/routes/http.ts +370 -0
  152. package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +210 -0
  153. package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +58 -0
  154. package/runtime/node_modules/@metro-labs/daemon/src/routes/session.ts +29 -0
  155. package/runtime/node_modules/@metro-labs/daemon/src/routes/threema-callback.ts +103 -0
  156. package/runtime/node_modules/@metro-labs/daemon/src/server/control.ts +65 -0
  157. package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +80 -0
  158. package/runtime/node_modules/@metro-labs/daemon/src/server/owner.ts +48 -0
  159. package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +117 -0
  160. package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
  161. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-inline.ts +100 -0
  162. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-interactive.ts +161 -0
  163. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-resolve.ts +202 -0
  164. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-session.ts +280 -0
  165. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-xmtp.ts +111 -0
  166. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach.ts +248 -0
  167. package/runtime/node_modules/@metro-labs/daemon/src/stations/materialize.ts +261 -0
  168. package/runtime/node_modules/@metro-labs/daemon/src/stations/registry.ts +37 -0
  169. package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +82 -0
  170. package/runtime/node_modules/@metro-labs/daemon/src/stations/supervisor-io.ts +97 -0
  171. package/runtime/node_modules/@metro-labs/daemon/src/stations/supervisor.ts +320 -0
  172. package/runtime/node_modules/@metro-labs/daemon/src/stations/threema-callbacks.ts +32 -0
  173. package/runtime/node_modules/@metro-labs/daemon/src/stations/train-call.ts +22 -0
  174. package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +97 -0
  175. package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +123 -0
  176. package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +40 -0
  177. package/runtime/node_modules/@metro-labs/discord-bot/package.json +28 -0
  178. package/runtime/node_modules/@metro-labs/discord-bot/src/accounts.ts +118 -0
  179. package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +388 -0
  180. package/runtime/node_modules/@metro-labs/discord-bot/src/api-base.ts +1 -0
  181. package/runtime/node_modules/@metro-labs/discord-bot/src/attachments.ts +29 -0
  182. package/runtime/node_modules/@metro-labs/discord-bot/src/format.ts +220 -0
  183. package/runtime/node_modules/@metro-labs/discord-bot/src/group-actions.ts +50 -0
  184. package/runtime/node_modules/@metro-labs/discord-bot/src/group.ts +115 -0
  185. package/runtime/node_modules/@metro-labs/discord-bot/src/index.ts +127 -0
  186. package/runtime/node_modules/@metro-labs/discord-bot/src/members.ts +215 -0
  187. package/runtime/node_modules/@metro-labs/discord-bot/src/send-files.ts +43 -0
  188. package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +19 -0
  189. package/runtime/node_modules/@metro-labs/discord-bot/src/verify.ts +82 -0
  190. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-speak.ts +195 -0
  191. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-transcribe.ts +292 -0
  192. package/runtime/node_modules/@metro-labs/discord-bot/src/voice.ts +197 -0
  193. package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +5 -0
  194. package/runtime/node_modules/@metro-labs/http/package.json +29 -0
  195. package/runtime/node_modules/@metro-labs/http/src/api-error.ts +8 -0
  196. package/runtime/node_modules/@metro-labs/http/src/api-http.ts +106 -0
  197. package/runtime/node_modules/@metro-labs/http/src/cors.ts +29 -0
  198. package/runtime/node_modules/@metro-labs/http/src/mode-api.ts +32 -0
  199. package/runtime/node_modules/@metro-labs/http/src/return-to.ts +21 -0
  200. package/runtime/node_modules/@metro-labs/http/src/workos-token.ts +150 -0
  201. package/runtime/node_modules/@metro-labs/telegram/package.json +26 -0
  202. package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +80 -0
  203. package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +254 -0
  204. package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +87 -0
  205. package/runtime/node_modules/@metro-labs/telegram/src/client.ts +77 -0
  206. package/runtime/node_modules/@metro-labs/telegram/src/format.ts +156 -0
  207. package/runtime/node_modules/@metro-labs/telegram/src/group.ts +261 -0
  208. package/runtime/node_modules/@metro-labs/telegram/src/history.ts +52 -0
  209. package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +78 -0
  210. package/runtime/node_modules/@metro-labs/telegram/src/index.ts +46 -0
  211. package/runtime/node_modules/@metro-labs/telegram/src/login.ts +166 -0
  212. package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +80 -0
  213. package/runtime/node_modules/@metro-labs/telegram/src/members.ts +75 -0
  214. package/runtime/node_modules/@metro-labs/telegram/src/normalize.ts +22 -0
  215. package/runtime/node_modules/@metro-labs/telegram/src/reactions.ts +167 -0
  216. package/runtime/node_modules/@metro-labs/telegram/src/station.ts +24 -0
  217. package/runtime/node_modules/@metro-labs/telegram/src/types.ts +7 -0
  218. package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +1 -0
  219. package/runtime/node_modules/@metro-labs/telegram-bot/package.json +25 -0
  220. package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +120 -0
  221. package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +295 -0
  222. package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +128 -0
  223. package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +201 -0
  224. package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +109 -0
  225. package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +166 -0
  226. package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +47 -0
  227. package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +17 -0
  228. package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +58 -0
  229. package/runtime/node_modules/@metro-labs/telegram-bot/src/verify.ts +38 -0
  230. package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +3 -0
  231. package/runtime/node_modules/@metro-labs/threema/package.json +26 -0
  232. package/runtime/node_modules/@metro-labs/threema/src/accounts.ts +100 -0
  233. package/runtime/node_modules/@metro-labs/threema/src/actions.ts +223 -0
  234. package/runtime/node_modules/@metro-labs/threema/src/api.ts +130 -0
  235. package/runtime/node_modules/@metro-labs/threema/src/crypto.ts +132 -0
  236. package/runtime/node_modules/@metro-labs/threema/src/format.ts +123 -0
  237. package/runtime/node_modules/@metro-labs/threema/src/ids.ts +21 -0
  238. package/runtime/node_modules/@metro-labs/threema/src/index.ts +29 -0
  239. package/runtime/node_modules/@metro-labs/threema/src/station.ts +10 -0
  240. package/runtime/node_modules/@metro-labs/threema/src/verify.ts +117 -0
  241. package/runtime/node_modules/@metro-labs/webhook/package.json +23 -0
  242. package/runtime/node_modules/@metro-labs/webhook/src/station.ts +37 -0
  243. package/runtime/node_modules/@metro-labs/whatsapp/package.json +27 -0
  244. package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +66 -0
  245. package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +101 -0
  246. package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +190 -0
  247. package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +72 -0
  248. package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +129 -0
  249. package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +347 -0
  250. package/runtime/node_modules/@metro-labs/whatsapp/src/delivery.ts +49 -0
  251. package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +138 -0
  252. package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +57 -0
  253. package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +40 -0
  254. package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +59 -0
  255. package/runtime/node_modules/@metro-labs/whatsapp/src/logger.ts +60 -0
  256. package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +176 -0
  257. package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +84 -0
  258. package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +22 -0
  259. package/runtime/node_modules/@metro-labs/whatsapp/src/outbox.ts +38 -0
  260. package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +185 -0
  261. package/runtime/node_modules/@metro-labs/whatsapp/src/resolve.ts +52 -0
  262. package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +18 -0
  263. package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +98 -0
  264. package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +6 -0
  265. package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +5 -0
  266. package/runtime/node_modules/@metro-labs/xmtp/package.json +33 -0
  267. package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +112 -0
  268. package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +110 -0
  269. package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +299 -0
  270. package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +157 -0
  271. package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +87 -0
  272. package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +375 -0
  273. package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +107 -0
  274. package/runtime/node_modules/@metro-labs/xmtp/src/codecs.ts +171 -0
  275. package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +239 -0
  276. package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +55 -0
  277. package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +335 -0
  278. package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +80 -0
  279. package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +34 -0
  280. package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +56 -0
  281. package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +33 -0
  282. package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +125 -0
  283. package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +157 -0
  284. package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +40 -0
  285. package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +349 -0
  286. package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +13 -0
  287. package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +126 -0
  288. package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +212 -0
  289. package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +90 -0
  290. package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +84 -0
  291. package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +53 -0
  292. package/runtime/runtime.json +3 -0
  293. package/runtime/server.ts +1 -0
  294. package/runtime/stations.json +37 -0
  295. package/runtime/trains/.keep +0 -0
  296. package/LICENSE +0 -21
  297. package/README.md +0 -139
  298. package/dist/broker/claims.js +0 -144
  299. package/dist/broker/history-stream.js +0 -149
  300. package/dist/cli/config.js +0 -179
  301. package/dist/cli/index.js +0 -175
  302. package/dist/cli/messenger-api.js +0 -214
  303. package/dist/cli/messenger-transcribe.js +0 -43
  304. package/dist/cli/messenger-uploads.js +0 -116
  305. package/dist/cli/monitor-api.js +0 -205
  306. package/dist/cli/tail.js +0 -95
  307. package/dist/cli/util.js +0 -72
  308. package/dist/cli/webhook.js +0 -181
  309. package/dist/codex-rc/client.js +0 -225
  310. package/dist/codex-rc/protocol.js +0 -38
  311. package/dist/dispatcher/server.js +0 -122
  312. package/dist/dispatcher.js +0 -97
  313. package/dist/history.js +0 -143
  314. package/dist/ipc.js +0 -90
  315. package/dist/lines.js +0 -54
  316. package/dist/local-identity.js +0 -80
  317. package/dist/log.js +0 -15
  318. package/dist/paths.js +0 -114
  319. package/dist/trains/protocol.js +0 -99
  320. package/dist/trains/supervisor.js +0 -210
  321. package/dist/tunnel.js +0 -102
  322. package/docs/broker.md +0 -166
  323. package/docs/monitor.md +0 -241
  324. package/docs/uri-scheme.md +0 -127
  325. package/examples/README.md +0 -32
  326. package/examples/telegram.ts +0 -121
  327. package/skills/metro/SKILL.md +0 -110
@@ -0,0 +1,202 @@
1
+ import {
2
+ assertAttachmentSize,
3
+ assertContentLength,
4
+ guessMime,
5
+ saveBufferToCache,
6
+ } from '@metro-labs/core/stations/attachments';
7
+ import {
8
+ assertInlineTotal,
9
+ decodeInline,
10
+ removeInlineTemp,
11
+ splitInlineData,
12
+ writeInlineTemp,
13
+ } from './attach-inline.js';
14
+ import { realpathSync } from 'node:fs';
15
+ import { log } from '@metro-labs/core/log';
16
+ import { readUpload, UPLOAD_TTL_MS } from '../files/upload-store.js';
17
+ import type { CanonicalAttachment } from '@metro-labs/core/stations/types';
18
+
19
+ export interface ResolvedAttachment {
20
+ path: string;
21
+ mime: string;
22
+ name: string;
23
+ bytes: number;
24
+ temp?: string;
25
+ }
26
+
27
+ export interface ResolveOptions {
28
+ allowed?: Set<string>;
29
+ }
30
+
31
+ interface InlineBudget {
32
+ used: number;
33
+ }
34
+
35
+ const FETCH_TIMEOUT_MS = 60_000;
36
+
37
+ const basenameOf = (src: string): string =>
38
+ src.split('?')[0]?.split('#')[0]?.split('/').filter(Boolean).pop() ?? '';
39
+
40
+ const isHttpUrl = (src: string): boolean => /^https?:\/\//i.test(src);
41
+
42
+ const mintId = (): string => Math.random().toString(36).slice(2, 12);
43
+
44
+ const HIDDEN_SEGMENT = /(^|\/)\.[^/]/;
45
+
46
+ function assertReadablePath(path: string): void {
47
+ let real: string;
48
+ try {
49
+ real = realpathSync(path);
50
+ } catch {
51
+ return;
52
+ }
53
+ if (HIDDEN_SEGMENT.test(real))
54
+ throw new Error(
55
+ `attachment path '${path}' resolves into a hidden directory ` +
56
+ `('${real}') and will not be read. \`path\` is read on the daemon ` +
57
+ 'machine; put the file somewhere non-hidden or pass `upload` instead.',
58
+ );
59
+ }
60
+
61
+ async function fromPath(
62
+ a: CanonicalAttachment,
63
+ path: string,
64
+ ): Promise<ResolvedAttachment> {
65
+ assertReadablePath(path);
66
+ const file = Bun.file(path);
67
+ if (!(await file.exists()))
68
+ throw new Error(
69
+ `attachment path '${path}' does not exist on the metro host. ` +
70
+ '`path` is read on the daemon machine, not on the caller\'s machine; ' +
71
+ 'pass `url` instead if the file is not already on the daemon.',
72
+ );
73
+ assertAttachmentSize(file.size);
74
+ return {
75
+ path,
76
+ mime: a.mime ?? guessMime(path),
77
+ name: a.name ?? basenameOf(path) ?? 'attachment',
78
+ bytes: file.size,
79
+ };
80
+ }
81
+
82
+ async function fromUrl(
83
+ a: CanonicalAttachment,
84
+ url: string,
85
+ ): Promise<ResolvedAttachment> {
86
+ if (!isHttpUrl(url))
87
+ throw new Error(
88
+ `attachment url '${url}' is not an http(s) url; use \`path\` for a local file`,
89
+ );
90
+ const res = await fetch(url, {
91
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
92
+ });
93
+ if (!res.ok)
94
+ throw new Error(`attachment fetch failed ${res.status} for '${url}'`);
95
+ assertContentLength(res.headers.get('content-length'));
96
+ const data = new Uint8Array(await res.arrayBuffer());
97
+ const mime =
98
+ a.mime ?? res.headers.get('content-type')?.split(';')[0] ?? guessMime(url);
99
+ const name = a.name ?? basenameOf(url) ?? 'attachment';
100
+ const saved = await saveBufferToCache(data, `out${mintId()}`, 0, {
101
+ mime,
102
+ name,
103
+ });
104
+ return { path: saved.path, mime, name, bytes: data.length };
105
+ }
106
+
107
+ async function fromData(
108
+ a: CanonicalAttachment,
109
+ data: string,
110
+ budget: InlineBudget,
111
+ ): Promise<ResolvedAttachment> {
112
+ const name = a.name ?? 'attachment';
113
+ const source = splitInlineData(data);
114
+ const bytes = decodeInline(source.data, `'${name}'`);
115
+ budget.used += bytes.length;
116
+ assertInlineTotal(budget.used);
117
+ const { dir, path } = await writeInlineTemp(bytes, a.name);
118
+ return {
119
+ path,
120
+ mime: a.mime ?? source.mime ?? guessMime(name),
121
+ name,
122
+ bytes: bytes.length,
123
+ temp: dir,
124
+ };
125
+ }
126
+
127
+ const uploadMissing = (id: string): Error =>
128
+ new Error(
129
+ `upload '${id}' is not a live upload of yours. Either it was never created, or its ` +
130
+ 'bytes were never pushed to `POST /api/uploads`, or it belongs to another agent, or ' +
131
+ `it expired (an upload lives ${Math.round(UPLOAD_TTL_MS / 60_000)} minutes). ` +
132
+ 'Create a new one with `create_upload` and push the file again.',
133
+ );
134
+
135
+ function fromUpload(
136
+ a: CanonicalAttachment,
137
+ id: string,
138
+ allowed: Set<string> | undefined,
139
+ ): ResolvedAttachment {
140
+ const rec = allowed === undefined ? undefined : readUpload(id);
141
+ if (rec === undefined || !(allowed?.has(rec.agentId) ?? false))
142
+ throw uploadMissing(id);
143
+ const name = a.name ?? rec.name;
144
+ return { path: rec.path, mime: a.mime ?? rec.mime, name, bytes: rec.bytes };
145
+ }
146
+
147
+ export const SOURCE_KEYS = ['path', 'url', 'data', 'upload'] as const;
148
+
149
+ const sourcesOf = (a: CanonicalAttachment): string[] =>
150
+ SOURCE_KEYS.filter((k) => {
151
+ const v = a[k];
152
+ return typeof v === 'string' && v.length > 0;
153
+ });
154
+
155
+ async function resolveAttachment(
156
+ a: CanonicalAttachment,
157
+ budget: InlineBudget = { used: 0 },
158
+ opts: ResolveOptions = {},
159
+ ): Promise<ResolvedAttachment> {
160
+ const sources = sourcesOf(a);
161
+ if (sources.length === 0)
162
+ throw new Error(
163
+ 'attachment requires exactly one of `upload`, `data`, `url` or `path`',
164
+ );
165
+ if (sources.length > 1)
166
+ throw new Error(
167
+ `attachment names ${sources.length} sources (${sources
168
+ .map((s) => `\`${s}\``)
169
+ .join(', ')}); pass exactly one of \`upload\`, \`data\`, \`url\` or \`path\``,
170
+ );
171
+ log.info({ source: sources[0] }, 'send: attachment source');
172
+ if (a.upload) return fromUpload(a, a.upload, opts.allowed);
173
+ if (a.data) return fromData(a, a.data, budget);
174
+ if (a.path) return fromPath(a, a.path);
175
+ return fromUrl(a, a.url ?? '');
176
+ }
177
+
178
+ export async function cleanupAttachments(
179
+ atts: ResolvedAttachment[],
180
+ ): Promise<void> {
181
+ for (const a of atts) if (a.temp) await removeInlineTemp(a.temp);
182
+ }
183
+
184
+ export async function resolveAttachments(
185
+ atts: CanonicalAttachment[],
186
+ opts: ResolveOptions = {},
187
+ ): Promise<ResolvedAttachment[]> {
188
+ const out: ResolvedAttachment[] = [];
189
+ const budget: InlineBudget = { used: 0 };
190
+ for (let i = 0; i < atts.length; i++) {
191
+ const a = atts[i];
192
+ if (!a) continue;
193
+ try {
194
+ out.push(await resolveAttachment(a, budget, opts));
195
+ } catch (e) {
196
+ await cleanupAttachments(out);
197
+ const why = e instanceof Error ? e.message : String(e);
198
+ throw new Error(`attachment ${i + 1} of ${atts.length}: ${why}`);
199
+ }
200
+ }
201
+ return out;
202
+ }
@@ -0,0 +1,280 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { ApiError } from '@metro-labs/http/api-error';
3
+ import { errMsg, log } from '@metro-labs/core/log';
4
+ import type { StationName } from '@metro-labs/core/station-names';
5
+ import { ensureStationDeps } from './runtime-deps.js';
6
+ import {
7
+ startInteractiveAttach,
8
+ type AttachDriver,
9
+ type AttachOutcome,
10
+ type AttachPrompt,
11
+ type AttachStep,
12
+ type DriverHooks,
13
+ type InteractiveStation,
14
+ type StartedAttach,
15
+ } from './attach-interactive.js';
16
+
17
+ export type StartAttach = (
18
+ station: InteractiveStation,
19
+ input: Record<string, unknown>,
20
+ hooks: DriverHooks,
21
+ ) => Promise<StartedAttach>;
22
+
23
+ export const ATTACH_ID_RE = /^as_[A-Za-z0-9_-]{22}$/;
24
+
25
+ const PENDING_TTL_MS = 5 * 60_000;
26
+ const SETTLED_TTL_MS = 60_000;
27
+ const SWEEP_MS = 15_000;
28
+ const MAX_PER_AGENT = 2;
29
+ const MAX_TOTAL = 40;
30
+
31
+ export interface AttachOwner {
32
+ subject: string;
33
+ agentId: string;
34
+ }
35
+
36
+ export interface AttachView {
37
+ attachId: string;
38
+ station: string;
39
+ status: 'pending' | 'done' | 'failed';
40
+ step: AttachStep | null;
41
+ prompt: string;
42
+ qr: string | null;
43
+ pairingCode: string | null;
44
+ accountId: string | null;
45
+ identity: Record<string, string>;
46
+ activated: boolean;
47
+ error: string | null;
48
+ expiresAt: number;
49
+ }
50
+
51
+ export type CompleteAttach = (
52
+ owner: AttachOwner,
53
+ station: StationName,
54
+ config: Record<string, unknown>,
55
+ ) => Promise<{ accountId: string; activated: boolean }>;
56
+
57
+ export type AuthorizeAttach = (owner: AttachOwner) => Promise<void>;
58
+
59
+ export interface AttachSessionDeps {
60
+ authorize: AuthorizeAttach;
61
+ complete: CompleteAttach;
62
+ start?: StartAttach;
63
+ }
64
+
65
+ interface Session {
66
+ owner: AttachOwner;
67
+ driver: AttachDriver | null;
68
+ view: AttachView;
69
+ }
70
+
71
+ const missing = (): ApiError => new ApiError('no such attach session', 404);
72
+
73
+ function newAttachId(): string {
74
+ return `as_${randomBytes(16).toString('base64url')}`;
75
+ }
76
+
77
+ function blankView(attachId: string, station: string): AttachView {
78
+ return {
79
+ attachId,
80
+ station,
81
+ status: 'pending',
82
+ step: null,
83
+ prompt: '',
84
+ qr: null,
85
+ pairingCode: null,
86
+ accountId: null,
87
+ identity: {},
88
+ activated: false,
89
+ error: null,
90
+ expiresAt: Date.now() + PENDING_TTL_MS,
91
+ };
92
+ }
93
+
94
+ export class AttachSessions {
95
+ private sessions = new Map<string, Session>();
96
+ private sweeper: ReturnType<typeof setInterval> | null = null;
97
+
98
+ constructor(private deps: AttachSessionDeps) {}
99
+
100
+ private ensureSweeper(): void {
101
+ if (this.sweeper) return;
102
+ this.sweeper = setInterval(() => {
103
+ this.sweep().catch((err: unknown) => {
104
+ log.warn({ err: errMsg(err) }, 'attach-session: sweep failed');
105
+ });
106
+ }, SWEEP_MS);
107
+ this.sweeper.unref();
108
+ }
109
+
110
+ private own(owner: AttachOwner, attachId: string): Session {
111
+ const session = this.sessions.get(attachId);
112
+ if (
113
+ session?.owner.subject !== owner.subject ||
114
+ session.owner.agentId !== owner.agentId
115
+ )
116
+ throw missing();
117
+ return session;
118
+ }
119
+
120
+ private admit(owner: AttachOwner): void {
121
+ if (this.sessions.size >= MAX_TOTAL)
122
+ throw new ApiError(
123
+ 'too many sign-ins are in flight on this daemon, try again shortly',
124
+ 429,
125
+ );
126
+ const mine = [...this.sessions.values()].filter(
127
+ (s) => s.owner.agentId === owner.agentId && s.view.status === 'pending',
128
+ );
129
+ if (mine.length >= MAX_PER_AGENT)
130
+ throw new ApiError(
131
+ 'this agent already has a sign-in in progress, finish or cancel it first',
132
+ 409,
133
+ );
134
+ }
135
+
136
+ private settle(session: Session, patch: Partial<AttachView>): void {
137
+ Object.assign(session.view, patch, {
138
+ qr: null,
139
+ pairingCode: null,
140
+ step: null,
141
+ expiresAt: Date.now() + SETTLED_TTL_MS,
142
+ });
143
+ session.driver = null;
144
+ }
145
+
146
+ private async finish(
147
+ attachId: string,
148
+ station: StationName,
149
+ outcome: AttachOutcome,
150
+ ): Promise<void> {
151
+ const session = this.sessions.get(attachId);
152
+ if (session?.view.status !== 'pending') return;
153
+ try {
154
+ const landed = await this.deps.complete(
155
+ session.owner,
156
+ station,
157
+ outcome.config,
158
+ );
159
+ this.settle(session, {
160
+ status: 'done',
161
+ prompt: '',
162
+ identity: outcome.identity,
163
+ accountId: landed.accountId,
164
+ activated: landed.activated,
165
+ });
166
+ log.info(
167
+ { agentId: session.owner.agentId, station, account: landed.accountId },
168
+ 'attach-session: signed in and attached a station account',
169
+ );
170
+ } catch (err) {
171
+ const reason =
172
+ err instanceof ApiError ? err.message : 'could not store the account';
173
+ log.warn({ station, err: errMsg(err) }, 'attach-session: store failed');
174
+ this.settle(session, { status: 'failed', prompt: '', error: reason });
175
+ }
176
+ }
177
+
178
+ private hooksFor(attachId: string, station: StationName) {
179
+ return {
180
+ prompt: (p: AttachPrompt): void => {
181
+ const session = this.sessions.get(attachId);
182
+ if (session?.view.status !== 'pending') return;
183
+ session.view.step = p.step;
184
+ session.view.prompt = p.prompt;
185
+ session.view.qr = p.qr ?? null;
186
+ session.view.pairingCode = p.pairingCode ?? null;
187
+ },
188
+ done: (o: AttachOutcome): void => {
189
+ this.finish(attachId, station, o).catch((err: unknown) => {
190
+ log.warn(
191
+ { attachId, station, err: errMsg(err) },
192
+ 'attach-session: completion failed',
193
+ );
194
+ });
195
+ },
196
+ fail: (message: string): void => {
197
+ const session = this.sessions.get(attachId);
198
+ if (session?.view.status !== 'pending') return;
199
+ this.settle(session, { status: 'failed', prompt: '', error: message });
200
+ },
201
+ };
202
+ }
203
+
204
+ async start(
205
+ owner: AttachOwner,
206
+ station: InteractiveStation,
207
+ input: Record<string, unknown>,
208
+ ): Promise<AttachView> {
209
+ await this.deps.authorize(owner);
210
+ this.admit(owner);
211
+ this.ensureSweeper();
212
+ const attachId = newAttachId();
213
+ const session: Session = {
214
+ owner,
215
+ driver: null,
216
+ view: blankView(attachId, station),
217
+ };
218
+ this.sessions.set(attachId, session);
219
+ try {
220
+ ensureStationDeps(station);
221
+ const started = await (this.deps.start ?? startInteractiveAttach)(
222
+ station,
223
+ input,
224
+ this.hooksFor(attachId, station),
225
+ );
226
+ session.driver = started.driver;
227
+ this.hooksFor(attachId, station).prompt(started.prompt);
228
+ } catch (err) {
229
+ this.sessions.delete(attachId);
230
+ throw err;
231
+ }
232
+ log.info(
233
+ { agentId: owner.agentId, station, attachId },
234
+ 'attach-session: started',
235
+ );
236
+ return { ...session.view };
237
+ }
238
+
239
+ view(owner: AttachOwner, attachId: string): AttachView {
240
+ return { ...this.own(owner, attachId).view };
241
+ }
242
+
243
+ async submit(
244
+ owner: AttachOwner,
245
+ attachId: string,
246
+ input: { code?: unknown; password?: unknown },
247
+ ): Promise<AttachView> {
248
+ const session = this.own(owner, attachId);
249
+ const driver = session.driver;
250
+ if (session.view.status !== 'pending' || !driver)
251
+ throw new ApiError('this sign-in is already finished', 409);
252
+ await driver.submit(input);
253
+ return { ...session.view };
254
+ }
255
+
256
+ async cancel(owner: AttachOwner, attachId: string): Promise<void> {
257
+ const session = this.own(owner, attachId);
258
+ this.sessions.delete(attachId);
259
+ await session.driver?.cancel().catch(() => undefined);
260
+ log.info({ attachId }, 'attach-session: cancelled');
261
+ }
262
+
263
+ async sweep(now = Date.now()): Promise<void> {
264
+ for (const [attachId, session] of [...this.sessions]) {
265
+ if (session.view.expiresAt > now) continue;
266
+ this.sessions.delete(attachId);
267
+ const driver = session.driver;
268
+ session.driver = null;
269
+ if (!driver) continue;
270
+ log.info({ attachId }, 'attach-session: expired, credentials discarded');
271
+ await driver.cancel().catch(() => undefined);
272
+ }
273
+ }
274
+
275
+ async stop(): Promise<void> {
276
+ if (this.sweeper) clearInterval(this.sweeper);
277
+ this.sweeper = null;
278
+ await this.sweep(Number.MAX_SAFE_INTEGER);
279
+ }
280
+ }
@@ -0,0 +1,111 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { rmSync } from 'node:fs';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { errMsg, log } from '@metro-labs/core/log';
5
+
6
+ export class XmtpAttachError extends Error {}
7
+
8
+ export interface XmtpIdentity {
9
+ inboxId: string;
10
+ address: string;
11
+ installationId: string;
12
+ dbPath: string;
13
+ }
14
+
15
+ export type VerifyXmtpKey = (
16
+ privateKey: string,
17
+ dbPath: string,
18
+ ) => Promise<XmtpIdentity>;
19
+
20
+ const VERIFY_TIMEOUT_MS = 90_000;
21
+ const UNREACHABLE =
22
+ 'Metro could not open an XMTP inbox with the key it generated, so nothing was attached';
23
+
24
+ export function newXmtpDbPath(): string {
25
+ return `~/.metro/xmtp-production-${randomBytes(8).toString('hex')}.db3`;
26
+ }
27
+
28
+ export function discardXmtpDb(dbPath: string): void {
29
+ for (const suffix of ['', '-wal', '-shm'])
30
+ rmSync(`${dbPath}${suffix}`, { force: true });
31
+ }
32
+
33
+ export function withoutKey(message: string, privateKey: string): string {
34
+ return message.split(privateKey).join('[redacted]');
35
+ }
36
+
37
+ interface VerifyReply {
38
+ ok?: unknown;
39
+ inboxId?: unknown;
40
+ address?: unknown;
41
+ installationId?: unknown;
42
+ dbPath?: unknown;
43
+ error?: unknown;
44
+ }
45
+
46
+ const str = (value: unknown): string => (typeof value === 'string' ? value : '');
47
+
48
+ function readReply(raw: string): VerifyReply {
49
+ const line = raw.trim().split('\n').at(-1) ?? '';
50
+ try {
51
+ const parsed: unknown = JSON.parse(line);
52
+ return typeof parsed === 'object' && parsed !== null ? parsed : {};
53
+ } catch {
54
+ return {};
55
+ }
56
+ }
57
+
58
+ async function runVerifier(payload: string): Promise<string> {
59
+ const script = fileURLToPath(import.meta.resolve('@metro-labs/xmtp/verify'));
60
+ const proc = Bun.spawn(['bun', 'run', script], {
61
+ stdin: 'pipe',
62
+ stdout: 'pipe',
63
+ stderr: 'pipe',
64
+ });
65
+ await proc.stdin.write(payload);
66
+ await proc.stdin.end();
67
+ const timer = setTimeout(() => {
68
+ proc.kill();
69
+ }, VERIFY_TIMEOUT_MS);
70
+ try {
71
+ const [out, err, code] = await Promise.all([
72
+ new Response(proc.stdout).text(),
73
+ new Response(proc.stderr).text(),
74
+ proc.exited,
75
+ ]);
76
+ if (code !== 0)
77
+ log.warn(
78
+ { code, stderr: err.trim().slice(-500) },
79
+ 'attach-xmtp: the inbox check exited badly',
80
+ );
81
+ return out;
82
+ } finally {
83
+ clearTimeout(timer);
84
+ }
85
+ }
86
+
87
+ export async function verifyXmtpKeyOutOfProcess(
88
+ privateKey: string,
89
+ dbPath: string,
90
+ ): Promise<XmtpIdentity> {
91
+ const raw = await runVerifier(
92
+ JSON.stringify({ privateKey, dbPath }),
93
+ ).catch((err: unknown) => {
94
+ log.warn({ err: errMsg(err) }, 'attach-xmtp: could not run the inbox check');
95
+ throw new XmtpAttachError(UNREACHABLE);
96
+ });
97
+ const reply = readReply(raw);
98
+ if (reply.ok !== true)
99
+ throw new XmtpAttachError(
100
+ withoutKey(str(reply.error) || UNREACHABLE, privateKey),
101
+ );
102
+ const identity = {
103
+ inboxId: str(reply.inboxId),
104
+ address: str(reply.address),
105
+ installationId: str(reply.installationId),
106
+ dbPath: str(reply.dbPath),
107
+ };
108
+ if (identity.inboxId === '' || identity.address === '')
109
+ throw new XmtpAttachError(UNREACHABLE);
110
+ return identity;
111
+ }