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

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 (453) hide show
  1. package/dist/api.js +9 -101
  2. package/dist/background.js +123 -0
  3. package/dist/claude-settings.js +40 -0
  4. package/dist/claude.js +173 -0
  5. package/dist/cli.js +47 -110
  6. package/dist/control.js +19 -103
  7. package/dist/hold.js +210 -0
  8. package/dist/local.js +43 -0
  9. package/dist/mcp-config.js +25 -0
  10. package/dist/node-name.js +71 -0
  11. package/dist/onboarding.js +44 -0
  12. package/dist/provider-flags.js +9 -0
  13. package/dist/route.js +58 -0
  14. package/dist/runtime-install.js +96 -0
  15. package/dist/runtime.js +29 -52
  16. package/dist/serve.js +157 -0
  17. package/dist/service.js +304 -0
  18. package/dist/tail.js +119 -0
  19. package/dist/update.js +13 -1
  20. package/package.json +2 -23
  21. package/runtime/marketplace/.claude-plugin/marketplace.json +12 -0
  22. package/runtime/marketplace/plugin/.claude-plugin/plugin.json +17 -0
  23. package/runtime/marketplace/plugin/.mcp.json +1 -0
  24. package/runtime/marketplace/plugin/METRO.md +26 -0
  25. package/runtime/marketplace/plugin/STAGE.md +42 -0
  26. package/runtime/marketplace/plugin/bin/guard.mjs +71 -0
  27. package/runtime/marketplace/plugin/bin/metro-plugin.mjs +30 -0
  28. package/runtime/marketplace/plugin/bin/policy.mjs +97 -0
  29. package/runtime/marketplace/plugin/bin/session-start.mjs +31 -0
  30. package/runtime/marketplace/plugin/hooks/hooks.json +25 -0
  31. package/runtime/node_modules/@metro-labs/core/package.json +51 -0
  32. package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
  33. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/events.ts +11 -7
  34. package/runtime/node_modules/@metro-labs/{mcp/src/db → core/src}/ids.ts +5 -0
  35. package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
  36. package/runtime/node_modules/@metro-labs/{mcp/src/stations → core/src}/lines.ts +22 -26
  37. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/protocol.ts +7 -4
  38. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/secure-fs.ts +17 -0
  39. package/runtime/node_modules/@metro-labs/core/src/station-names.ts +14 -0
  40. package/runtime/node_modules/@metro-labs/core/src/stations/account-files.ts +41 -0
  41. package/runtime/node_modules/@metro-labs/core/src/stations/account-store.ts +83 -0
  42. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/attachments.ts +0 -1
  43. package/runtime/node_modules/@metro-labs/core/src/stations/mail-text.ts +72 -0
  44. package/runtime/node_modules/@metro-labs/core/src/stations/mail-trust.ts +29 -0
  45. package/runtime/node_modules/@metro-labs/core/src/stations/mail.ts +212 -0
  46. package/runtime/node_modules/@metro-labs/core/src/stations/messaging-normalize.ts +16 -0
  47. package/runtime/node_modules/@metro-labs/core/src/stations/oauth.ts +126 -0
  48. package/runtime/node_modules/@metro-labs/core/src/stations/profile.ts +58 -0
  49. package/runtime/node_modules/@metro-labs/core/src/stations/sender-profile.ts +64 -0
  50. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/station-runtime.ts +6 -11
  51. package/runtime/node_modules/@metro-labs/core/src/stations/train-boot.ts +42 -0
  52. package/runtime/node_modules/@metro-labs/core/src/stations/train-events.ts +84 -0
  53. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/types.ts +18 -1
  54. package/runtime/node_modules/@metro-labs/core/src/tickets.ts +37 -0
  55. package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
  56. package/runtime/node_modules/@metro-labs/daemon/package.json +49 -0
  57. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/agent-fs.ts +134 -0
  58. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files-api.ts +12 -0
  59. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files.ts +89 -0
  60. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/home-fs.ts +113 -0
  61. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/job-env.ts +51 -0
  62. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/provision.ts +80 -0
  63. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedule-detail.ts +99 -0
  64. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules-api.ts +27 -0
  65. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules.ts +144 -0
  66. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/unit-files.ts +37 -0
  67. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/user.ts +89 -0
  68. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/view.ts +87 -0
  69. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-attach.ts +19 -0
  70. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-lookups.ts +55 -0
  71. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-routes.ts +76 -0
  72. package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +357 -0
  73. package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +30 -0
  74. package/runtime/node_modules/@metro-labs/daemon/src/agents/allowlist.ts +59 -0
  75. package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +131 -0
  76. package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +132 -0
  77. package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +305 -0
  78. package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +142 -0
  79. package/runtime/node_modules/@metro-labs/{mcp/src/db/key-map.ts → daemon/src/agents/keys.ts} +1 -11
  80. package/runtime/node_modules/@metro-labs/daemon/src/agents/map.ts +133 -0
  81. package/runtime/node_modules/@metro-labs/daemon/src/agents/policy-route.ts +27 -0
  82. package/runtime/node_modules/@metro-labs/{mcp/src/db/agent-scope.ts → daemon/src/agents/scope.ts} +2 -2
  83. package/runtime/node_modules/@metro-labs/daemon/src/agents/sender-cards.ts +94 -0
  84. package/runtime/node_modules/@metro-labs/daemon/src/agents/senders.ts +38 -0
  85. package/runtime/node_modules/@metro-labs/daemon/src/approvals/api.ts +55 -0
  86. package/runtime/node_modules/@metro-labs/daemon/src/approvals/pending.ts +150 -0
  87. package/runtime/node_modules/@metro-labs/daemon/src/approvals/preview.ts +66 -0
  88. package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +221 -0
  89. package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +36 -0
  90. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/crash-guard.ts +1 -1
  91. package/runtime/node_modules/@metro-labs/daemon/src/boot/local-owner.ts +21 -0
  92. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/paths.ts +6 -34
  93. package/runtime/node_modules/@metro-labs/daemon/src/channels/addressed.ts +26 -0
  94. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/inbound.ts +75 -45
  95. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/media-note.ts +11 -7
  96. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/pending.ts +4 -1
  97. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/relay.ts +2 -2
  98. package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +368 -0
  99. package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +359 -0
  100. package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +208 -0
  101. package/runtime/node_modules/@metro-labs/daemon/src/claude/memory.ts +32 -0
  102. package/runtime/node_modules/@metro-labs/daemon/src/claude/onboarding.ts +60 -0
  103. package/runtime/node_modules/@metro-labs/daemon/src/claude/plugin-install.ts +149 -0
  104. package/runtime/node_modules/@metro-labs/daemon/src/claude/session-files.ts +75 -0
  105. package/runtime/node_modules/@metro-labs/daemon/src/claude/session.ts +295 -0
  106. package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +109 -0
  107. package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +329 -0
  108. package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +120 -0
  109. package/runtime/node_modules/@metro-labs/daemon/src/claude/usage-probe.ts +127 -0
  110. package/runtime/node_modules/@metro-labs/daemon/src/claude/version.ts +113 -0
  111. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-api.ts → daemon/src/connectors/api.ts} +79 -113
  112. package/runtime/node_modules/@metro-labs/{mcp/src/db/connector-config.ts → daemon/src/connectors/config.ts} +67 -41
  113. package/runtime/node_modules/@metro-labs/daemon/src/connectors/gates.ts +72 -0
  114. package/runtime/node_modules/@metro-labs/daemon/src/connectors/health.ts +18 -0
  115. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-client.ts +14 -17
  116. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-discovery.ts +33 -20
  117. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth-routes.ts → daemon/src/connectors/oauth-routes.ts} +30 -32
  118. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth.ts → daemon/src/connectors/oauth.ts} +61 -22
  119. package/runtime/node_modules/@metro-labs/daemon/src/connectors/plugin-sync.ts +131 -0
  120. package/runtime/node_modules/@metro-labs/daemon/src/connectors/reach.ts +27 -0
  121. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-policy.ts +90 -0
  122. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +347 -0
  123. package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +385 -0
  124. package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +81 -0
  125. package/runtime/node_modules/@metro-labs/daemon/src/connectors/transfer-api.ts +116 -0
  126. package/runtime/node_modules/@metro-labs/daemon/src/connectors/transfer-crypto.ts +44 -0
  127. package/runtime/node_modules/@metro-labs/daemon/src/connectors/transfer-store.ts +48 -0
  128. package/runtime/node_modules/@metro-labs/daemon/src/connectors/url.ts +37 -0
  129. package/runtime/node_modules/@metro-labs/daemon/src/connectors/verify.ts +106 -0
  130. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-grant.ts +4 -4
  131. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-owner.ts +3 -3
  132. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-reaper.ts +174 -0
  133. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-serve.ts +12 -13
  134. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-api.ts +10 -27
  135. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-store.ts +4 -4
  136. package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +233 -0
  137. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +214 -0
  138. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-device.ts +91 -0
  139. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +173 -0
  140. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +209 -0
  141. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-version.ts +44 -0
  142. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +155 -0
  143. package/runtime/node_modules/@metro-labs/daemon/src/gateway/effort.ts +93 -0
  144. package/runtime/node_modules/@metro-labs/daemon/src/gateway/eventstream.ts +123 -0
  145. package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +237 -0
  146. package/runtime/node_modules/@metro-labs/daemon/src/gateway/frames.ts +118 -0
  147. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +307 -0
  148. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-auth.ts +160 -0
  149. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-client.ts +46 -0
  150. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-setup.ts +150 -0
  151. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-stream.ts +139 -0
  152. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-translate.ts +235 -0
  153. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini.ts +208 -0
  154. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +203 -0
  155. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +285 -0
  156. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-lists.ts +57 -0
  157. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-signin.ts +161 -0
  158. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-store.ts +72 -0
  159. package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +104 -0
  160. package/runtime/node_modules/@metro-labs/daemon/src/gateway/pkce.ts +36 -0
  161. package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +118 -0
  162. package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +18 -0
  163. package/runtime/node_modules/@metro-labs/daemon/src/gateway/subscription.ts +120 -0
  164. package/runtime/node_modules/@metro-labs/daemon/src/gateway/text.ts +35 -0
  165. package/runtime/node_modules/@metro-labs/daemon/src/gateway/tool-search.ts +126 -0
  166. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage-refresh.ts +102 -0
  167. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +348 -0
  168. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/accounts.ts +28 -17
  169. package/runtime/node_modules/@metro-labs/daemon/src/mcp/attachment-schema.ts +91 -0
  170. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/call-tools.ts +49 -20
  171. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/ctx.ts +4 -4
  172. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/event-store.ts +15 -16
  173. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/group-tools.ts +2 -2
  174. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/index.ts +34 -80
  175. package/runtime/node_modules/@metro-labs/daemon/src/mcp/instructions.ts +19 -0
  176. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/member-tools.ts +2 -2
  177. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-prompt.ts +87 -0
  178. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +88 -0
  179. package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-gate.ts +82 -0
  180. package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-snapshot.ts +79 -0
  181. package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-lookup.ts +60 -0
  182. package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-tool.ts +96 -0
  183. package/runtime/node_modules/@metro-labs/daemon/src/mcp/read-tool.ts +87 -0
  184. package/runtime/node_modules/@metro-labs/daemon/src/mcp/request-identity.ts +46 -0
  185. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-slot.ts +71 -0
  186. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/session.ts +47 -44
  187. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-catalog.ts +93 -0
  188. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-def.ts +9 -0
  189. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-dispatch.ts +53 -40
  190. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-schemas.ts +64 -113
  191. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/upload-tool.ts +6 -11
  192. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/helper-script.ts +126 -0
  193. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/install.ts +37 -0
  194. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/privilege.ts +48 -0
  195. package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +132 -0
  196. package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +316 -0
  197. package/runtime/node_modules/@metro-labs/daemon/src/policy/policy.ts +118 -0
  198. package/runtime/node_modules/@metro-labs/daemon/src/routes/bearer.ts +35 -0
  199. package/runtime/node_modules/@metro-labs/daemon/src/routes/body.ts +24 -0
  200. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/routes}/http.ts +63 -51
  201. package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +209 -0
  202. package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +69 -0
  203. package/runtime/node_modules/@metro-labs/daemon/src/routes/session.ts +29 -0
  204. package/runtime/node_modules/@metro-labs/daemon/src/routes/threema-callback.ts +103 -0
  205. package/runtime/node_modules/@metro-labs/daemon/src/server/cloudwatch.ts +178 -0
  206. package/runtime/node_modules/@metro-labs/daemon/src/server/control.ts +39 -0
  207. package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +58 -0
  208. package/runtime/node_modules/@metro-labs/daemon/src/server/owner.ts +26 -0
  209. package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +90 -0
  210. package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
  211. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-browser.ts +102 -0
  212. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-driver.ts +42 -0
  213. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-inline.ts +29 -1
  214. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-interactive.ts +5 -31
  215. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-resolve.ts +38 -13
  216. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/attach-session.ts +32 -22
  217. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-xmtp.ts +8 -9
  218. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach.ts +69 -3
  219. package/runtime/node_modules/@metro-labs/{mcp/src/db → daemon/src/stations}/materialize.ts +60 -179
  220. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/registry.ts +20 -2
  221. package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +82 -0
  222. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor-io.ts +3 -3
  223. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor.ts +6 -9
  224. package/runtime/node_modules/@metro-labs/daemon/src/stations/threema-callbacks.ts +32 -0
  225. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/train-call.ts +1 -1
  226. package/runtime/node_modules/@metro-labs/daemon/src/stations/webhook-endpoints.ts +51 -0
  227. package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +84 -0
  228. package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +124 -0
  229. package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +15 -0
  230. package/runtime/node_modules/@metro-labs/daemon/src/vault/api.ts +45 -0
  231. package/runtime/node_modules/@metro-labs/daemon/src/vault/config.ts +51 -0
  232. package/runtime/node_modules/@metro-labs/daemon/src/vault/firewall.ts +9 -0
  233. package/runtime/node_modules/@metro-labs/daemon/src/vault/index.ts +96 -0
  234. package/runtime/node_modules/@metro-labs/daemon/src/vault/install.ts +56 -0
  235. package/runtime/node_modules/@metro-labs/daemon/src/vault/paths.ts +26 -0
  236. package/runtime/node_modules/@metro-labs/daemon/src/vault/proxy.ts +147 -0
  237. package/runtime/node_modules/@metro-labs/daemon/src/vault/store.ts +129 -0
  238. package/runtime/node_modules/@metro-labs/daemon/src/vault/trust.ts +44 -0
  239. package/runtime/node_modules/@metro-labs/discord-bot/package.json +2 -4
  240. package/runtime/node_modules/@metro-labs/discord-bot/src/accounts.ts +3 -23
  241. package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +19 -187
  242. package/runtime/node_modules/@metro-labs/discord-bot/src/attachments.ts +2 -2
  243. package/runtime/node_modules/@metro-labs/discord-bot/src/format.ts +26 -67
  244. package/runtime/node_modules/@metro-labs/discord-bot/src/group-actions.ts +1 -1
  245. package/runtime/node_modules/@metro-labs/discord-bot/src/group.ts +2 -2
  246. package/runtime/node_modules/@metro-labs/discord-bot/src/index.ts +8 -14
  247. package/runtime/node_modules/@metro-labs/discord-bot/src/members.ts +2 -2
  248. package/runtime/node_modules/@metro-labs/discord-bot/src/profile.ts +68 -0
  249. package/runtime/node_modules/@metro-labs/discord-bot/src/send-files.ts +12 -13
  250. package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +5 -1
  251. package/runtime/node_modules/@metro-labs/gmail/package.json +25 -0
  252. package/runtime/node_modules/@metro-labs/gmail/src/accounts.ts +81 -0
  253. package/runtime/node_modules/@metro-labs/gmail/src/actions.ts +14 -0
  254. package/runtime/node_modules/@metro-labs/gmail/src/api.ts +31 -0
  255. package/runtime/node_modules/@metro-labs/gmail/src/attachments.ts +35 -0
  256. package/runtime/node_modules/@metro-labs/gmail/src/auth.ts +105 -0
  257. package/runtime/node_modules/@metro-labs/gmail/src/config.ts +13 -0
  258. package/runtime/node_modules/@metro-labs/gmail/src/inbound.ts +96 -0
  259. package/runtime/node_modules/@metro-labs/gmail/src/index.ts +12 -0
  260. package/runtime/node_modules/@metro-labs/gmail/src/login.ts +37 -0
  261. package/runtime/node_modules/@metro-labs/gmail/src/message.ts +125 -0
  262. package/runtime/node_modules/@metro-labs/gmail/src/mime.ts +70 -0
  263. package/runtime/node_modules/@metro-labs/gmail/src/outbound.ts +124 -0
  264. package/runtime/node_modules/@metro-labs/gmail/src/query.ts +99 -0
  265. package/runtime/node_modules/@metro-labs/gmail/src/state.ts +24 -0
  266. package/runtime/node_modules/@metro-labs/gmail/src/station.ts +15 -0
  267. package/runtime/node_modules/@metro-labs/gmail/src/trust.ts +42 -0
  268. package/runtime/node_modules/@metro-labs/http/package.json +30 -0
  269. package/runtime/node_modules/@metro-labs/http/src/api-http.ts +135 -0
  270. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/session-api.ts → http/src/mode-api.ts} +13 -9
  271. package/runtime/node_modules/@metro-labs/http/src/return-to.ts +21 -0
  272. package/runtime/node_modules/@metro-labs/http/src/sigv4.ts +90 -0
  273. package/runtime/node_modules/@metro-labs/http/src/workos-token.ts +149 -0
  274. package/runtime/node_modules/@metro-labs/outlook/package.json +25 -0
  275. package/runtime/node_modules/@metro-labs/outlook/src/accounts.ts +78 -0
  276. package/runtime/node_modules/@metro-labs/outlook/src/actions.ts +14 -0
  277. package/runtime/node_modules/@metro-labs/outlook/src/attachments.ts +81 -0
  278. package/runtime/node_modules/@metro-labs/outlook/src/auth.ts +120 -0
  279. package/runtime/node_modules/@metro-labs/outlook/src/browser.ts +42 -0
  280. package/runtime/node_modules/@metro-labs/outlook/src/config.ts +23 -0
  281. package/runtime/node_modules/@metro-labs/outlook/src/format.ts +59 -0
  282. package/runtime/node_modules/@metro-labs/outlook/src/graph.ts +55 -0
  283. package/runtime/node_modules/@metro-labs/outlook/src/inbound.ts +96 -0
  284. package/runtime/node_modules/@metro-labs/outlook/src/index.ts +12 -0
  285. package/runtime/node_modules/@metro-labs/outlook/src/login.ts +129 -0
  286. package/runtime/node_modules/@metro-labs/outlook/src/me.ts +31 -0
  287. package/runtime/node_modules/@metro-labs/outlook/src/outbound.ts +103 -0
  288. package/runtime/node_modules/@metro-labs/outlook/src/query.ts +84 -0
  289. package/runtime/node_modules/@metro-labs/outlook/src/state.ts +28 -0
  290. package/runtime/node_modules/@metro-labs/outlook/src/station.ts +15 -0
  291. package/runtime/node_modules/@metro-labs/outlook/src/trust.ts +41 -0
  292. package/runtime/node_modules/@metro-labs/telegram/package.json +1 -3
  293. package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +5 -24
  294. package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +8 -6
  295. package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +1 -1
  296. package/runtime/node_modules/@metro-labs/telegram/src/client.ts +2 -2
  297. package/runtime/node_modules/@metro-labs/telegram/src/format.ts +19 -34
  298. package/runtime/node_modules/@metro-labs/telegram/src/group.ts +3 -3
  299. package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +13 -34
  300. package/runtime/node_modules/@metro-labs/telegram/src/index.ts +4 -43
  301. package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +2 -3
  302. package/runtime/node_modules/@metro-labs/telegram/src/members.ts +1 -1
  303. package/runtime/node_modules/@metro-labs/telegram/src/profile.ts +70 -0
  304. package/runtime/node_modules/@metro-labs/telegram/src/reactions.ts +2 -2
  305. package/runtime/node_modules/@metro-labs/telegram/src/station.ts +4 -1
  306. package/runtime/node_modules/@metro-labs/telegram/src/types.ts +0 -1
  307. package/runtime/node_modules/@metro-labs/telegram-bot/package.json +1 -1
  308. package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +7 -41
  309. package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +22 -77
  310. package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +2 -2
  311. package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +46 -48
  312. package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +15 -15
  313. package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +6 -82
  314. package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +1 -1
  315. package/runtime/node_modules/@metro-labs/telegram-bot/src/profile.ts +85 -0
  316. package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +5 -1
  317. package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +20 -12
  318. package/runtime/node_modules/@metro-labs/threema/package.json +26 -0
  319. package/runtime/node_modules/@metro-labs/threema/src/accounts.ts +96 -0
  320. package/runtime/node_modules/@metro-labs/threema/src/actions.ts +124 -0
  321. package/runtime/node_modules/@metro-labs/threema/src/api.ts +152 -0
  322. package/runtime/node_modules/@metro-labs/threema/src/crypto.ts +100 -0
  323. package/runtime/node_modules/@metro-labs/threema/src/files.ts +47 -0
  324. package/runtime/node_modules/@metro-labs/threema/src/format.ts +164 -0
  325. package/runtime/node_modules/@metro-labs/threema/src/groups.ts +96 -0
  326. package/runtime/node_modules/@metro-labs/threema/src/ids.ts +21 -0
  327. package/runtime/node_modules/@metro-labs/threema/src/inbound.ts +87 -0
  328. package/runtime/node_modules/@metro-labs/threema/src/index.ts +24 -0
  329. package/runtime/node_modules/@metro-labs/threema/src/messages.ts +264 -0
  330. package/runtime/node_modules/@metro-labs/threema/src/outbound.ts +160 -0
  331. package/runtime/node_modules/@metro-labs/threema/src/station.ts +13 -0
  332. package/runtime/node_modules/@metro-labs/threema/src/verify.ts +117 -0
  333. package/runtime/node_modules/@metro-labs/webhook/package.json +1 -1
  334. package/runtime/node_modules/@metro-labs/webhook/src/station.ts +5 -8
  335. package/runtime/node_modules/@metro-labs/whatsapp/package.json +2 -5
  336. package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +6 -28
  337. package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +1 -1
  338. package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +54 -11
  339. package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +2 -2
  340. package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +1 -1
  341. package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +86 -4
  342. package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +7 -58
  343. package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +11 -28
  344. package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +4 -37
  345. package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +1 -1
  346. package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +1 -1
  347. package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +1 -1
  348. package/runtime/node_modules/@metro-labs/whatsapp/src/names.ts +75 -0
  349. package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +44 -0
  350. package/runtime/node_modules/@metro-labs/whatsapp/src/resolve.ts +52 -0
  351. package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +16 -1
  352. package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +5 -9
  353. package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +0 -1
  354. package/runtime/node_modules/@metro-labs/xmtp/package.json +3 -2
  355. package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +10 -20
  356. package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +2 -2
  357. package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +15 -204
  358. package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +40 -53
  359. package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +72 -220
  360. package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +3 -3
  361. package/runtime/node_modules/@metro-labs/xmtp/src/codecs.ts +27 -0
  362. package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +11 -7
  363. package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +7 -24
  364. package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +8 -18
  365. package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +1 -1
  366. package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +2 -2
  367. package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +30 -16
  368. package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +12 -20
  369. package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +57 -33
  370. package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +1 -1
  371. package/runtime/node_modules/@metro-labs/xmtp/src/names.ts +61 -0
  372. package/runtime/node_modules/@metro-labs/xmtp/src/profile.ts +153 -0
  373. package/runtime/node_modules/@metro-labs/xmtp/src/resolve.ts +44 -0
  374. package/runtime/node_modules/@metro-labs/xmtp/src/sender.ts +112 -0
  375. package/runtime/node_modules/@metro-labs/xmtp/src/smart.ts +72 -0
  376. package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +7 -2
  377. package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +22 -58
  378. package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +55 -48
  379. package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +4 -6
  380. package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +19 -5
  381. package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +14 -4
  382. package/runtime/runtime.json +1 -1
  383. package/runtime/server.ts +1 -0
  384. package/runtime/stations.json +38 -0
  385. package/dist/prompt.js +0 -61
  386. package/dist/store.js +0 -70
  387. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-speak.ts +0 -195
  388. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-transcribe.ts +0 -292
  389. package/runtime/node_modules/@metro-labs/discord-bot/src/voice.ts +0 -197
  390. package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +0 -5
  391. package/runtime/node_modules/@metro-labs/mcp/package.json +0 -66
  392. package/runtime/node_modules/@metro-labs/mcp/src/channels/dedupe.ts +0 -24
  393. package/runtime/node_modules/@metro-labs/mcp/src/daemon/account-api.ts +0 -311
  394. package/runtime/node_modules/@metro-labs/mcp/src/daemon/agent-api.ts +0 -341
  395. package/runtime/node_modules/@metro-labs/mcp/src/daemon/api-http.ts +0 -129
  396. package/runtime/node_modules/@metro-labs/mcp/src/daemon/boot.ts +0 -320
  397. package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair-api.ts +0 -111
  398. package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair.ts +0 -20
  399. package/runtime/node_modules/@metro-labs/mcp/src/daemon/collection-api.ts +0 -202
  400. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-json.ts +0 -31
  401. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-tools.ts +0 -100
  402. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-url.ts +0 -57
  403. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-verify.ts +0 -333
  404. package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-auth.ts +0 -164
  405. package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-oauth.ts +0 -208
  406. package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity.ts +0 -79
  407. package/runtime/node_modules/@metro-labs/mcp/src/daemon/oauth-pending.ts +0 -65
  408. package/runtime/node_modules/@metro-labs/mcp/src/daemon/pair-codes.ts +0 -58
  409. package/runtime/node_modules/@metro-labs/mcp/src/daemon/project-api.ts +0 -214
  410. package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-api.ts +0 -125
  411. package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-pair.ts +0 -18
  412. package/runtime/node_modules/@metro-labs/mcp/src/daemon/runtime-source.ts +0 -105
  413. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session-apis.ts +0 -41
  414. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session.ts +0 -218
  415. package/runtime/node_modules/@metro-labs/mcp/src/daemon/tunnel.ts +0 -169
  416. package/runtime/node_modules/@metro-labs/mcp/src/db/account-attach.ts +0 -91
  417. package/runtime/node_modules/@metro-labs/mcp/src/db/agent-admin.ts +0 -215
  418. package/runtime/node_modules/@metro-labs/mcp/src/db/agent-map.ts +0 -71
  419. package/runtime/node_modules/@metro-labs/mcp/src/db/client.ts +0 -37
  420. package/runtime/node_modules/@metro-labs/mcp/src/db/connector-collections.ts +0 -218
  421. package/runtime/node_modules/@metro-labs/mcp/src/db/connectors.ts +0 -329
  422. package/runtime/node_modules/@metro-labs/mcp/src/db/projects.ts +0 -300
  423. package/runtime/node_modules/@metro-labs/mcp/src/db/runtime-admin.ts +0 -31
  424. package/runtime/node_modules/@metro-labs/mcp/src/db/runtimes.ts +0 -105
  425. package/runtime/node_modules/@metro-labs/mcp/src/db/schema.ts +0 -131
  426. package/runtime/node_modules/@metro-labs/mcp/src/db/token-carry.ts +0 -45
  427. package/runtime/node_modules/@metro-labs/mcp/src/db/users.ts +0 -57
  428. package/runtime/node_modules/@metro-labs/mcp/src/db/whatsapp-login.ts +0 -18
  429. package/runtime/node_modules/@metro-labs/mcp/src/mcp/channel-owner.ts +0 -29
  430. package/runtime/node_modules/@metro-labs/mcp/src/mcp/frame-scope.ts +0 -21
  431. package/runtime/node_modules/@metro-labs/mcp/src/mcp/permission-relay.ts +0 -66
  432. package/runtime/node_modules/@metro-labs/mcp/src/mcp/request-identity.ts +0 -73
  433. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-registry.ts +0 -172
  434. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-route.ts +0 -43
  435. package/runtime/node_modules/@metro-labs/mcp/src/monitor/api.ts +0 -240
  436. package/runtime/node_modules/@metro-labs/mcp/src/server.ts +0 -2
  437. package/runtime/node_modules/@metro-labs/mcp/src/stations/account-store.ts +0 -80
  438. package/runtime/node_modules/@metro-labs/mcp/src/stations/messaging-normalize.ts +0 -88
  439. package/runtime/node_modules/@metro-labs/telegram/src/normalize.ts +0 -22
  440. package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +0 -1
  441. package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +0 -3
  442. package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +0 -22
  443. package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +0 -5
  444. package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +0 -87
  445. package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +0 -55
  446. package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +0 -349
  447. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/log.ts +0 -0
  448. /package/runtime/node_modules/@metro-labs/{mcp/src/mcp → core/src}/str.ts +0 -0
  449. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/train-error.ts +0 -0
  450. /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/webhook-note.ts +0 -0
  451. /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/raw-get-stream.ts +0 -0
  452. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/api-error.ts +0 -0
  453. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/cors.ts +0 -0
package/dist/tail.js ADDED
@@ -0,0 +1,119 @@
1
+ import { localAgent } from './local.js';
2
+ import { assertAgentId, localUrl } from './runtime.js';
3
+ const BACKOFF_MS = [1_000, 2_000, 5_000];
4
+ const STALL_MS = 90_000;
5
+ export const backoffAt = (attempt) => BACKOFF_MS[Math.min(attempt, BACKOFF_MS.length - 1)] ?? 5_000;
6
+ export function sseDataLines(buffer, chunk) {
7
+ const lines = (buffer + chunk).split('\n');
8
+ const rest = lines.pop() ?? '';
9
+ const events = [];
10
+ for (const raw of lines) {
11
+ const line = raw.endsWith('\r') ? raw.slice(0, -1) : raw;
12
+ if (!line.startsWith('data:'))
13
+ continue;
14
+ const value = line.slice(5);
15
+ events.push(value.startsWith(' ') ? value.slice(1) : value);
16
+ }
17
+ return { rest, events };
18
+ }
19
+ function keySource(agentId) {
20
+ const fromEnv = process.env.METRO_AGENT_KEY?.trim();
21
+ if (fromEnv !== undefined && fromEnv !== '')
22
+ return { resolve: () => Promise.resolve(fromEnv), fixed: true };
23
+ return {
24
+ resolve: () => {
25
+ const agent = localAgent();
26
+ if (agent === null || (agentId !== undefined && agent.id !== agentId))
27
+ throw new Error(`no agent ${agentId === undefined ? '' : `${agentId} `}on this machine — start metro serve, or set METRO_AGENT_KEY`);
28
+ return Promise.resolve(agent.key);
29
+ },
30
+ fixed: false,
31
+ };
32
+ }
33
+ const armStall = (control) => setTimeout(() => {
34
+ control.abort();
35
+ }, STALL_MS);
36
+ async function connect(key, signal) {
37
+ try {
38
+ return await fetch(`${localUrl()}/api/tail`, {
39
+ headers: { authorization: `Bearer ${key}` },
40
+ signal,
41
+ });
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ async function pump(body, control, stall) {
48
+ const reader = body.getReader();
49
+ const decoder = new TextDecoder();
50
+ let buffer = '';
51
+ try {
52
+ for (;;) {
53
+ const { done, value } = await reader.read();
54
+ if (done)
55
+ return 'ended';
56
+ clearTimeout(stall.timer);
57
+ stall.timer = armStall(control);
58
+ const out = sseDataLines(buffer, decoder.decode(value, { stream: true }));
59
+ buffer = out.rest;
60
+ for (const event of out.events)
61
+ process.stdout.write(`${event}\n`);
62
+ }
63
+ }
64
+ catch {
65
+ return 'ended';
66
+ }
67
+ }
68
+ async function streamOnce(key) {
69
+ const control = new AbortController();
70
+ const stall = { timer: armStall(control) };
71
+ try {
72
+ const res = await connect(key, control.signal);
73
+ if (res === null)
74
+ return 'unreachable';
75
+ if (res.status === 401)
76
+ return 'unauthorized';
77
+ if (!res.ok || res.body === null)
78
+ return 'unreachable';
79
+ return await pump(res.body, control, stall);
80
+ }
81
+ finally {
82
+ clearTimeout(stall.timer);
83
+ }
84
+ }
85
+ function note(state, message) {
86
+ if (state.last === message)
87
+ return;
88
+ state.last = message;
89
+ process.stderr.write(`metro: ${message}\n`);
90
+ }
91
+ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
92
+ async function settle(end, source, key, state) {
93
+ if (end === 'unauthorized') {
94
+ if (source.fixed)
95
+ throw new Error('the key in METRO_AGENT_KEY was refused by the local daemon');
96
+ note(state, 'key refused — fetching the current one');
97
+ return source.resolve();
98
+ }
99
+ if (end === 'unreachable')
100
+ note(state, `no metro daemon on ${localUrl()} — run 'metro serve'`);
101
+ else
102
+ note(state, 'stream ended — reconnecting');
103
+ return key;
104
+ }
105
+ export async function tailEvents(argv) {
106
+ const agentId = argv[0] === undefined ? undefined : assertAgentId(argv[0]);
107
+ const source = keySource(agentId);
108
+ let key = await source.resolve();
109
+ const state = { last: '' };
110
+ let attempt = 0;
111
+ for (;;) {
112
+ const end = await streamOnce(key);
113
+ if (end === 'ended')
114
+ attempt = 0;
115
+ key = await settle(end, source, key, state);
116
+ await delay(backoffAt(attempt));
117
+ attempt += 1;
118
+ }
119
+ }
package/dist/update.js CHANGED
@@ -9,7 +9,19 @@ export function installArgs(manager, version) {
9
9
  ? ['add', '--global', spec]
10
10
  : ['install', '--global', spec];
11
11
  }
12
- export async function update() {
12
+ export const checkReport = (current, latest) => ({
13
+ current,
14
+ latest,
15
+ newer: latest !== '' && isNewer(latest, current),
16
+ });
17
+ async function updateCheck() {
18
+ return checkReport(currentVersion(), await publishedVersion());
19
+ }
20
+ export async function update(argv = []) {
21
+ if (argv.includes('--check')) {
22
+ process.stdout.write(`${JSON.stringify(await updateCheck())}\n`);
23
+ return 0;
24
+ }
13
25
  const current = currentVersion();
14
26
  const newest = await publishedVersion();
15
27
  if (newest === '') {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stage-labs/metro",
3
- "version": "0.1.0-beta.23",
4
- "description": "The metro command line. Sign in once per machine, then hand your MCP connector list to Claude Code without the credentials touching disk, argv or shell history.",
3
+ "version": "0.1.0-beta.230",
4
+ "description": "The metro command line: run your agent on this machine, relaying its chat channels and connectors to Claude Code.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -35,26 +35,5 @@
35
35
  "knip": "^6.15.0",
36
36
  "madge": "^8.0.0",
37
37
  "typescript": "^5"
38
- },
39
- "dependencies": {
40
- "@discordjs/voice": "^0.19.2",
41
- "@modelcontextprotocol/sdk": "^1.12.0",
42
- "@mtcute/bun": "0.30.1",
43
- "@xmtp/content-type-primitives": "^3.0.1",
44
- "@xmtp/content-type-reaction": "^2.0.2",
45
- "@xmtp/content-type-remote-attachment": "^2.0.4",
46
- "@xmtp/content-type-reply": "^2.0.3",
47
- "@xmtp/content-type-wallet-send-calls": "^2.0.0",
48
- "@xmtp/node-bindings": "1.9.1",
49
- "@xmtp/node-sdk": "^6.0.0",
50
- "baileys": "7.0.0-rc14",
51
- "discord.js": "^14.26.4",
52
- "drizzle-orm": "^0.44.0",
53
- "pino": "^9.5.0",
54
- "pino-pretty": "^13.1.3",
55
- "postgres": "^3.4.5",
56
- "prism-media": "^1.3.5",
57
- "viem": "^2.52.2",
58
- "zod": "^3.23.8"
59
38
  }
60
39
  }
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "metro",
3
+ "description": "Metro — connector relay and chat bridge for agents",
4
+ "owner": { "name": "Bonustrack", "url": "https://metro.box" },
5
+ "plugins": [
6
+ {
7
+ "name": "metro",
8
+ "source": "./plugin",
9
+ "description": "Every connector on this box as its own MCP server through metro's local relay, the orchestrator guard, and the standing rules loaded at session start."
10
+ }
11
+ ]
12
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "metro",
3
+ "version": "0.1.0-beta.230",
4
+ "description": "Metro for Claude Code, installed by the metro daemon on this machine: every connector the agent holds as its own MCP server relayed through the daemon, the orchestrator-only guard on the main thread, and the standing rules loaded at each session start. No vendor credential ever sits in a config file.",
5
+ "author": {
6
+ "name": "Bonustrack",
7
+ "url": "https://metro.box"
8
+ },
9
+ "repository": "https://github.com/bonustrack/metro",
10
+ "license": "MIT",
11
+ "keywords": [
12
+ "metro",
13
+ "mcp",
14
+ "connectors",
15
+ "relay"
16
+ ]
17
+ }
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: metro
3
+ description: How this box's agent works on metro. Acknowledge, delegate, relay, answer over chat, never block on the terminal. Loaded at every session start by the metro plugin; edit it here to change the rules on this box.
4
+ ---
5
+
6
+ You are the main thread of a Claude Code session that is connected to chat through metro, on a machine nobody watches. The main thread is an orchestrator: it may only delegate and talk. A guard in the metro plugin denies every other tool on this thread, so this is the shape of the work, not a preference.
7
+
8
+ **Inbound.** A message arrives as a `<channel source="metro" …>` block. Read `addressed` first: `direct`, `mention` or `reply` means it is for you; without it the message merely happened in a room you watch, so treat it as context and stay silent unless the person plainly wants you. For a message that is for you, the first tool call is `react` on it (👀, then 👍 or ✅ once done) so the person knows you saw it, and any reply goes on the same `line`, passed verbatim. Exception: when the person asks you to close something ("mark as done"), skip the reaction and the acknowledgement: close it directly and confirm once when it is finished.
9
+
10
+ **Typing.** Whenever you are about to send a message on a line within the next 10 seconds, call `typing` on that `line` first, so the person sees "typing…" while you write. It shows once and fades by itself (about 5 s on the Telegram bot, 10 s on Discord, 25 s on WhatsApp) or when your message arrives, so there is nothing to stop. Only WhatsApp, the Telegram bot and Discord support it; on other channels skip it.
11
+
12
+ **Delegate everything that is work.** Reading files, running commands, searching, fetching pages, editing, and every connector tool: hand it to a subagent with the `Agent` tool, `subagent_type: "worker"`, always `run_in_background: true`, then keep answering chat while it runs and relay the result when the task notification arrives. A foreground subagent blinds you to chat and the guard refuses it. You may read image files yourself, so a screenshot someone sends is yours to look at.
13
+
14
+ **Never wait on the terminal.** `AskUserQuestion`, plan mode and anything that blocks for a person at the keyboard are denied everywhere, main thread and subagents alike. When something is ambiguous, do what does not depend on it, choose the most reasonable reading, say so in your reply, and if a real decision is needed ask over chat with `send` and carry on. Tool-approval prompts reach the chat too; the person answers `yes <id>` or `no <id>` there.
15
+
16
+ **Calls that need the owner's approval run in a worker.** The owner can make a metro tool on a channel wait for approval. On the main thread such a call is refused, because waiting for the answer would stop the whole session: hand that exact call to a background worker (`run_in_background: true`) and keep answering. The worker waits for the owner's answer on its own.
17
+
18
+ **Finish what was asked.** You work on your own. Nobody is watching a screen, and a question sent to chat may go unanswered for hours, so asking "Shall I?" about work already requested simply stops it. Anything reversible that follows from the request, do. Stop only for a destructive action or a genuine change of scope. Before you end a turn, read your own last paragraph: if it is a plan, a question, a list of next steps or a promise ("I'll…", "Next…"), then the work is not done, so do it now, retries and missing information included. End the turn when the task is finished, or when you are truly blocked on something only the person can give you.
19
+
20
+ The exception is a person describing a problem, asking a question or thinking out loud. There the answer IS the deliverable: reply, and change nothing until they ask.
21
+
22
+ **The whole request is the deliverable.** Do not quietly make it smaller, larger or different. Read an ambiguity the way a careful colleague would, make the ordinary judgement calls yourself, and name the assumption in your reply. If one part turns out to be blocked, finish every other part and say plainly what you left out and why: scaling the work down is the person's call, not yours. Something else you notice on the way is a suggestion at the end of the reply, not extra work to do now.
23
+
24
+ **Report like a relay.** A worker's report is the only evidence you have, so pass on what it verified and say plainly what it did not. Short messages on chat: lead with the outcome, one idea per sentence, no tool names, no file paths unless the person needs them. Send a file out with `create_upload` (the curl line it hands back runs in a worker) and then `send` with the upload id.
25
+
26
+ **Keep going.** Long tasks run as background agents and loops; check in over chat when something lands rather than going quiet. The session is restarted by the daemon if it exits, so an interrupted task is resumed from chat, not from memory.
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: stage
3
+ description: How to use Stage channels (XMTP groups, https://stage.box) through metro. Create a channel, rename it, add or remove members, set labels and assignees, read its info, and send, reply, react, unreact, delete and read messages. Works only when this agent has an XMTP account in metro.
4
+ ---
5
+
6
+ Stage (https://stage.box) is a messenger built on XMTP. A Stage channel is an XMTP group. You use it with the metro tools below (`mcp__metro__<name>`).
7
+
8
+ **XMTP only.** All of this needs an XMTP account connected to this agent in metro. Check with `list_accounts`: it must show an account under `xmtp`. Many agents have none. Then none of this works: say so plainly and do not try another channel. The owner can add an XMTP channel on https://metro.box.
9
+
10
+ **Lines and links.** A channel's line is `metro://xmtp/<account>/<channel id>`. Pass it verbatim as `line`. Its link is `https://stage.box/#/channel/<channel id>`, the last part of the line. Stage shows Markdown, so `[#Launch plan](https://stage.box/#/channel/<channel id>)` is a clickable link. A `message_id` comes from the inbound message or from `read`.
11
+
12
+ **Channels.**
13
+ - Create: `create_group {"station": "xmtp", "name": "Launch plan", "members": ["0x…"]}`. Members are 0x addresses or XMTP inbox ids. It returns the new `line` and `id`.
14
+ - Rename: `set_channel_metadata {"line": "…", "name": "New title"}`. No tool sets the description or the picture.
15
+ - Add or remove people: `add_members {"line": "…", "members": ["0x…"]}`. `remove_members` takes the same shape.
16
+ - Leave: `close_channel {"line": "…", "removeSelf": true}`.
17
+ - Read: `group_info {"line": "…"}` gives the name, `labels`, `assigned`, `appData` and the members (`inboxId`, `address`). `list_members {"line": "…"}` gives the members only.
18
+ - Direct chat: `dm {"address": "0x…"}` opens a 1:1 chat and returns its line.
19
+ - With several XMTP accounts, add `"account": "<id>"` to `create_group` and `dm`.
20
+
21
+ **Labels and assignees.** They live in the channel's metadata, and Stage shows them on the channel.
22
+ - Labels: `set_channel_metadata {"line": "…", "metadata": {"labels": ["🚧 In progress", "Metro"]}}`. At most 16 labels of 24 characters each.
23
+ - Assignees: `set_channel_metadata {"line": "…", "metadata": {"assigned": ["0x…"]}}`. Only 0x addresses of current members.
24
+ - Each key you send replaces that whole list. Keys you leave out stay as they are. To add one label or one assignee, read `group_info` first and send the old list plus the new one. `[]` clears a list. Read `group_info` again to check it saved.
25
+
26
+ **Task status labels.** When a channel is a task, keep exactly one of these status labels, plus any project labels:
27
+ - `🗒️ Backlog`
28
+ - `🎯 To-do`
29
+ - `🚧 In progress`
30
+ - `🔍 In review`
31
+ - `✅ Done`
32
+ - `🚫 Blocked`
33
+
34
+ Move it from Backlog or To-do to In progress, then In review, then Done. Use Blocked while you wait on someone. To change it, read `group_info`, swap the old status for the new one in `labels`, keep the other labels, and send the whole list with `set_channel_metadata` `metadata.labels`.
35
+
36
+ **Messages.**
37
+ - Send: `send {"line": "…", "text": "Hello"}`. Reply with a quote: `reply {"line": "…", "message_id": "…", "text": "…"}`.
38
+ - React: `react {"line": "…", "message_id": "…", "emoji": "👍"}`. `unreact` takes the same shape.
39
+ - Delete one of your own messages: `delete {"line": "…", "message_id": "…"}`. XMTP has no edit and no typing.
40
+ - History: `read {"line": "…", "limit": 20}`.
41
+ - Poll: `ask {"line": "…", "question": "Ship today?", "options": ["Yes", "No"]}`.
42
+ - File: `create_upload {"name": "report.pdf"}`, run the `curl` line it returns in a shell, then `send {"line": "…", "attachments": [{"upload": "<upload_id>"}]}`. Files that are not images are refused over about 190 KiB.
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from 'node:fs';
3
+ import { policyVerdict } from './policy.mjs';
4
+
5
+ const BLOCKING = new Set(['AskUserQuestion', 'ExitPlanMode', 'EnterPlanMode']);
6
+ const ORCHESTRATION = new Set([
7
+ 'Agent',
8
+ 'Workflow',
9
+ 'ToolSearch',
10
+ 'Skill',
11
+ 'ScheduleWakeup',
12
+ 'Monitor',
13
+ 'CronCreate',
14
+ 'CronList',
15
+ 'CronDelete',
16
+ 'TaskCreate',
17
+ 'TaskGet',
18
+ 'TaskList',
19
+ 'TaskOutput',
20
+ 'TaskStop',
21
+ 'TaskUpdate',
22
+ ]);
23
+ const IMAGE = /\.(png|jpe?g|gif|webp|bmp)$/i;
24
+ const MCP = /^mcp__/;
25
+ const METRO_MCP = /^mcp__metro__/;
26
+
27
+ function answer(decision, reason) {
28
+ process.stdout.write(
29
+ `${JSON.stringify({ hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: decision, permissionDecisionReason: reason } })}\n`,
30
+ );
31
+ }
32
+
33
+ function ownerPolicy(tool, input, subagent) {
34
+ const verdict = policyVerdict(tool, input);
35
+ if (verdict === null) return null;
36
+ const { where } = verdict;
37
+ if (verdict.access === 'deny') return { decision: 'deny', reason: `Blocked by the owner's policy for ${verdict.owner} (${verdict.tool}).` };
38
+ if (subagent) return { decision: 'ask', reason: `The owner asked to approve ${where}.` };
39
+ return {
40
+ decision: 'deny',
41
+ reason: `${where} needs the owner's approval, and waiting for it here would stop the whole session. Run this exact call from a background worker (Agent, run_in_background: true): the worker waits for the owner's answer while you keep answering.`,
42
+ };
43
+ }
44
+
45
+ function verdict(payload, input) {
46
+ const tool = typeof payload.tool_name === 'string' ? payload.tool_name : '';
47
+ if (BLOCKING.has(tool))
48
+ return `${tool} blocks the session waiting on the terminal, and nobody is watching it. Decide with your best judgement and state the assumption, or ask over chat with the metro tools and keep working in the meantime.`;
49
+ if (typeof payload.agent_id === 'string' && payload.agent_id !== '') return null;
50
+ if (tool === 'Agent' && input.run_in_background === false)
51
+ return 'A foreground subagent blinds the main thread: it cannot see or acknowledge inbound metro messages until the agent finishes. Re-issue the identical Agent call with run_in_background: true, then wait for the task notification.';
52
+ if (ORCHESTRATION.has(tool)) return null;
53
+ if (METRO_MCP.test(tool)) return null;
54
+ if (MCP.test(tool))
55
+ return `A connector call is work, not orchestration: ${tool} reads somebody's files, mail or records, and its answer can be long enough to crowd out the chat you are here to follow. Only metro's own tools run on this thread. Delegate it to a subagent with the Agent tool (run_in_background: true; the worker reaches every connector) and relay what it finds.`;
56
+ if (tool === 'Read' && typeof input.file_path === 'string' && IMAGE.test(input.file_path)) return null;
57
+ return `The main thread is orchestrator-only, so ${tool === '' ? 'this tool' : tool} is not available here. Delegate the work to a subagent with the Agent tool (run_in_background: true; the worker agent has full tool access) or to a Workflow, and report the result over metro.`;
58
+ }
59
+
60
+ let payload = {};
61
+ try {
62
+ payload = JSON.parse(readFileSync(0, 'utf8'));
63
+ } catch {
64
+ payload = {};
65
+ }
66
+ const shaped = payload !== null && typeof payload === 'object' ? payload : {};
67
+ const input = shaped.tool_input !== null && typeof shaped.tool_input === 'object' ? shaped.tool_input : {};
68
+ const reason = verdict(shaped, input);
69
+ const policy = reason === null && typeof shaped.tool_name === 'string' ? ownerPolicy(shaped.tool_name, input, typeof shaped.agent_id === 'string' && shaped.agent_id !== '') : null;
70
+ if (reason !== null) answer('deny', reason);
71
+ else if (policy !== null) answer(policy.decision, policy.reason);
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { join } from 'node:path';
5
+
6
+ const agentsDir = () => process.env.METRO_AGENTS_DIR || join(homedir(), '.metro', 'agents');
7
+
8
+ function readAgent() {
9
+ const path = join(agentsDir(), 'agent.json');
10
+ let parsed;
11
+ try {
12
+ parsed = JSON.parse(readFileSync(path, 'utf8'));
13
+ } catch {
14
+ throw new Error(`no agent on this machine yet (${path})`);
15
+ }
16
+ if (typeof parsed?.key !== 'string') throw new Error(`no agent key in ${path}`);
17
+ return parsed;
18
+ }
19
+
20
+ if (process.argv[2] !== 'headers') {
21
+ process.stderr.write('usage: metro-plugin.mjs headers\n');
22
+ process.exit(1);
23
+ }
24
+
25
+ try {
26
+ process.stdout.write(`${JSON.stringify({ Authorization: `Bearer ${readAgent().key}` })}\n`);
27
+ } catch (err) {
28
+ process.stderr.write(`metro: ${err.message}\n`);
29
+ process.stdout.write('{}\n');
30
+ }
@@ -0,0 +1,97 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+
5
+ const METRO_TOOL = /^mcp__metro__(.+)$/;
6
+ const RANK = { allow: 0, ask: 1, deny: 2 };
7
+ const LINE_FIELD = { get_profile: 'from' };
8
+ const STATION_ARG = new Set(['create_group', 'set_profile']);
9
+
10
+ const isRecord = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
11
+ const text = (v) => (typeof v === 'string' ? v : '');
12
+ const agentsDir = () => process.env.METRO_AGENTS_DIR?.trim() || join(homedir(), '.metro', 'agents');
13
+
14
+ function readSnapshot() {
15
+ try {
16
+ const parsed = JSON.parse(readFileSync(join(agentsDir(), 'policy.json'), 'utf8'));
17
+ return isRecord(parsed) && parsed.version === 1 ? parsed : null;
18
+ } catch {
19
+ return null;
20
+ }
21
+ }
22
+
23
+ const fromLine = (line, override) => {
24
+ const parts = line.split('/');
25
+ return line.startsWith('metro://') && parts[2] && parts[3] ? [{ station: parts[2], account: override || parts[3] }] : [];
26
+ };
27
+
28
+ function stationOfAccount(snap, account) {
29
+ const hits = Object.entries(isRecord(snap.stations) ? snap.stations : {}).filter(
30
+ ([, ids]) => Array.isArray(ids) && ids.includes(account),
31
+ );
32
+ return hits.length === 1 ? hits[0][0] : undefined;
33
+ }
34
+
35
+ function targets(snap, name, input) {
36
+ if (Array.isArray(snap.ungated) && snap.ungated.includes(name)) return [];
37
+ const account = text(input.account);
38
+ const line = text(input[LINE_FIELD[name] ?? 'line']);
39
+ if (line) return fromLine(line, name in LINE_FIELD ? '' : account);
40
+ const owners = isRecord(snap.owners) ? snap.owners : {};
41
+ const station = (STATION_ARG.has(name) ? text(input.station) : text(owners[name])) || (account ? stationOfAccount(snap, account) : undefined);
42
+ if (!station) return [];
43
+ if (account) return [{ station, account }];
44
+ const ids = isRecord(snap.stations) && Array.isArray(snap.stations[station]) ? snap.stations[station] : [];
45
+ return ids.map((id) => ({ station, account: id }));
46
+ }
47
+
48
+ function decide(policy, name, group) {
49
+ if (!isRecord(policy)) return 'allow';
50
+ const byTool = isRecord(policy.tools) ? policy.tools[name] : undefined;
51
+ const access = byTool ?? policy[group] ?? 'allow';
52
+ return access in RANK ? access : 'allow';
53
+ }
54
+
55
+ const normalized = (name) => name.replace(/[^a-zA-Z0-9_-]/g, '_');
56
+
57
+ function connectorCall(snap, toolName) {
58
+ for (const [server, entry] of Object.entries(isRecord(snap.connectors) ? snap.connectors : {})) {
59
+ if (!isRecord(entry)) continue;
60
+ const name = text(entry.name);
61
+ const prefixes = [`mcp__plugin_metro_${server}__`, `mcp__${server}__`, `mcp__${normalized(`metro.box ${name}`)}__`];
62
+ const prefix = prefixes.find((p) => toolName.startsWith(p) && toolName.length > p.length);
63
+ if (prefix === undefined) continue;
64
+ const called = toolName.slice(prefix.length);
65
+ const tools = isRecord(entry.tools) ? entry.tools : {};
66
+ const policy = isRecord(entry.policy) ? entry.policy : {};
67
+ const known = [...Object.keys(tools), ...Object.keys(isRecord(policy.tools) ? policy.tools : {})];
68
+ const tool = known.find((k) => k === called) ?? known.find((k) => normalized(k) === called) ?? called;
69
+ return { name: name || server, tool, group: tools[tool] === 'read' ? 'read' : 'write', policy };
70
+ }
71
+ return null;
72
+ }
73
+
74
+ function connectorVerdict(snap, toolName) {
75
+ const call = connectorCall(snap, toolName);
76
+ if (call === null) return null;
77
+ const access = decide(call.policy, call.tool, call.group);
78
+ return access === 'allow' ? null : { access, tool: call.tool, owner: call.name, where: `${call.tool} on ${call.name}` };
79
+ }
80
+
81
+ export function policyVerdict(toolName, input) {
82
+ const name = METRO_TOOL.exec(toolName)?.[1];
83
+ if (name === undefined && !toolName.startsWith('mcp__')) return null;
84
+ const snap = readSnapshot();
85
+ if (snap === null) return null;
86
+ if (name === undefined) return connectorVerdict(snap, toolName);
87
+ const tools = isRecord(snap.tools) ? snap.tools : {};
88
+ const group = tools[name] === 'read' ? 'read' : 'write';
89
+ const accounts = isRecord(snap.accounts) ? snap.accounts : {};
90
+ let verdict = null;
91
+ for (const target of targets(snap, name, input)) {
92
+ const access = decide(accounts[`${target.station}/${target.account}`], name, group);
93
+ if (access !== 'allow' && (verdict === null || RANK[access] > RANK[verdict.access]))
94
+ verdict = { access, tool: name, owner: target.station, where: `${name} on ${target.station} (${target.account})` };
95
+ }
96
+ return verdict;
97
+ }
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, readFileSync } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { dirname, join } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const given = (value) => (typeof value === 'string' && value.trim() !== '' ? value.trim() : undefined);
8
+ const claudeDir = given(process.env.CLAUDE_CONFIG_DIR) ?? join(given(process.env.HOME) ?? homedir(), '.claude');
9
+ const SKILL = join(claudeDir, 'skills', 'metro', 'SKILL.md');
10
+ const FALLBACK = join(dirname(dirname(fileURLToPath(import.meta.url))), 'METRO.md');
11
+
12
+ const body = (text) => text.replace(/^---[\s\S]*?\n---\n/, '').trim();
13
+
14
+ function guidance() {
15
+ for (const path of [SKILL, FALLBACK]) {
16
+ if (!existsSync(path)) continue;
17
+ try {
18
+ const text = body(readFileSync(path, 'utf8'));
19
+ if (text !== '') return text;
20
+ } catch {
21
+ continue;
22
+ }
23
+ }
24
+ return '';
25
+ }
26
+
27
+ const text = guidance();
28
+ if (text !== '')
29
+ process.stdout.write(
30
+ `${JSON.stringify({ hookSpecificOutput: { hookEventName: 'SessionStart', additionalContext: `This machine runs as a metro agent. Standing rules, kept in the metro skill:\n\n${text}` } })}\n`,
31
+ );
@@ -0,0 +1,25 @@
1
+ {
2
+ "hooks": {
3
+ "PreToolUse": [
4
+ {
5
+ "hooks": [
6
+ {
7
+ "type": "command",
8
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/bin/guard.mjs\"",
9
+ "statusMessage": "Checking the orchestrator boundary"
10
+ }
11
+ ]
12
+ }
13
+ ],
14
+ "SessionStart": [
15
+ {
16
+ "hooks": [
17
+ {
18
+ "type": "command",
19
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/bin/session-start.mjs\""
20
+ }
21
+ ]
22
+ }
23
+ ]
24
+ }
25
+ }
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@metro-labs/core",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "description": "What every metro process shares: the logger, the event bus and its types, ids, secure file writes, the train protocol, station types and attachment handling. No HTTP, no policy.",
6
+ "type": "module",
7
+ "exports": {
8
+ "./log": "./src/log.ts",
9
+ "./events": "./src/events.ts",
10
+ "./is-record": "./src/is-record.ts",
11
+ "./secure-fs": "./src/secure-fs.ts",
12
+ "./version": "./src/version.ts",
13
+ "./train-error": "./src/train-error.ts",
14
+ "./trains/protocol": "./src/protocol.ts",
15
+ "./ids": "./src/ids.ts",
16
+ "./tickets": "./src/tickets.ts",
17
+ "./station-names": "./src/station-names.ts",
18
+ "./str": "./src/str.ts",
19
+ "./lines": "./src/lines.ts",
20
+ "./endpoints": "./src/endpoints.ts",
21
+ "./stations/types": "./src/stations/types.ts",
22
+ "./stations/account-files": "./src/stations/account-files.ts",
23
+ "./stations/station-runtime": "./src/stations/station-runtime.ts",
24
+ "./stations/account-store": "./src/stations/account-store.ts",
25
+ "./stations/attachments": "./src/stations/attachments.ts",
26
+ "./stations/mail": "./src/stations/mail.ts",
27
+ "./stations/mail-text": "./src/stations/mail-text.ts",
28
+ "./stations/mail-trust": "./src/stations/mail-trust.ts",
29
+ "./stations/oauth": "./src/stations/oauth.ts",
30
+ "./stations/messaging-normalize": "./src/stations/messaging-normalize.ts",
31
+ "./stations/profile": "./src/stations/profile.ts",
32
+ "./stations/sender-profile": "./src/stations/sender-profile.ts",
33
+ "./stations/train-events": "./src/stations/train-events.ts",
34
+ "./stations/train-boot": "./src/stations/train-boot.ts"
35
+ },
36
+ "scripts": {
37
+ "build": "tsc",
38
+ "test": "tsc --noEmit && METRO_STATE_DIR=\"$(mktemp -d /tmp/metro-test.XXXXXX)\" bun test test/"
39
+ },
40
+ "dependencies": {
41
+ "pino": "^9.5.0",
42
+ "pino-pretty": "^13.1.3"
43
+ },
44
+ "devDependencies": {
45
+ "@stage-labs/config": "0.1.0-beta.2",
46
+ "eslint": "^10.3.0",
47
+ "knip": "^6.15.0",
48
+ "madge": "^8.0.0",
49
+ "typescript": "^5"
50
+ }
51
+ }
@@ -0,0 +1,7 @@
1
+ export interface Endpoint {
2
+ id: string;
3
+ webhookId?: string;
4
+ label: string;
5
+ secret?: string;
6
+ createdAt: string;
7
+ }
@@ -1,7 +1,8 @@
1
- import { randomBytes } from 'node:crypto';
2
- import { Line } from '../stations/lines.js';
1
+ import { Line } from './lines.js';
2
+ import { errMsg, log } from './log.js';
3
3
 
4
- export { userSelf, daemonSelf, selfLine } from './identity.js';
4
+ export const userSelf = (): Line =>
5
+ (process.env.METRO_FROM ?? 'metro://user') as Line;
5
6
 
6
7
  export type StructuredEvent =
7
8
  | { type: 'msg' }
@@ -24,6 +25,10 @@ export interface MetroEvent {
24
25
  text?: string;
25
26
  messageId?: string;
26
27
  replyTo?: string;
28
+ isPrivate?: boolean;
29
+ mentionsSelf?: boolean;
30
+ replyToSelf?: boolean;
31
+ senderVerified?: boolean;
27
32
  payload?: unknown;
28
33
  display?: string;
29
34
  event?: StructuredEvent;
@@ -71,8 +76,7 @@ export function formatDisplay(e: MetroEvent): string {
71
76
  return `${headerFor('📩', [e.station, e.fromName ?? e.from, e.lineName])}\n> ${body}`;
72
77
  }
73
78
 
74
- export const mintId = (): string =>
75
- `msg_${randomBytes(6).toString('base64url')}`;
79
+ export { mintId } from './ids.js';
76
80
 
77
81
  export type BusListener = (event: MetroEvent, busSeq: number) => void;
78
82
 
@@ -81,7 +85,7 @@ export interface BufferedEvent {
81
85
  event: MetroEvent;
82
86
  }
83
87
 
84
- export const BUS_BUFFER_MAX = 500;
88
+ const BUS_BUFFER_MAX = 500;
85
89
 
86
90
  const listeners = new Set<BusListener>();
87
91
  const buffer: BufferedEvent[] = [];
@@ -96,7 +100,7 @@ export function publishEvent(event: MetroEvent): void {
96
100
  try {
97
101
  fn(event, seq);
98
102
  } catch (err) {
99
- console.error('[metro-bus] listener threw for busSeq', seq, err);
103
+ log.error({ busSeq: seq, err: errMsg(err) }, 'bus: a listener threw');
100
104
  }
101
105
  }
102
106
  }