@stage-labs/metro 0.1.0-beta.13 → 0.1.0-beta.131

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 (329) hide show
  1. package/dist/api.js +14 -0
  2. package/dist/claude-settings.js +40 -0
  3. package/dist/claude.js +176 -0
  4. package/dist/cli.js +101 -0
  5. package/dist/control.js +74 -0
  6. package/dist/hold.js +211 -0
  7. package/dist/local.js +93 -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/plugin.js +120 -0
  12. package/dist/provider-flags.js +9 -0
  13. package/dist/route.js +38 -0
  14. package/dist/runtime-install.js +97 -0
  15. package/dist/runtime.js +74 -0
  16. package/dist/serve.js +150 -0
  17. package/dist/service.js +242 -0
  18. package/dist/tail.js +119 -0
  19. package/dist/update.js +45 -0
  20. package/dist/version.js +97 -0
  21. package/package.json +14 -27
  22. package/runtime/marketplace/.claude-plugin/marketplace.json +12 -0
  23. package/runtime/marketplace/plugin/.claude-plugin/plugin.json +18 -0
  24. package/runtime/marketplace/plugin/.mcp.json +1 -0
  25. package/runtime/marketplace/plugin/bin/guard.mjs +55 -0
  26. package/runtime/marketplace/plugin/bin/metro-plugin.mjs +122 -0
  27. package/runtime/marketplace/plugin/bin/session-start.mjs +31 -0
  28. package/runtime/marketplace/plugin/hooks/hooks.json +25 -0
  29. package/runtime/marketplace/plugin/orchestrator.md +16 -0
  30. package/runtime/marketplace/plugin/skills/refresh/SKILL.md +15 -0
  31. package/runtime/node_modules/@metro-labs/core/package.json +43 -0
  32. package/runtime/node_modules/@metro-labs/core/src/address.ts +6 -0
  33. package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
  34. package/runtime/node_modules/@metro-labs/core/src/events.ts +120 -0
  35. package/runtime/node_modules/@metro-labs/core/src/identity.ts +7 -0
  36. package/runtime/node_modules/@metro-labs/core/src/ids.ts +21 -0
  37. package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
  38. package/runtime/node_modules/@metro-labs/core/src/lines.ts +87 -0
  39. package/runtime/node_modules/@metro-labs/core/src/log.ts +42 -0
  40. package/runtime/node_modules/@metro-labs/core/src/protocol.ts +226 -0
  41. package/runtime/node_modules/@metro-labs/core/src/secure-fs.ts +57 -0
  42. package/runtime/node_modules/@metro-labs/core/src/station-names.ts +13 -0
  43. package/runtime/node_modules/@metro-labs/core/src/stations/account-store.ts +60 -0
  44. package/runtime/node_modules/@metro-labs/core/src/stations/attachments.ts +196 -0
  45. package/runtime/node_modules/@metro-labs/core/src/stations/messaging-normalize.ts +88 -0
  46. package/runtime/node_modules/@metro-labs/core/src/stations/station-runtime.ts +64 -0
  47. package/runtime/node_modules/@metro-labs/core/src/stations/types.ts +108 -0
  48. package/runtime/node_modules/@metro-labs/core/src/str.ts +5 -0
  49. package/runtime/node_modules/@metro-labs/core/src/train-error.ts +53 -0
  50. package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
  51. package/runtime/node_modules/@metro-labs/daemon/package.json +48 -0
  52. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-attach.ts +19 -0
  53. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-routes.ts +70 -0
  54. package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +365 -0
  55. package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +43 -0
  56. package/runtime/node_modules/@metro-labs/daemon/src/agents/allowlist.ts +37 -0
  57. package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +300 -0
  58. package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +122 -0
  59. package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +371 -0
  60. package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +155 -0
  61. package/runtime/node_modules/@metro-labs/daemon/src/agents/keys.ts +45 -0
  62. package/runtime/node_modules/@metro-labs/daemon/src/agents/map.ts +95 -0
  63. package/runtime/node_modules/@metro-labs/daemon/src/agents/scope.ts +64 -0
  64. package/runtime/node_modules/@metro-labs/daemon/src/agents/seed.ts +33 -0
  65. package/runtime/node_modules/@metro-labs/daemon/src/agents/senders.ts +38 -0
  66. package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +209 -0
  67. package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +39 -0
  68. package/runtime/node_modules/@metro-labs/daemon/src/boot/crash-guard.ts +49 -0
  69. package/runtime/node_modules/@metro-labs/daemon/src/boot/local-owner.ts +14 -0
  70. package/runtime/node_modules/@metro-labs/daemon/src/boot/paths.ts +106 -0
  71. package/runtime/node_modules/@metro-labs/daemon/src/channels/addressed.ts +25 -0
  72. package/runtime/node_modules/@metro-labs/daemon/src/channels/dedupe.ts +24 -0
  73. package/runtime/node_modules/@metro-labs/daemon/src/channels/inbound.ts +377 -0
  74. package/runtime/node_modules/@metro-labs/daemon/src/channels/media-note.ts +85 -0
  75. package/runtime/node_modules/@metro-labs/daemon/src/channels/pending.ts +75 -0
  76. package/runtime/node_modules/@metro-labs/daemon/src/channels/relay.ts +129 -0
  77. package/runtime/node_modules/@metro-labs/daemon/src/channels/webhook-note.ts +51 -0
  78. package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +309 -0
  79. package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +358 -0
  80. package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +169 -0
  81. package/runtime/node_modules/@metro-labs/daemon/src/claude/onboarding.ts +56 -0
  82. package/runtime/node_modules/@metro-labs/daemon/src/claude/plugin-install.ts +140 -0
  83. package/runtime/node_modules/@metro-labs/daemon/src/claude/session-files.ts +90 -0
  84. package/runtime/node_modules/@metro-labs/daemon/src/claude/session.ts +253 -0
  85. package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +117 -0
  86. package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +239 -0
  87. package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +154 -0
  88. package/runtime/node_modules/@metro-labs/daemon/src/claude/version.ts +109 -0
  89. package/runtime/node_modules/@metro-labs/daemon/src/connectors/api.ts +310 -0
  90. package/runtime/node_modules/@metro-labs/daemon/src/connectors/cli-api.ts +63 -0
  91. package/runtime/node_modules/@metro-labs/daemon/src/connectors/config.ts +175 -0
  92. package/runtime/node_modules/@metro-labs/daemon/src/connectors/json.ts +21 -0
  93. package/runtime/node_modules/@metro-labs/daemon/src/connectors/model.ts +77 -0
  94. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-client.ts +166 -0
  95. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-discovery.ts +139 -0
  96. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-pending.ts +65 -0
  97. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-routes.ts +171 -0
  98. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth.ts +155 -0
  99. package/runtime/node_modules/@metro-labs/daemon/src/connectors/plugin-sync.ts +122 -0
  100. package/runtime/node_modules/@metro-labs/daemon/src/connectors/reach.ts +27 -0
  101. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-target.ts +39 -0
  102. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +296 -0
  103. package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +286 -0
  104. package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +98 -0
  105. package/runtime/node_modules/@metro-labs/daemon/src/connectors/url.ts +70 -0
  106. package/runtime/node_modules/@metro-labs/daemon/src/connectors/verify.ts +332 -0
  107. package/runtime/node_modules/@metro-labs/daemon/src/connectors/watch.ts +54 -0
  108. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-grant.ts +99 -0
  109. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-owner.ts +32 -0
  110. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-serve.ts +121 -0
  111. package/runtime/node_modules/@metro-labs/daemon/src/files/upload-api.ts +294 -0
  112. package/runtime/node_modules/@metro-labs/daemon/src/files/upload-store.ts +181 -0
  113. package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +259 -0
  114. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +231 -0
  115. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-device.ts +91 -0
  116. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +288 -0
  117. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +203 -0
  118. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +231 -0
  119. package/runtime/node_modules/@metro-labs/daemon/src/gateway/eventstream.ts +123 -0
  120. package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +187 -0
  121. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +229 -0
  122. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +269 -0
  123. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +207 -0
  124. package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +90 -0
  125. package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +65 -0
  126. package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +17 -0
  127. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +229 -0
  128. package/runtime/node_modules/@metro-labs/daemon/src/mcp/accounts.ts +151 -0
  129. package/runtime/node_modules/@metro-labs/daemon/src/mcp/call-tools.ts +216 -0
  130. package/runtime/node_modules/@metro-labs/daemon/src/mcp/channel-owner.ts +29 -0
  131. package/runtime/node_modules/@metro-labs/daemon/src/mcp/ctx.ts +62 -0
  132. package/runtime/node_modules/@metro-labs/daemon/src/mcp/event-store.ts +91 -0
  133. package/runtime/node_modules/@metro-labs/daemon/src/mcp/frame-scope.ts +21 -0
  134. package/runtime/node_modules/@metro-labs/daemon/src/mcp/group-tools.ts +129 -0
  135. package/runtime/node_modules/@metro-labs/daemon/src/mcp/index.ts +191 -0
  136. package/runtime/node_modules/@metro-labs/daemon/src/mcp/member-tools.ts +72 -0
  137. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +66 -0
  138. package/runtime/node_modules/@metro-labs/daemon/src/mcp/raw-get-stream.ts +207 -0
  139. package/runtime/node_modules/@metro-labs/daemon/src/mcp/request-identity.ts +47 -0
  140. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-registry.ts +172 -0
  141. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-route.ts +43 -0
  142. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session.ts +215 -0
  143. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-dispatch.ts +215 -0
  144. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-schemas.ts +400 -0
  145. package/runtime/node_modules/@metro-labs/daemon/src/mcp/upload-tool.ts +66 -0
  146. package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +237 -0
  147. package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +389 -0
  148. package/runtime/node_modules/@metro-labs/daemon/src/routes/body.ts +24 -0
  149. package/runtime/node_modules/@metro-labs/daemon/src/routes/http.ts +372 -0
  150. package/runtime/node_modules/@metro-labs/daemon/src/routes/identity.ts +54 -0
  151. package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +223 -0
  152. package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +60 -0
  153. package/runtime/node_modules/@metro-labs/daemon/src/routes/session.ts +29 -0
  154. package/runtime/node_modules/@metro-labs/daemon/src/routes/threema-callback.ts +103 -0
  155. package/runtime/node_modules/@metro-labs/daemon/src/server/control.ts +64 -0
  156. package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +61 -0
  157. package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +116 -0
  158. package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
  159. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-inline.ts +100 -0
  160. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-interactive.ts +161 -0
  161. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-resolve.ts +202 -0
  162. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-session.ts +280 -0
  163. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-xmtp.ts +111 -0
  164. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach.ts +248 -0
  165. package/runtime/node_modules/@metro-labs/daemon/src/stations/materialize.ts +261 -0
  166. package/runtime/node_modules/@metro-labs/daemon/src/stations/registry.ts +37 -0
  167. package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +82 -0
  168. package/runtime/node_modules/@metro-labs/daemon/src/stations/supervisor-io.ts +97 -0
  169. package/runtime/node_modules/@metro-labs/daemon/src/stations/supervisor.ts +320 -0
  170. package/runtime/node_modules/@metro-labs/daemon/src/stations/threema-callbacks.ts +32 -0
  171. package/runtime/node_modules/@metro-labs/daemon/src/stations/train-call.ts +22 -0
  172. package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +96 -0
  173. package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +123 -0
  174. package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +40 -0
  175. package/runtime/node_modules/@metro-labs/discord-bot/package.json +28 -0
  176. package/runtime/node_modules/@metro-labs/discord-bot/src/accounts.ts +118 -0
  177. package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +388 -0
  178. package/runtime/node_modules/@metro-labs/discord-bot/src/api-base.ts +1 -0
  179. package/runtime/node_modules/@metro-labs/discord-bot/src/attachments.ts +29 -0
  180. package/runtime/node_modules/@metro-labs/discord-bot/src/format.ts +220 -0
  181. package/runtime/node_modules/@metro-labs/discord-bot/src/group-actions.ts +50 -0
  182. package/runtime/node_modules/@metro-labs/discord-bot/src/group.ts +115 -0
  183. package/runtime/node_modules/@metro-labs/discord-bot/src/index.ts +127 -0
  184. package/runtime/node_modules/@metro-labs/discord-bot/src/members.ts +215 -0
  185. package/runtime/node_modules/@metro-labs/discord-bot/src/send-files.ts +43 -0
  186. package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +19 -0
  187. package/runtime/node_modules/@metro-labs/discord-bot/src/verify.ts +82 -0
  188. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-speak.ts +195 -0
  189. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-transcribe.ts +292 -0
  190. package/runtime/node_modules/@metro-labs/discord-bot/src/voice.ts +197 -0
  191. package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +5 -0
  192. package/runtime/node_modules/@metro-labs/http/package.json +33 -0
  193. package/runtime/node_modules/@metro-labs/http/src/api-error.ts +8 -0
  194. package/runtime/node_modules/@metro-labs/http/src/api-http.ts +95 -0
  195. package/runtime/node_modules/@metro-labs/http/src/cors.ts +29 -0
  196. package/runtime/node_modules/@metro-labs/http/src/identity-key.ts +33 -0
  197. package/runtime/node_modules/@metro-labs/http/src/identity-registry.ts +13 -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/signed-identity.ts +36 -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 +219 -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 +39 -0
  295. package/runtime/trains/.keep +0 -0
  296. package/LICENSE +0 -21
  297. package/README.md +0 -252
  298. package/dist/broker.js +0 -202
  299. package/dist/cache.js +0 -69
  300. package/dist/cli/actions.js +0 -206
  301. package/dist/cli/config.js +0 -185
  302. package/dist/cli/index.js +0 -188
  303. package/dist/cli/skill.js +0 -62
  304. package/dist/cli/tail.js +0 -164
  305. package/dist/cli/util.js +0 -72
  306. package/dist/cli/webhook.js +0 -81
  307. package/dist/codex-rc.js +0 -245
  308. package/dist/dispatcher.js +0 -128
  309. package/dist/history.js +0 -121
  310. package/dist/ipc.js +0 -72
  311. package/dist/log.js +0 -15
  312. package/dist/monitor.js +0 -194
  313. package/dist/paths.js +0 -68
  314. package/dist/registry.js +0 -48
  315. package/dist/stations/claude.js +0 -45
  316. package/dist/stations/codex.js +0 -68
  317. package/dist/stations/discord.js +0 -216
  318. package/dist/stations/index.js +0 -129
  319. package/dist/stations/telegram-md.js +0 -34
  320. package/dist/stations/telegram-upload.js +0 -113
  321. package/dist/stations/telegram.js +0 -234
  322. package/dist/stations/webhook.js +0 -103
  323. package/dist/tunnel.js +0 -64
  324. package/dist/webhooks.js +0 -41
  325. package/docs/broker.md +0 -214
  326. package/docs/monitor.md +0 -163
  327. package/docs/uri-scheme.md +0 -124
  328. package/docs/users.md +0 -226
  329. package/skills/metro/SKILL.md +0 -256
package/docs/users.md DELETED
@@ -1,226 +0,0 @@
1
- # Metro: a guide for Claude Code / Codex users
2
-
3
- You are running inside a session that has **launched `metro`** in the background. Metro emits a live stream of JSON events from Discord, Telegram, third-party webhooks (GitHub, Intercom, …), and other users on its stdout. Your job is to consume that stream and post replies back via subcommands.
4
-
5
- ## Starting metro
6
-
7
- The launch mechanics differ by runtime — pick the one that matches yours.
8
-
9
- ### Claude Code
10
-
11
- ```
12
- Bash(command: "metro", run_in_background: true)
13
- ```
14
-
15
- Then attach `Monitor` to its stdout. Each line is one JSON event you act on.
16
-
17
- ### Codex
18
-
19
- ```
20
- shell(command: "METRO_CODEX_RC=ws://127.0.0.1:8421 metro", run_in_background: true)
21
- ```
22
-
23
- Don't watch its stdout — Codex has no Monitor equivalent. Metro pushes each event into your thread via JSON-RPC `turn/start`, so events arrive as user input on your next turn. The user must have a daemon and TUI running for this to work:
24
-
25
- ```
26
- codex app-server --listen ws://127.0.0.1:8421 # daemon (terminal 1)
27
- codex --remote ws://127.0.0.1:8421 # TUI (this session — terminal 2)
28
- ```
29
-
30
- Run `metro doctor` if anything seems off.
31
-
32
- ## Event shape
33
-
34
- Every event is a **history entry** — the same record that's appended to `history.jsonl`. Fields: `kind` (`inbound`/`outbound`/`edit`/`react`), `id` (`msg_…`), `ts`, `station`, `line` (conversation), `lineName?`, `from` (participant URI), `fromName?`, `to`, `text`, `messageId?` (platform-side id; inbound/outbound only), `payload?` (raw platform message; inbound only).
35
-
36
- ```json
37
- {"kind":"inbound","id":"msg_aB3xY7zP","ts":"2026-05-14T12:00:00Z","station":"telegram","line":"metro://telegram/-100…/247","lineName":"infra","from":"metro://telegram/user/12345","fromName":"@alice","to":"metro://claude/user/9bfc7af0-…","messageId":"4567","text":"hello [image]","payload":{"message_id":4567,"chat":{"id":-100,"type":"supergroup","is_forum":true},"from":{"id":12345,"username":"alice"},"text":"hello","entities":[{"type":"mention","offset":0,"length":6}],"photo":[{"file_id":"…"}],"reply_to_message":{"message_id":4500,"text":"earlier","from":{"id":99,"username":"bob"}}}}
38
- ```
39
-
40
- ```json
41
- {"kind":"inbound","id":"msg_pQ4r5sT0","ts":"…","station":"claude","line":"metro://claude/9bfc7af0-…/50b00d11-…","from":"metro://codex/user/8119ecb1-…","to":"metro://claude/9bfc7af0-…/50b00d11-…","text":"deploy succeeded"}
42
- ```
43
-
44
- ### `payload` by station
45
-
46
- `payload` is the platform's native message shape. Narrow on `event.station`:
47
-
48
- - **`discord`** — discord.js `Message.toJSON()`: camelCase fields (`channelId`, `guildId`, `content`, `author`, `mentions: { users[], roles[], everyone }`, `attachments[]`, `reference`, …). Collections come back as **arrays of IDs**. `referencedMessage` (also `toJSON()`-shaped) is added inline on replies (auto-fetched).
49
- - **`telegram`** — raw Bot API `Message` (snake_case): `{ message_id, chat, from, text, caption, entities[], photo[], document, voice, audio, reply_to_message, … }`. `reply_to_message` is inline on replies.
50
- - **`webhook`** — `{ headers: Record<string,string>, body: <parsed JSON | raw string> }`. Narrow further on the provider — GitHub sets `headers['x-github-event']` (`push`, `pull_request`, `issues`, …) and includes a `repository`/`sender` in body; Intercom sets `x-intercom-topic` etc. `text` is a short summary; full event is always in `payload.body`.
51
-
52
- Use `payload` for anything the envelope doesn't surface — mentions, reply chains, embeds, stickers, entities.
53
-
54
- Both `from` and `to` are **participant URIs** (the conversation lives in `line`): `metro://<station>/user/<id>` for a person, `metro://claude/user/<orgId>` for a Claude Code user (orgId = stable Anthropic-account UUID), `metro://codex/user/<accountId>` for a Codex user (accountId = stable ChatGPT-account UUID), `metro://<station>/<channelId>` as a fallback `to` when sending to a group with no single recipient.
55
-
56
- When **you** call `metro send`/`reply`/`edit`/`react`, metro auto-stamps `from` to your runtime — `metro://claude/user/<orgId>` (when `$CLAUDECODE` is set; orgId comes from `claude auth status --json`) or `metro://codex/user/<accountId>` (when `$METRO_CODEX_RC`/`$CODEX_HOME` is set; accountId comes from `$CODEX_HOME/auth.json`, `tokens.account_id`). Both identities are account-scoped, not install-scoped: switch accounts with `claude auth login` / `codex login` and the next event uses the new id (within ~5 s for the daemon, immediately for one-shot CLI calls). Override with `--from=<uri>` or `$METRO_FROM`. When replying/reacting, `to` is auto-set to the original sender (history lookup).
57
-
58
- - `kind: "inbound"` — a message arrived. Source can be:
59
- - a human on a chat platform (Discord/Telegram),
60
- - a third-party service POSTing to a registered webhook endpoint (`station: "webhook"`, `payload: { headers, body }`),
61
- - another Claude / Codex user posting cross-process via `metro send` against your line.
62
-
63
- `text` may include `[image]` / `[voice]` / `[audio]` / `[file: <name>]` placeholders alongside the real text — non-image attachments are opaque markers, images can be materialized via `metro download`.
64
-
65
- ## Required flow on every event
66
-
67
- 1. **Echo `event.display` verbatim as your first chat output.** Every event ships a pre-rendered chat-bubble in `event.display` — bold header (icon + station + sender) and a markdown blockquote body. Paste it as-is before any commentary or tool calls. Monitor's notification chip is a CLI-only UI and won't surface visibly in VSCode/Cursor, so your own echo is the only cross-surface signal:
68
-
69
- ```
70
- **📩 telegram · @bonustrack**
71
- > Hey
72
- ```
73
-
74
- The format is centralized in metro's dispatcher (`formatDisplay()` in `src/history.ts`) — don't compose your own.
75
-
76
- 2. **Decide and act** using the subcommands below.
77
-
78
- ## Detecting "is this for me?"
79
-
80
- Derive from `payload`. Bot id per station is in `$METRO_STATE_DIR/bot-ids.json` (`{discord:"<userId>", telegram:"<userId>"}`).
81
-
82
- - **`discord`** — DM if `payload.guildId == null`; otherwise pinged if `payload.mentions.users.includes(<bot-id>)`.
83
- - **`telegram`** — DM if `payload.chat.type === 'private'`; otherwise pinged if any entity in `payload.entities` (or `caption_entities`) is `{type:"mention"}` matching `@<bot-username>`, or `{type:"text_mention", user:{id:<bot-id>}}`.
84
- - **`webhook`** — every POST is for you (you registered the endpoint). Route on `payload.headers['x-github-event']` / `x-intercom-topic` etc. to know which provider event it is.
85
-
86
- Default for chat: only reply on DM or ping; otherwise stay silent or `metro react` to ack. Webhooks just consume — no ack mechanism.
87
-
88
- ## Subcommands
89
-
90
- | Action | Command |
91
- |---|---|
92
- | Quote-reply (threads under original) | `metro reply <line> <messageId> <text>` |
93
- | Send a fresh message (no reply context) | `metro send <line> <text>` |
94
- | Edit a message you previously sent | `metro edit <line> <messageId> <text>` |
95
- | Reaction (empty emoji clears it) | `metro react <line> <messageId> <emoji>` |
96
- | Download `[image]` attachments | `metro download <line> <messageId> [--out=<dir>]` |
97
- | Recent-message lookback (Discord only) | `metro fetch <line> [--limit=20]` |
98
- | Cross-user ping | `metro send <user-line> <text> [--from=<line>]` |
99
- | Register webhook endpoint | `metro webhook add <label> [--secret=<hmac-secret>]` |
100
- | List / remove webhook endpoints | `metro webhook list` · `metro webhook remove <id>` |
101
- | Configure Cloudflare named tunnel | `metro tunnel setup <tunnel-name> <hostname>` |
102
-
103
- `reply` / `send` / `edit` accept multi-line text via stdin (heredoc). Webhooks are receive-only — there's no `reply` for them, just consume the event.
104
-
105
- ### Rich content flags
106
-
107
- `send` and `reply` accept these flags; `edit` accepts `--buttons` only.
108
-
109
- - `--image=<path>` — local image. **Repeatable** for albums: `--image=a.png --image=b.png` (or comma-separated). Up to 10 / message. Text becomes the caption (on the first image for albums).
110
- - `--document=<path>` — local file (PDF, log, csv, …). Same repeat/comma syntax.
111
- - `--voice=<path>` — single voice message (`.ogg` Opus or `.mp3`). On Telegram renders as a voice bubble; on Discord uploaded as audio attachment.
112
- - `--buttons='[[{"text":"…","url":"…"}]]'` — inline URL-button keyboard (2D rows × buttons). Pass `'[]'` to `edit` to clear.
113
-
114
- ```bash
115
- metro send <line> "screenshot" --image=/tmp/build.png
116
- metro send <line> "before/after" --image=/tmp/before.png --image=/tmp/after.png
117
- metro reply <line> <id> "voice note" --voice=/tmp/note.ogg
118
- metro send <line> "approve?" --buttons='[[{"text":"Open PR","url":"https://github.com/x/y/pull/1"}]]'
119
- ```
120
-
121
- Limits: 20 MB / file. Telegram albums are single-type (photos OR documents per album); mixing kinds still works — metro splits into two messages. Buttons are dropped on multi-attachment Telegram sends. URL buttons only for now.
122
-
123
- Append `--json` to any command for a single JSON line you can parse.
124
-
125
- ## When to use `reply` vs `send`
126
-
127
- - **`reply`** — responding to a specific inbound message. Threads under it. Default when handling an `inbound` event.
128
- - **`send`** — initiating without a triggering message: a long task you kicked off finished, a follow-up the user asked you to deliver later, or posting to a Claude / Codex line (`metro://claude/...`, `metro://codex/...`) to notify a peer.
129
-
130
- ## Universal message IDs
131
-
132
- The `id` field on every event and `metro history` row is metro's **universal ID** (`msg_<8 chars>`). It works anywhere a `<message_id>` is expected — `metro reply`, `edit`, `react`, `download` — and resolves to the platform's own id via the history file. Use it for chaining commands or referring back across stations.
133
-
134
- ## `metro history` — read the universal message log
135
-
136
- Every inbound, outbound, edit, and react is appended to `$METRO_STATE_DIR/history.jsonl` automatically.
137
-
138
- ```bash
139
- metro history --limit=20 # recent 20, newest first
140
- metro history --line=metro://discord/123 # only this conversation
141
- metro history --kind=inbound --since=2026-05-14 # inbounds since that day
142
- metro history --station=telegram --text=deploy # all Telegram entries containing "deploy"
143
- metro history --from='@alice' --json # everything from alice, JSON
144
- ```
145
-
146
- Filters: `--limit` (default 50), `--line`, `--station`, `--kind` (`inbound`/`outbound`/`edit`/`react`), `--from`, `--text`, `--since` (ISO), `--json`.
147
-
148
- ## Discovery
149
-
150
- ### `metro lines`
151
-
152
- ```
153
- $ metro lines
154
- 2m ago metro://discord/1234567890 infra
155
- 5m ago metro://telegram/-100123/42 design-review
156
- ```
157
-
158
- Lines sorted by recency. Use when the user says "the Telegram channel" or "that PR thread."
159
-
160
- ### `metro stations`
161
-
162
- ```
163
- $ metro stations
164
- ✓ discord in: text+image · out: text · features: reply, send, edit, react, download, fetch
165
- DISCORD_BOT_TOKEN
166
- ✓ telegram in: text+image · out: text · features: reply, send, edit, react, download, fetch
167
- TELEGRAM_BOT_TOKEN
168
- ✓ claude in: text · out: text · features: send
169
- account: 9bfc7af0-… · seen 1 user, 2 sessions
170
- seen: 9bfc7af0-… · sessions: 2
171
- ✗ codex in: text · out: text · features: send
172
- set METRO_CODEX_RC=ws://… to push
173
- ✓ webhook in: text · out: – · features: –
174
- 2 endpoints · base https://webhook.example.com
175
- ```
176
-
177
- `✓` = ready (env/runtime detected), `✗` = configured-but-broken or runtime not detected, `·` = informational. The detail line under each Claude / Codex row shows the resolved account id plus the per-user count of sessions metro has observed — pull addressable Claude / Codex lines from those.
178
-
179
- ## Webhooks (receiving HTTP events)
180
-
181
- When the user wants metro to receive events from a third-party service (GitHub PRs, Intercom conversations, Fireflies meetings, …):
182
-
183
- 1. **One-time tunnel setup** (only needed once per machine): `metro tunnel setup <tunnel-name> <hostname>`. Requires `cloudflared` on PATH (`brew install cloudflared`) and a Cloudflare account + domain on Cloudflare DNS. Run `cloudflared tunnel login` first if you haven't.
184
- 2. **Register an endpoint**: `metro webhook add <label> [--secret=<shared-secret>]`. Prints the public URL — paste it into the provider's webhook settings. For GitHub specifically, set **Content type: `application/json`** (form-encoded won't parse into `payload.body`).
185
- 3. **Run the daemon**: `metro`. With at least one endpoint registered, metro auto-binds the HTTP listener (port 8420, override `METRO_WEBHOOK_PORT`) and spawns `cloudflared tunnel run` if `tunnel.json` exists.
186
-
187
- Each POST becomes an inbound event:
188
-
189
- ```json
190
- {"kind":"inbound","station":"webhook","line":"metro://webhook/<id>","lineName":"github",
191
- "from":"metro://webhook/<id>","to":"metro://claude/user/<orgId>",
192
- "messageId":"<x-github-delivery>","text":"push POST /wh/<id>",
193
- "payload":{"headers":{"x-github-event":"push",…},"body":{"ref":"refs/heads/main",…}}}
194
- ```
195
-
196
- `text` is a short summary; the real event lives in `payload.body`. Use `payload.headers['x-github-event']` (or `x-intercom-topic` etc.) to narrow on provider event type. If you set `--secret`, metro verifies `X-Hub-Signature-256` and rejects bad signatures with 401 — you see only authenticated events.
197
-
198
- ## Image attachments
199
-
200
- When an inbound has an `[image]` tag in `text`:
201
-
202
- 1. `metro download <line> <messageId>` → prints absolute paths.
203
- 2. `Read` each path with your `Read` tool — the image enters your context as a vision input.
204
- 3. Reply normally via `metro reply`.
205
-
206
- ## Cross-user notification
207
-
208
- Both Claude Code and Codex can post to each other's **line** — `metro://claude/<user-id>/<session-id>` or `metro://codex/<user-id>/<session-id>`. `<user-id>` is the peer's stable account id (cross-device); `<session-id>` is one conversation. Discover both by running `metro stations` (which lists every user + session metro has seen), or by reading `$METRO_STATE_DIR/user-registry.json` directly. The daemon re-emits the post on its stdout stream (and pushes via codex-rc if configured), so the peer sees it as an inbound event:
209
-
210
- ```bash
211
- metro send metro://claude/9bfc7af0-…/50b00d11-… "build green, ready to ship"
212
- metro send metro://claude/9bfc7af0-…/50b00d11-… "build green" --from=metro://codex/user/8119ecb1-… # override sender
213
- ```
214
-
215
- This requires the metro daemon to be running on the machine. Without a daemon, Claude / Codex line sends error with a clear message.
216
-
217
- ## Don'ts
218
-
219
- - ❌ Spawning a second metro daemon — there's one per machine (lockfile-enforced).
220
- - ❌ `metro send` to a line that isn't in `metro lines` unless the user gave it to you explicitly.
221
- - ❌ Narrating the tool ("I'll now use metro reply to…"). The tool call is already visible.
222
-
223
- ## Further reading
224
-
225
- - URI scheme: [`uri-scheme.md`](uri-scheme.md)
226
- - Source: https://github.com/bonustrack/metro
@@ -1,256 +0,0 @@
1
- ---
2
- name: metro
3
- description: Run the metro Telegram/Discord/webhook relay in this session — launch `metro` in the background, watch its stdout for inbound JSON events, and act on each. Use when the user asks to start/run/launch metro, when you see JSON lines on stdout shaped `{"kind":"inbound","station":...,"line":"metro://...","messageId":...,"text":...}`, or when handling a chat/webhook reply/edit/react/send/download/fetch.
4
- ---
5
-
6
- # Metro — running the Telegram / Discord / webhook relay
7
-
8
- Metro is a CLI that relays between this session and external sources: Telegram, Discord, and HTTP webhooks from third parties (GitHub, Intercom, Fireflies, …). You launch `metro` once when the user asks, then act on each inbound JSON line via `metro <subcommand>`.
9
-
10
- ## Starting metro
11
-
12
- When the user asks to run/start/launch metro:
13
-
14
- ### Claude Code
15
-
16
- ```
17
- Bash(command: "metro", run_in_background: true)
18
- ```
19
-
20
- Then attach `Monitor` to its stdout. Each line is one JSON event. Stderr is pino logs — don't act on it.
21
-
22
- ### Codex
23
-
24
- ```
25
- shell(command: "METRO_CODEX_RC=ws://127.0.0.1:8421 metro", run_in_background: true)
26
- ```
27
-
28
- Codex has no Monitor equivalent. Instead, metro pushes each event into your thread via JSON-RPC `turn/start`, so events arrive as user input on your next turn. The user must have a daemon + TUI running on the **same WebSocket URL**:
29
-
30
- ```
31
- codex app-server --listen ws://127.0.0.1:8421 # daemon (terminal 1)
32
- codex --remote ws://127.0.0.1:8421 # TUI (terminal 2) — type "hi" once to create a live thread
33
- ```
34
-
35
- Then metro starts third. If metro exits immediately or you see `thread not found` retries on its stderr, the TUI didn't create a thread yet — tell the user to type something in the TUI.
36
-
37
- ### Diagnostics
38
-
39
- If something seems off, run `metro doctor`. Common causes: missing tokens (`metro setup telegram <token>` / `metro setup discord <token>`), Discord Message Content Intent not toggled, stale lockfile, or (Codex) no live thread on the daemon.
40
-
41
- ## Event shape
42
-
43
- Every line on stdout is one **history entry** — the same record appended to `history.jsonl`. Fields:
44
- - `kind` — `"inbound"`, `"outbound"`, `"edit"`, or `"react"`. Inbound `react` events fire when a human adds an emoji reaction in Discord/Telegram — `emoji` is set, `text` is omitted, `messageId` is the message that got reacted to.
45
- - `id` (`msg_…`) — universal message ID minted by metro
46
- - `ts` — ISO timestamp
47
- - `station` — `"discord"`, `"telegram"`, `"claude"`, `"codex"`, `"webhook"`
48
- - `line` — conversation URI; `lineName?` is the channel/topic display name (for webhooks: the label you gave it)
49
- - `from` / `fromName?` — sender participant URI + optional display name
50
- - `to` — recipient participant URI (local user for DMs, conversation `line` for groups, original sender for replies/reacts)
51
- - `text` — universal display projection. Includes `[image]`/`[file: …]`/`[voice]`/`[audio]` tags inline.
52
- - `messageId?` — platform-side id (Discord snowflake, Telegram int). Set on inbound/outbound.
53
- - `payload?` — raw platform-native message object. Set on inbound only. Shape varies per `station`.
54
-
55
- ```json
56
- {"kind":"inbound","id":"msg_aB3xY7zP","ts":"2026-05-14T12:00:00Z","station":"telegram","line":"metro://telegram/-100…/247","lineName":"infra","from":"metro://telegram/user/12345","fromName":"@alice","to":"metro://claude/user/9bfc7af0-…","messageId":"4567","text":"hi [image]","payload":{"message_id":4567,"chat":{"id":-100,"type":"supergroup","is_forum":true},"from":{"id":12345,"username":"alice"},"text":"hi","photo":[{"file_id":"…"}],"reply_to_message":{"message_id":4500,"text":"earlier","from":{"id":99,"username":"bob"}}}}
57
- ```
58
-
59
- ```json
60
- {"kind":"inbound","id":"msg_pQ4r5sT0","ts":"…","station":"claude","line":"metro://claude/9bfc7af0-…/50b00d11-…","from":"metro://codex/user/8119ecb1-…","to":"metro://claude/9bfc7af0-…/50b00d11-…","text":"deploy green"}
61
- ```
62
-
63
- ### `payload` by station
64
-
65
- `payload` is the platform's native message shape. Narrow on `event.station`:
66
-
67
- - **`discord`** — discord.js `Message.toJSON()`: camelCase fields (`channelId`, `guildId`, `content`, `author`, `mentions: { users[], roles[], everyone }`, `attachments[]`, `reference`, …). Collections come back as **arrays of IDs**. `referencedMessage` is added inline on replies (auto-fetched).
68
- - **`telegram`** — raw Bot API `Message` (snake_case): `{ message_id, chat, from, text, caption, entities[], photo[], document, voice, audio, reply_to_message, … }`. `reply_to_message` is inline on replies.
69
- - **`webhook`** — `{ headers, body }`. The provider lives in `headers['x-github-event']`, `headers['x-intercom-topic']`, etc. Full event payload is `body` (parsed JSON when possible). `text` is a short summary; always narrow on `body` for real routing.
70
-
71
- Use `payload` for anything the envelope doesn't surface — mentions, reply chains, embeds, entities.
72
-
73
- ## Detecting "is this for me?"
74
-
75
- Derive from `payload`. Bot id per station is cached in `$METRO_STATE_DIR/bot-ids.json` (`{discord:"<userId>", telegram:"<userId>"}`, written by the daemon on start).
76
-
77
- - **discord** — DM when `payload.guildId == null`; otherwise pinged when `payload.mentions.users.includes(<bot-id>)`.
78
- - **telegram** — DM when `payload.chat.type === 'private'`; otherwise pinged when any entity in `payload.entities` (or `caption_entities`) is `{type:"mention"}` matching `@<bot-username>` or `{type:"text_mention", user:{id:<bot-id>}}`.
79
- - **webhook** — every POST is "for you" by design (it's an endpoint you registered). Route on `payload.headers['x-github-event']` / `x-intercom-topic` etc. to decide which provider event you're handling.
80
-
81
- Default for chat: only reply on DM or ping; otherwise stay silent or `metro react` to ack. Webhooks have no "ack" mechanism — just consume the event.
82
-
83
- Both `from` and `to` are **participant URIs** (the conversation context lives in `line`):
84
- - `metro://<station>/user/<id>` — a person on a chat platform
85
- - `metro://claude/user/<orgId>` — a Claude Code user (orgId = stable Anthropic-account UUID, same across devices for the same account)
86
- - `metro://codex/user/<accountId>` — a Codex user (accountId = stable ChatGPT-account UUID, same across devices)
87
- - `metro://webhook/<endpoint-id>` — a webhook endpoint (line + `from` are the same — no HTTP-side user identity)
88
- - `metro://<station>/<channelId>` — a channel (used as `to` for fresh sends to a group, where no single recipient)
89
-
90
- When **you** send via `metro send`/`reply`/`edit`/`react`, metro auto-stamps `from = metro://claude/user/<orgId>` (when `$CLAUDECODE` is set; resolved from `claude auth status --json`) or `metro://codex/user/<accountId>` (from `$METRO_CODEX_RC` / `$CODEX_HOME`; resolved from `$CODEX_HOME/auth.json`). Switching accounts via `claude auth login` / `codex login` flips the id on the next event (within ~5 s for the daemon). Override with `--from=<uri>` or `$METRO_FROM`. When replying/reacting, `to` is automatically the original sender (looked up via the universal id).
91
-
92
- The `id` is the **canonical handle** for that message across all stations — store it if you want to refer back to it later.
93
-
94
- - `kind: "inbound"` — a message arrived. Source can be a human on Discord/Telegram, a webhook POST, or another Claude / Codex user posting to your line via `metro send` (cross-process).
95
-
96
- `text` may contain `[image]`, `[voice]`, `[audio]`, or `[file: <name>]` placeholders alongside the real text — non-image attachments are opaque markers; images can be materialized via `metro download`.
97
-
98
- ## Required flow on every event
99
-
100
- 1. **Echo `event.display` verbatim as your first chat output.** Every event ships a pre-rendered chat-bubble in `event.display` — bold header (icon + station + sender) and a markdown blockquote body. Render this string as-is, before any commentary or tool calls. Monitor's notification chip is a CLI-only UI and won't surface visibly in VSCode/Cursor, so this echo is the only cross-surface signal the user has. Example:
101
-
102
- ```
103
- **📩 telegram · @bonustrack**
104
- > Hey
105
- ```
106
-
107
- Don't compose your own bubble — the format is centralized in metro's dispatcher; just paste the string.
108
-
109
- 2. **Decide and act** using the subcommands below.
110
-
111
- No server-side auto-reaction — don't expect 👀 to be on the user's message; add one yourself with `metro react` if you want to ack quickly.
112
-
113
- ## Subcommands
114
-
115
- All take positional args (no `--to=`/`--text=` flags). Append `--json` to any for a parseable single-line result.
116
-
117
- | Action | Command |
118
- |---|---|
119
- | Quote-reply (threads under original) | `metro reply <line> <messageId> <text>` |
120
- | Send a fresh message (no reply context) | `metro send <line> <text>` |
121
- | Edit a message you previously sent | `metro edit <line> <messageId> <text>` |
122
- | Reaction (empty emoji clears) | `metro react <line> <messageId> <emoji>` |
123
- | Download `[image]` attachments → paths | `metro download <line> <messageId> [--out=<dir>]` |
124
- | Recent channel history (Discord only) | `metro fetch <line> [--limit=20]` |
125
- | Ping another user (cross-user line) | `metro send metro://claude/<user-id>/<session-id> <text> [--from=<line>]` |
126
- | Register webhook endpoint | `metro webhook add <label> [--secret=<hmac-secret>]` |
127
- | List / remove webhook endpoints | `metro webhook list` · `metro webhook remove <id>` |
128
- | Configure Cloudflare named tunnel | `metro tunnel setup <tunnel-name> <hostname>` |
129
-
130
- `reply` / `send` / `edit` accept multi-line text via stdin (heredoc).
131
-
132
- ### Rich content flags
133
-
134
- `send` and `reply` accept these extra flags; `edit` accepts `--buttons` only.
135
-
136
- - `--image=<path>` — upload a local image. **Repeatable** for albums: `--image=a.png --image=b.png`. Comma-separated also works: `--image='a.png,b.png'`. Up to 10 / message. Text becomes the caption (on the first image for albums).
137
- - `--document=<path>` — upload any local file (PDF, log, csv, …). Same repeat/comma syntax.
138
- - `--voice=<path>` — single voice message (`.ogg` Opus or `.mp3`). On Telegram renders as a voice bubble via `sendVoice`; on Discord uploaded as an audio attachment.
139
- - `--buttons='[[{"text":"…","url":"https://…"}]]'` — attach an inline URL-button keyboard. 2D array: outer = rows, inner = buttons on that row.
140
-
141
- ```bash
142
- metro send <line> "screenshot" --image=/tmp/build.png
143
- metro send <line> "before/after" --image=/tmp/before.png --image=/tmp/after.png
144
- metro reply <line> <id> "log + transcript" --document=/tmp/run.log --document=/tmp/transcript.txt
145
- metro send <line> "have a listen" --voice=/tmp/note.ogg
146
- metro send <line> "approve?" --buttons='[[{"text":"Open PR","url":"https://github.com/x/y/pull/1"}]]'
147
- metro edit <line> <id> "still working…" --buttons='[]' # clears buttons
148
- ```
149
-
150
- Limits / quirks:
151
- - 20 MB per file (both platforms).
152
- - Telegram albums are single-type (all photos OR all documents in one album). Mixing kinds in one send still works — metro splits into two album messages and returns the first id.
153
- - Telegram drops `--buttons` when multiple attachments are sent (the Bot API doesn't allow `reply_markup` on media groups).
154
- - URL buttons only (no callback / interactive components yet).
155
-
156
- ## When to use `reply` vs `send`
157
-
158
- - **`reply`** — responding to a specific inbound message. Threads under it. Default for handling an `inbound` event.
159
- - **`send`** — initiating without a triggering message: a long task finished, a follow-up the user asked you to deliver later, or posting to a Claude / Codex line (`metro://claude/...`, `metro://codex/...`) to notify a peer.
160
-
161
- ## Line URI scheme
162
-
163
- `metro://<station>/<path>` — see [docs/uri-scheme.md](https://github.com/bonustrack/metro/blob/main/docs/uri-scheme.md) for the full grammar.
164
-
165
- | Station | Pattern | Example |
166
- |------------|-------------------------------------------|--------------------------------------|
167
- | `discord` | `metro://discord/<channel-id>` | `metro://discord/1234567890` |
168
- | `telegram` | `metro://telegram/<chat-id>[/<topic-id>]` | `metro://telegram/-1001234567890/42` |
169
- | `claude` | `metro://claude/<user-id>/<session-id>` | `metro://claude/9bfc7af0-…/50b00d11-…` |
170
- | `codex` | `metro://codex/<user-id>/<session-id>` | `metro://codex/8119ecb1-…/01997d4b-…` |
171
- | `webhook` | `metro://webhook/<endpoint-id>` | `metro://webhook/fwaCgTKJuLAjS2K0` |
172
-
173
- The `messageId` is **not** part of the URI — it's a separate positional arg for `reply` / `edit` / `react` / `download`.
174
-
175
- ## Image attachments
176
-
177
- When an event's `text` contains `[image]`:
178
-
179
- 1. `metro download <line> <messageId>` — writes images to disk and prints absolute paths.
180
- 2. `Read` each path with your Read tool — the image enters your context as a vision input.
181
- 3. Reply normally with `metro reply`.
182
-
183
- ## Opaque attachment markers
184
-
185
- `[voice]`, `[audio]`, and `[file: <name>]` are opaque — `metro download` only handles images. Acknowledge in text or ask the user to resend as a regular file.
186
-
187
- ## Cross-user notification
188
-
189
- Both Claude Code and Codex can post to each other's line:
190
-
191
- ```bash
192
- metro send metro://claude/9bfc7af0-…/50b00d11-… "build green, ready to ship"
193
- metro send metro://codex/8119ecb1-…/01997d4b-… "build green" --from=metro://claude/user/9bfc7af0-… # override sender
194
- ```
195
-
196
- The daemon re-emits the post on its stdout stream (and pushes via codex-rc if configured), so the peer sees an `{"kind":"inbound",...}` event. Requires the metro daemon to be running on the machine — Claude / Codex line sends error with `metro daemon is not running` otherwise.
197
-
198
- ## Discoverability
199
-
200
- - `metro lines` — list recently-seen conversations (sorted by recency).
201
- - `metro stations` — list stations + capability matrix.
202
- - `metro history` — universal message log (every inbound + outbound + edit + react across all stations). Newest first. Filters:
203
- - `--limit=N` (default 50)
204
- - `--line=<metro://…>` — only this conversation
205
- - `--station=<discord|telegram|claude|codex|webhook>`
206
- - `--kind=<inbound|outbound|edit|react>`
207
- - `--from=<sender>`
208
- - `--text=<substring>`
209
- - `--since=<iso>` — e.g. `--since=2026-05-14T00:00:00Z`
210
- - `--json` — machine-parseable
211
-
212
- Every action you take is logged automatically — `metro send`/`reply`/`edit`/`react` append outbound entries, daemon-side inbounds append on arrival. Stored at `$METRO_STATE_DIR/history.jsonl`.
213
-
214
- ## Universal message IDs
215
-
216
- The `id` from `metro history` or an event JSON works **anywhere a `<message_id>` argument is expected**:
217
-
218
- ```bash
219
- # Either form works for reply/edit/react/download:
220
- metro reply <line> 4567 "ack" # platform messageId (Telegram int)
221
- metro reply <line> msg_aB3xY7zP "ack" # universal — resolves via history
222
- ```
223
-
224
- Use universal IDs when chaining commands or referring back to a specific message across stations.
225
-
226
- ## Exit codes
227
-
228
- - `0` success
229
- - `1` usage error (bad args, unknown subcommand)
230
- - `2` configuration error (no tokens — tell the user to run `metro setup`)
231
- - `3` upstream error (rate limit, auth, network) — retry once after a few seconds before surfacing
232
-
233
- `metro doctor` diagnoses tokens, gateways, dispatcher liveness, and codex-rc target.
234
-
235
- ## --json output
236
-
237
- Every command supports `--json` for stable parseable output:
238
-
239
- ```bash
240
- metro reply <line> <messageId> "ack" --json
241
- # {"ok":true,"line":"metro://discord/...","replyTo":"...","messageId":"..."}
242
-
243
- metro fetch metro://discord/1234 --limit=10 --json
244
- # {"ok":true,"line":"...","messages":[{"messageId":"...","author":"...","text":"...","timestamp":"..."},...]}
245
-
246
- metro download <line> <messageId> --json
247
- # {"ok":true,"line":"...","files":[{"path":"/abs/...png","mediaType":"image/png"}]}
248
- ```
249
-
250
- Use `--json` when you need to chain calls or capture the new `messageId` for a later edit.
251
-
252
- ## Don'ts
253
-
254
- - ❌ Spawning a second metro daemon — there's one per machine (lockfile-enforced).
255
- - ❌ Posting to a line that isn't in `metro lines` unless the user gave it to you explicitly.
256
- - ❌ Narrating the tool ("I'll now use metro reply to…"). The tool call is already visible to the user.