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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (442) hide show
  1. package/dist/api.js +9 -101
  2. package/dist/claude-settings.js +40 -0
  3. package/dist/claude.js +163 -0
  4. package/dist/cli.js +50 -109
  5. package/dist/control.js +47 -75
  6. package/dist/hold.js +211 -0
  7. package/dist/local.js +43 -0
  8. package/dist/mcp-config.js +25 -0
  9. package/dist/node-name.js +71 -0
  10. package/dist/onboarding.js +44 -0
  11. package/dist/provider-flags.js +9 -0
  12. package/dist/route.js +58 -0
  13. package/dist/runtime-install.js +97 -0
  14. package/dist/runtime.js +32 -52
  15. package/dist/serve.js +158 -0
  16. package/dist/service.js +243 -0
  17. package/dist/tail.js +119 -0
  18. package/dist/update.js +13 -1
  19. package/package.json +1 -22
  20. package/runtime/marketplace/.claude-plugin/marketplace.json +12 -0
  21. package/runtime/marketplace/plugin/.claude-plugin/plugin.json +17 -0
  22. package/runtime/marketplace/plugin/.mcp.json +1 -0
  23. package/runtime/marketplace/plugin/bin/guard.mjs +71 -0
  24. package/runtime/marketplace/plugin/bin/metro-plugin.mjs +30 -0
  25. package/runtime/marketplace/plugin/bin/policy.mjs +97 -0
  26. package/runtime/marketplace/plugin/bin/session-start.mjs +31 -0
  27. package/runtime/marketplace/plugin/hooks/hooks.json +25 -0
  28. package/runtime/marketplace/plugin/orchestrator.md +24 -0
  29. package/runtime/node_modules/@metro-labs/core/package.json +47 -0
  30. package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
  31. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/events.ts +8 -6
  32. package/runtime/node_modules/@metro-labs/core/src/identity.ts +7 -0
  33. package/runtime/node_modules/@metro-labs/{mcp/src/db → core/src}/ids.ts +5 -0
  34. package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
  35. package/runtime/node_modules/@metro-labs/{mcp/src/stations → core/src}/lines.ts +12 -3
  36. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/protocol.ts +7 -4
  37. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/secure-fs.ts +17 -0
  38. package/runtime/node_modules/@metro-labs/core/src/station-names.ts +13 -0
  39. package/runtime/node_modules/@metro-labs/core/src/stations/account-files.ts +41 -0
  40. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/account-store.ts +4 -24
  41. package/runtime/node_modules/@metro-labs/core/src/stations/profile.ts +58 -0
  42. package/runtime/node_modules/@metro-labs/core/src/stations/sender-profile.ts +64 -0
  43. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/station-runtime.ts +3 -6
  44. package/runtime/node_modules/@metro-labs/core/src/stations/train-boot.ts +42 -0
  45. package/runtime/node_modules/@metro-labs/core/src/stations/train-events.ts +89 -0
  46. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/types.ts +16 -0
  47. package/runtime/node_modules/@metro-labs/core/src/tickets.ts +37 -0
  48. package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
  49. package/runtime/node_modules/@metro-labs/daemon/package.json +48 -0
  50. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/agent-fs.ts +134 -0
  51. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files-api.ts +12 -0
  52. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files.ts +119 -0
  53. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/home-fs.ts +113 -0
  54. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/job-env.ts +51 -0
  55. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/provision.ts +99 -0
  56. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedule-detail.ts +100 -0
  57. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules-api.ts +27 -0
  58. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules.ts +252 -0
  59. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/unit-files.ts +61 -0
  60. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/user.ts +91 -0
  61. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/view.ts +87 -0
  62. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-attach.ts +19 -0
  63. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-lookups.ts +55 -0
  64. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-routes.ts +76 -0
  65. package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +357 -0
  66. package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +30 -0
  67. package/runtime/node_modules/@metro-labs/daemon/src/agents/allowlist.ts +59 -0
  68. package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +131 -0
  69. package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +132 -0
  70. package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +305 -0
  71. package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +168 -0
  72. package/runtime/node_modules/@metro-labs/{mcp/src/db/key-map.ts → daemon/src/agents/keys.ts} +1 -11
  73. package/runtime/node_modules/@metro-labs/{mcp/src/db/agent-map.ts → daemon/src/agents/map.ts} +58 -1
  74. package/runtime/node_modules/@metro-labs/daemon/src/agents/policy-route.ts +27 -0
  75. package/runtime/node_modules/@metro-labs/{mcp/src/db/agent-scope.ts → daemon/src/agents/scope.ts} +2 -2
  76. package/runtime/node_modules/@metro-labs/daemon/src/agents/sender-cards.ts +86 -0
  77. package/runtime/node_modules/@metro-labs/daemon/src/agents/senders.ts +38 -0
  78. package/runtime/node_modules/@metro-labs/daemon/src/approvals/api.ts +55 -0
  79. package/runtime/node_modules/@metro-labs/daemon/src/approvals/needs.ts +2 -0
  80. package/runtime/node_modules/@metro-labs/daemon/src/approvals/pending.ts +149 -0
  81. package/runtime/node_modules/@metro-labs/daemon/src/approvals/preview.ts +66 -0
  82. package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +221 -0
  83. package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +39 -0
  84. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/crash-guard.ts +1 -1
  85. package/runtime/node_modules/@metro-labs/daemon/src/boot/local-owner.ts +21 -0
  86. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/paths.ts +6 -34
  87. package/runtime/node_modules/@metro-labs/daemon/src/channels/addressed.ts +26 -0
  88. package/runtime/node_modules/@metro-labs/daemon/src/channels/dedupe.ts +12 -0
  89. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/inbound.ts +47 -44
  90. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/media-note.ts +9 -4
  91. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/pending.ts +4 -1
  92. package/runtime/node_modules/@metro-labs/daemon/src/channels/react-note.ts +13 -0
  93. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/relay.ts +2 -2
  94. package/runtime/node_modules/@metro-labs/daemon/src/channels/reply-id.ts +1 -0
  95. package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +355 -0
  96. package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +359 -0
  97. package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +208 -0
  98. package/runtime/node_modules/@metro-labs/daemon/src/claude/memory.ts +82 -0
  99. package/runtime/node_modules/@metro-labs/daemon/src/claude/onboarding.ts +60 -0
  100. package/runtime/node_modules/@metro-labs/daemon/src/claude/plugin-install.ts +149 -0
  101. package/runtime/node_modules/@metro-labs/daemon/src/claude/session-files.ts +75 -0
  102. package/runtime/node_modules/@metro-labs/daemon/src/claude/session.ts +283 -0
  103. package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +109 -0
  104. package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +271 -0
  105. package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +120 -0
  106. package/runtime/node_modules/@metro-labs/daemon/src/claude/version.ts +113 -0
  107. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-api.ts → daemon/src/connectors/api.ts} +77 -109
  108. package/runtime/node_modules/@metro-labs/{mcp/src/db/connector-config.ts → daemon/src/connectors/config.ts} +55 -26
  109. package/runtime/node_modules/@metro-labs/daemon/src/connectors/gates.ts +72 -0
  110. package/runtime/node_modules/@metro-labs/daemon/src/connectors/health.ts +18 -0
  111. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-client.ts +14 -17
  112. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-discovery.ts +28 -13
  113. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth-routes.ts → daemon/src/connectors/oauth-routes.ts} +30 -29
  114. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth.ts → daemon/src/connectors/oauth.ts} +61 -22
  115. package/runtime/node_modules/@metro-labs/daemon/src/connectors/plugin-sync.ts +131 -0
  116. package/runtime/node_modules/@metro-labs/daemon/src/connectors/reach.ts +27 -0
  117. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-policy.ts +90 -0
  118. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-target.ts +29 -0
  119. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +348 -0
  120. package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +358 -0
  121. package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +81 -0
  122. package/runtime/node_modules/@metro-labs/daemon/src/connectors/url.ts +37 -0
  123. package/runtime/node_modules/@metro-labs/daemon/src/connectors/verify.ts +106 -0
  124. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-grant.ts +4 -4
  125. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-owner.ts +3 -3
  126. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-reaper.ts +174 -0
  127. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-serve.ts +11 -12
  128. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-api.ts +10 -27
  129. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-store.ts +2 -2
  130. package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +233 -0
  131. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +208 -0
  132. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-device.ts +91 -0
  133. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +173 -0
  134. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +194 -0
  135. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +137 -0
  136. package/runtime/node_modules/@metro-labs/daemon/src/gateway/effort.ts +77 -0
  137. package/runtime/node_modules/@metro-labs/daemon/src/gateway/eventstream.ts +123 -0
  138. package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +237 -0
  139. package/runtime/node_modules/@metro-labs/daemon/src/gateway/frames.ts +118 -0
  140. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +274 -0
  141. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-auth.ts +160 -0
  142. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-client.ts +46 -0
  143. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-setup.ts +150 -0
  144. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-stream.ts +139 -0
  145. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-translate.ts +223 -0
  146. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini.ts +208 -0
  147. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +199 -0
  148. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +299 -0
  149. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-signin.ts +193 -0
  150. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-store.ts +70 -0
  151. package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +90 -0
  152. package/runtime/node_modules/@metro-labs/daemon/src/gateway/pkce.ts +36 -0
  153. package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +66 -0
  154. package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +18 -0
  155. package/runtime/node_modules/@metro-labs/daemon/src/gateway/subscription.ts +120 -0
  156. package/runtime/node_modules/@metro-labs/daemon/src/gateway/text.ts +15 -0
  157. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +244 -0
  158. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/accounts.ts +59 -18
  159. package/runtime/node_modules/@metro-labs/daemon/src/mcp/attachment-schema.ts +91 -0
  160. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/call-tools.ts +43 -20
  161. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/ctx.ts +4 -4
  162. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/event-store.ts +15 -16
  163. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/group-tools.ts +2 -2
  164. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/index.ts +24 -79
  165. package/runtime/node_modules/@metro-labs/daemon/src/mcp/instructions.ts +19 -0
  166. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/member-tools.ts +2 -2
  167. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-prompt.ts +87 -0
  168. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +79 -0
  169. package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-gate.ts +83 -0
  170. package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-snapshot.ts +79 -0
  171. package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-lookup.ts +60 -0
  172. package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-tool.ts +96 -0
  173. package/runtime/node_modules/@metro-labs/daemon/src/mcp/read-tool.ts +87 -0
  174. package/runtime/node_modules/@metro-labs/daemon/src/mcp/request-identity.ts +46 -0
  175. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-slot.ts +48 -0
  176. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/session.ts +33 -42
  177. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-catalog.ts +88 -0
  178. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-def.ts +9 -0
  179. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-dispatch.ts +53 -40
  180. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-schemas.ts +55 -119
  181. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/upload-tool.ts +6 -11
  182. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/api.ts +43 -0
  183. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/helper-script.ts +126 -0
  184. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/move.ts +165 -0
  185. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/privilege.ts +48 -0
  186. package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +132 -0
  187. package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +316 -0
  188. package/runtime/node_modules/@metro-labs/daemon/src/policy/policy.ts +118 -0
  189. package/runtime/node_modules/@metro-labs/daemon/src/routes/bearer.ts +35 -0
  190. package/runtime/node_modules/@metro-labs/daemon/src/routes/body.ts +24 -0
  191. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/routes}/http.ts +59 -51
  192. package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +208 -0
  193. package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +71 -0
  194. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/session-api.ts → daemon/src/routes/session.ts} +9 -7
  195. package/runtime/node_modules/@metro-labs/daemon/src/routes/threema-callback.ts +103 -0
  196. package/runtime/node_modules/@metro-labs/daemon/src/server/control.ts +39 -0
  197. package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +58 -0
  198. package/runtime/node_modules/@metro-labs/daemon/src/server/owner.ts +26 -0
  199. package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +90 -0
  200. package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
  201. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-driver.ts +42 -0
  202. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-inline.ts +29 -1
  203. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-interactive.ts +9 -36
  204. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-outlook.ts +63 -0
  205. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-resolve.ts +38 -13
  206. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/attach-session.ts +30 -20
  207. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-xmtp.ts +2 -2
  208. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach.ts +75 -9
  209. package/runtime/node_modules/@metro-labs/daemon/src/stations/materialize.ts +265 -0
  210. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/registry.ts +22 -6
  211. package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +82 -0
  212. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor-io.ts +2 -2
  213. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor.ts +5 -8
  214. package/runtime/node_modules/@metro-labs/daemon/src/stations/threema-callbacks.ts +32 -0
  215. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/train-call.ts +1 -1
  216. package/runtime/node_modules/@metro-labs/daemon/src/stations/webhook-endpoints.ts +51 -0
  217. package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +84 -0
  218. package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +124 -0
  219. package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +15 -0
  220. package/runtime/node_modules/@metro-labs/daemon/src/vault/api.ts +45 -0
  221. package/runtime/node_modules/@metro-labs/daemon/src/vault/config.ts +51 -0
  222. package/runtime/node_modules/@metro-labs/daemon/src/vault/firewall.ts +48 -0
  223. package/runtime/node_modules/@metro-labs/daemon/src/vault/index.ts +96 -0
  224. package/runtime/node_modules/@metro-labs/daemon/src/vault/install.ts +56 -0
  225. package/runtime/node_modules/@metro-labs/daemon/src/vault/paths.ts +26 -0
  226. package/runtime/node_modules/@metro-labs/daemon/src/vault/proxy.ts +148 -0
  227. package/runtime/node_modules/@metro-labs/daemon/src/vault/store.ts +130 -0
  228. package/runtime/node_modules/@metro-labs/daemon/src/vault/trust.ts +61 -0
  229. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/package.json +3 -5
  230. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/accounts.ts +11 -13
  231. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/actions.ts +6 -154
  232. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/attachments.ts +3 -3
  233. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/format.ts +28 -64
  234. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/group-actions.ts +1 -1
  235. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/group.ts +2 -2
  236. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/index.ts +14 -19
  237. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/members.ts +2 -2
  238. package/runtime/node_modules/@metro-labs/discord-bot/src/profile.ts +68 -0
  239. package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/send-files.ts +1 -1
  240. package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +22 -0
  241. package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +1 -0
  242. package/runtime/node_modules/@metro-labs/http/package.json +29 -0
  243. package/runtime/node_modules/@metro-labs/http/src/api-http.ts +138 -0
  244. package/runtime/node_modules/@metro-labs/http/src/mode-api.ts +32 -0
  245. package/runtime/node_modules/@metro-labs/http/src/return-to.ts +21 -0
  246. package/runtime/node_modules/@metro-labs/http/src/workos-token.ts +149 -0
  247. package/runtime/node_modules/@metro-labs/{telegram-user → outlook}/package.json +2 -5
  248. package/runtime/node_modules/@metro-labs/outlook/src/accounts.ts +107 -0
  249. package/runtime/node_modules/@metro-labs/outlook/src/actions.ts +20 -0
  250. package/runtime/node_modules/@metro-labs/outlook/src/attachments.ts +97 -0
  251. package/runtime/node_modules/@metro-labs/outlook/src/auth.ts +150 -0
  252. package/runtime/node_modules/@metro-labs/outlook/src/browser.ts +53 -0
  253. package/runtime/node_modules/@metro-labs/outlook/src/config.ts +36 -0
  254. package/runtime/node_modules/@metro-labs/outlook/src/format.ts +141 -0
  255. package/runtime/node_modules/@metro-labs/outlook/src/graph.ts +60 -0
  256. package/runtime/node_modules/@metro-labs/outlook/src/html.ts +72 -0
  257. package/runtime/node_modules/@metro-labs/outlook/src/inbound.ts +104 -0
  258. package/runtime/node_modules/@metro-labs/outlook/src/index.ts +12 -0
  259. package/runtime/node_modules/@metro-labs/outlook/src/login.ts +150 -0
  260. package/runtime/node_modules/@metro-labs/outlook/src/me.ts +41 -0
  261. package/runtime/node_modules/@metro-labs/outlook/src/outbound.ts +116 -0
  262. package/runtime/node_modules/@metro-labs/outlook/src/query.ts +119 -0
  263. package/runtime/node_modules/@metro-labs/outlook/src/state.ts +43 -0
  264. package/runtime/node_modules/@metro-labs/outlook/src/station.ts +15 -0
  265. package/runtime/node_modules/@metro-labs/outlook/src/trust.ts +70 -0
  266. package/runtime/node_modules/@metro-labs/telegram/package.json +3 -2
  267. package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +48 -88
  268. package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +214 -253
  269. package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +67 -108
  270. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/client.ts +6 -6
  271. package/runtime/node_modules/@metro-labs/telegram/src/format.ts +102 -146
  272. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/group.ts +4 -4
  273. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/history.ts +1 -1
  274. package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +57 -0
  275. package/runtime/node_modules/@metro-labs/telegram/src/index.ts +6 -102
  276. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/login.ts +20 -20
  277. package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +65 -151
  278. package/runtime/node_modules/@metro-labs/telegram/src/members.ts +61 -33
  279. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/normalize.ts +1 -1
  280. package/runtime/node_modules/@metro-labs/telegram/src/profile.ts +70 -0
  281. package/runtime/node_modules/@metro-labs/{telegram-user → telegram}/src/reactions.ts +2 -2
  282. package/runtime/node_modules/@metro-labs/telegram/src/station.ts +11 -1
  283. package/runtime/node_modules/@metro-labs/telegram/src/types.ts +5 -47
  284. package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +1 -3
  285. package/runtime/node_modules/@metro-labs/telegram-bot/package.json +25 -0
  286. package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +119 -0
  287. package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +246 -0
  288. package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +128 -0
  289. package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +173 -0
  290. package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +103 -0
  291. package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +95 -0
  292. package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +47 -0
  293. package/runtime/node_modules/@metro-labs/telegram-bot/src/profile.ts +65 -0
  294. package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +20 -0
  295. package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +56 -0
  296. package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +1 -0
  297. package/runtime/node_modules/@metro-labs/threema/package.json +26 -0
  298. package/runtime/node_modules/@metro-labs/threema/src/accounts.ts +106 -0
  299. package/runtime/node_modules/@metro-labs/threema/src/actions.ts +134 -0
  300. package/runtime/node_modules/@metro-labs/threema/src/api.ts +152 -0
  301. package/runtime/node_modules/@metro-labs/threema/src/crypto.ts +100 -0
  302. package/runtime/node_modules/@metro-labs/threema/src/files.ts +58 -0
  303. package/runtime/node_modules/@metro-labs/threema/src/format.ts +169 -0
  304. package/runtime/node_modules/@metro-labs/threema/src/groups.ts +96 -0
  305. package/runtime/node_modules/@metro-labs/threema/src/ids.ts +21 -0
  306. package/runtime/node_modules/@metro-labs/threema/src/inbound.ts +89 -0
  307. package/runtime/node_modules/@metro-labs/threema/src/index.ts +24 -0
  308. package/runtime/node_modules/@metro-labs/threema/src/messages.ts +264 -0
  309. package/runtime/node_modules/@metro-labs/threema/src/outbound.ts +160 -0
  310. package/runtime/node_modules/@metro-labs/threema/src/station.ts +13 -0
  311. package/runtime/node_modules/@metro-labs/threema/src/verify.ts +117 -0
  312. package/runtime/node_modules/@metro-labs/webhook/package.json +1 -1
  313. package/runtime/node_modules/@metro-labs/webhook/src/station.ts +5 -8
  314. package/runtime/node_modules/@metro-labs/whatsapp/package.json +1 -3
  315. package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +1 -2
  316. package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +1 -1
  317. package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +40 -5
  318. package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +2 -2
  319. package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +1 -1
  320. package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +74 -4
  321. package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +7 -56
  322. package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +10 -27
  323. package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +4 -37
  324. package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +1 -1
  325. package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +1 -1
  326. package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +1 -1
  327. package/runtime/node_modules/@metro-labs/whatsapp/src/names.ts +28 -0
  328. package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +1 -1
  329. package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +44 -0
  330. package/runtime/node_modules/@metro-labs/whatsapp/src/resolve.ts +52 -0
  331. package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +8 -1
  332. package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +5 -9
  333. package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +0 -1
  334. package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +1 -5
  335. package/runtime/node_modules/@metro-labs/xmtp/package.json +3 -2
  336. package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +9 -8
  337. package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +1 -1
  338. package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +3 -201
  339. package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +3 -42
  340. package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +12 -143
  341. package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +3 -3
  342. package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +3 -3
  343. package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +7 -24
  344. package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +7 -16
  345. package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +1 -1
  346. package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +2 -2
  347. package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +30 -16
  348. package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +11 -14
  349. package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +1 -19
  350. package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +1 -1
  351. package/runtime/node_modules/@metro-labs/xmtp/src/names.ts +61 -0
  352. package/runtime/node_modules/@metro-labs/xmtp/src/profile.ts +153 -0
  353. package/runtime/node_modules/@metro-labs/xmtp/src/sender.ts +112 -0
  354. package/runtime/node_modules/@metro-labs/xmtp/src/smart.ts +72 -0
  355. package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +5 -1
  356. package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +3 -50
  357. package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +30 -44
  358. package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +4 -6
  359. package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +19 -5
  360. package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +15 -3
  361. package/runtime/runtime.json +1 -1
  362. package/runtime/server.ts +1 -0
  363. package/runtime/stations.json +37 -0
  364. package/dist/prompt.js +0 -10
  365. package/dist/store.js +0 -70
  366. package/runtime/node_modules/@metro-labs/discord/src/station.ts +0 -19
  367. package/runtime/node_modules/@metro-labs/discord/src/voice-speak.ts +0 -195
  368. package/runtime/node_modules/@metro-labs/discord/src/voice-transcribe.ts +0 -292
  369. package/runtime/node_modules/@metro-labs/discord/src/voice.ts +0 -197
  370. package/runtime/node_modules/@metro-labs/discord/src/wire.ts +0 -5
  371. package/runtime/node_modules/@metro-labs/mcp/package.json +0 -66
  372. package/runtime/node_modules/@metro-labs/mcp/src/channels/dedupe.ts +0 -24
  373. package/runtime/node_modules/@metro-labs/mcp/src/daemon/account-api.ts +0 -311
  374. package/runtime/node_modules/@metro-labs/mcp/src/daemon/agent-api.ts +0 -335
  375. package/runtime/node_modules/@metro-labs/mcp/src/daemon/api-http.ts +0 -129
  376. package/runtime/node_modules/@metro-labs/mcp/src/daemon/boot.ts +0 -322
  377. package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair-api.ts +0 -111
  378. package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair.ts +0 -20
  379. package/runtime/node_modules/@metro-labs/mcp/src/daemon/collection-api.ts +0 -202
  380. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-json.ts +0 -31
  381. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-tools.ts +0 -100
  382. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-url.ts +0 -57
  383. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-verify.ts +0 -333
  384. package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-auth.ts +0 -164
  385. package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-oauth.ts +0 -208
  386. package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity.ts +0 -79
  387. package/runtime/node_modules/@metro-labs/mcp/src/daemon/oauth-pending.ts +0 -65
  388. package/runtime/node_modules/@metro-labs/mcp/src/daemon/pair-codes.ts +0 -58
  389. package/runtime/node_modules/@metro-labs/mcp/src/daemon/project-api.ts +0 -214
  390. package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-api.ts +0 -125
  391. package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-pair.ts +0 -18
  392. package/runtime/node_modules/@metro-labs/mcp/src/daemon/runtime-source.ts +0 -105
  393. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session-apis.ts +0 -41
  394. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session.ts +0 -218
  395. package/runtime/node_modules/@metro-labs/mcp/src/daemon/tunnel.ts +0 -169
  396. package/runtime/node_modules/@metro-labs/mcp/src/db/account-attach.ts +0 -91
  397. package/runtime/node_modules/@metro-labs/mcp/src/db/agent-admin.ts +0 -215
  398. package/runtime/node_modules/@metro-labs/mcp/src/db/client.ts +0 -37
  399. package/runtime/node_modules/@metro-labs/mcp/src/db/connector-collections.ts +0 -218
  400. package/runtime/node_modules/@metro-labs/mcp/src/db/connectors.ts +0 -329
  401. package/runtime/node_modules/@metro-labs/mcp/src/db/materialize.ts +0 -340
  402. package/runtime/node_modules/@metro-labs/mcp/src/db/projects.ts +0 -300
  403. package/runtime/node_modules/@metro-labs/mcp/src/db/runtime-admin.ts +0 -28
  404. package/runtime/node_modules/@metro-labs/mcp/src/db/runtimes.ts +0 -105
  405. package/runtime/node_modules/@metro-labs/mcp/src/db/schema.ts +0 -131
  406. package/runtime/node_modules/@metro-labs/mcp/src/db/token-carry.ts +0 -45
  407. package/runtime/node_modules/@metro-labs/mcp/src/db/users.ts +0 -57
  408. package/runtime/node_modules/@metro-labs/mcp/src/db/whatsapp-login.ts +0 -18
  409. package/runtime/node_modules/@metro-labs/mcp/src/mcp/channel-owner.ts +0 -29
  410. package/runtime/node_modules/@metro-labs/mcp/src/mcp/frame-scope.ts +0 -21
  411. package/runtime/node_modules/@metro-labs/mcp/src/mcp/permission-relay.ts +0 -66
  412. package/runtime/node_modules/@metro-labs/mcp/src/mcp/request-identity.ts +0 -73
  413. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-registry.ts +0 -172
  414. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-route.ts +0 -43
  415. package/runtime/node_modules/@metro-labs/mcp/src/monitor/api.ts +0 -240
  416. package/runtime/node_modules/@metro-labs/mcp/src/server.ts +0 -2
  417. package/runtime/node_modules/@metro-labs/telegram-user/src/accounts.ts +0 -81
  418. package/runtime/node_modules/@metro-labs/telegram-user/src/actions.ts +0 -254
  419. package/runtime/node_modules/@metro-labs/telegram-user/src/attachments.ts +0 -87
  420. package/runtime/node_modules/@metro-labs/telegram-user/src/format.ts +0 -141
  421. package/runtime/node_modules/@metro-labs/telegram-user/src/inbound.ts +0 -78
  422. package/runtime/node_modules/@metro-labs/telegram-user/src/index.ts +0 -46
  423. package/runtime/node_modules/@metro-labs/telegram-user/src/media-actions.ts +0 -80
  424. package/runtime/node_modules/@metro-labs/telegram-user/src/members.ts +0 -75
  425. package/runtime/node_modules/@metro-labs/telegram-user/src/station.ts +0 -24
  426. package/runtime/node_modules/@metro-labs/telegram-user/src/types.ts +0 -7
  427. package/runtime/node_modules/@metro-labs/telegram-user/src/wire.ts +0 -1
  428. package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +0 -87
  429. package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +0 -55
  430. package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +0 -349
  431. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/log.ts +0 -0
  432. /package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/attachments.ts +0 -0
  433. /package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/messaging-normalize.ts +0 -0
  434. /package/runtime/node_modules/@metro-labs/{mcp/src/mcp → core/src}/str.ts +0 -0
  435. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/train-error.ts +0 -0
  436. /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/webhook-note.ts +0 -0
  437. /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/raw-get-stream.ts +0 -0
  438. /package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/api-base.ts +0 -0
  439. /package/runtime/node_modules/@metro-labs/{discord → discord-bot}/src/verify.ts +0 -0
  440. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/api-error.ts +0 -0
  441. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/cors.ts +0 -0
  442. /package/runtime/node_modules/@metro-labs/{telegram → telegram-bot}/src/verify.ts +0 -0
@@ -0,0 +1,221 @@
1
+ import { join } from 'node:path';
2
+ import { type Server } from 'node:http';
3
+ import { userSelf } from '@metro-labs/core/events';
4
+ import { setTrainCallBackend } from '../stations/train-call.js';
5
+ import { errMsg, log, logFatalSync } from '@metro-labs/core/log';
6
+ import { acquireLock, STATE_DIR, trainsDir } from './paths.js';
7
+ import { installCrashGuard, markDaemonReady } from './crash-guard.js';
8
+ import { METRO_VERSION } from '@metro-labs/core/version';
9
+ import { funnelDriver, Tunnel, tunnelWanted } from '../net/tunnel.js';
10
+ import { webhookPort } from '../files/attach-serve.js';
11
+ import {
12
+ localConnectHint,
13
+ publicConnectHint,
14
+ tunnelPendingHint,
15
+ } from './connect-hint.js';
16
+ import { TrainSupervisor } from '../stations/supervisor.js';
17
+ import {
18
+ makeEmit,
19
+ startWebhookServer,
20
+ trainEventToMetroEvent,
21
+ } from '../routes/http.js';
22
+ import { agentsDir, fileSource } from '../agents/files.js';
23
+ import { syncPluginServers } from '../connectors/plugin-sync.js';
24
+ import { loadConnectorPolicies, readLocalConnectors } from '../connectors/store.js';
25
+ import { ensureMetroPlugin } from '../claude/plugin-install.js';
26
+ import { provisionAgentUser } from '../agent-user/provision.js';
27
+ import { convertRootJobs } from '../agent-user/schedules.js';
28
+ import { applyVault } from '../vault/index.js';
29
+ import { agentUser as currentAgentUser } from '../agent-user/user.js';
30
+ import { ensureServiceOomPolicy } from '../claude/memory.js';
31
+ import { unwatchSession, watchSession } from '../claude/session.js';
32
+ import { tryClaudeSetup } from '../claude/setup.js';
33
+ import { applyLocalOwner } from './local-owner.js';
34
+ import { installBearerSessions } from '../routes/bearer.js';
35
+ import { ensureLocalAgent, localOwner } from '../agents/file-admin.js';
36
+ import { migrateAgentLayout } from '../agents/files.js';
37
+ import { ensureStationDeps } from '../stations/runtime-deps.js';
38
+ import { localSessionApis } from '../routes/local-mode.js';
39
+ import type { SessionApis } from '../routes/session-apis.js';
40
+ import { createMetroMcp } from '../mcp/index.js';
41
+ import { startPromptExpiry } from '../approvals/pending.js';
42
+ import { watchPolicySnapshot } from '../mcp/policy-snapshot.js';
43
+ import { gatherAccountsForAgents } from '../mcp/accounts.js';
44
+ import { stationToolGroups } from '../mcp/tool-catalog.js';
45
+ import {
46
+ accountStationCapabilities,
47
+ forgetOrphans,
48
+ stationByName,
49
+ } from '../stations/registry.js';
50
+ import { prepareAccount } from '../stations/attach.js';
51
+ import { knownAccounts } from '../agents/map.js';
52
+ import { materializeFrom, reloadFrom } from '../stations/materialize.js';
53
+ import type { StationName } from '@metro-labs/core/station-names';
54
+ import { startUploadReaper } from '../files/upload-store.js';
55
+ import { startAttachReaper } from '../files/attach-reaper.js';
56
+
57
+ installCrashGuard();
58
+ acquireLock(join(STATE_DIR, '.tail-lock'));
59
+
60
+ log.info({ self: userSelf() }, 'user identity');
61
+
62
+ process.stdout.on('error', (err) => {
63
+ if ((err as NodeJS.ErrnoException).code !== 'EPIPE')
64
+ log.warn({ err: errMsg(err) }, 'stdout error');
65
+ });
66
+
67
+ const supervisor = new TrainSupervisor();
68
+ const emit = makeEmit();
69
+
70
+ supervisor.onTrainEvent((env, train) => {
71
+ const entry = trainEventToMetroEvent(env, train);
72
+ if (entry) emit(entry);
73
+ });
74
+
75
+ let webhookServer: Server | null = null;
76
+ const tunnel = tunnelWanted() ? new Tunnel(funnelDriver(webhookPort()), announcePublic) : null;
77
+
78
+ function announcePublic(url: string): void {
79
+ process.stderr.write(`\n${publicConnectHint(url, localOwner())}`);
80
+ }
81
+
82
+ setTrainCallBackend((train, action, args) =>
83
+ supervisor.call(train, action, args),
84
+ );
85
+
86
+ function announceLocalEndpoint(): void {
87
+ process.stderr.write(
88
+ `\n${tunnel === null ? localConnectHint(webhookPort(), localOwner()) : tunnelPendingHint()}`,
89
+ );
90
+ }
91
+
92
+ async function syncStations(station: StationName): Promise<void> {
93
+ const { removed } = await reloadFrom(fileSource);
94
+ if (stationByName(station)?.hasTrain === false) return;
95
+ if (removed.includes(station)) await supervisor.stopTrain(station);
96
+ else {
97
+ ensureStationDeps(station);
98
+ supervisor.requestReload(station);
99
+ }
100
+ }
101
+
102
+ function sessionApis(): SessionApis {
103
+ return localSessionApis({
104
+ syncStations,
105
+ reloadAgents: async () => {
106
+ await reloadFrom(fileSource);
107
+ },
108
+ restart: () => {
109
+ exitCode = RESTART_EXIT;
110
+ onShutdown();
111
+ },
112
+ stop: () => {
113
+ exitCode = HOLD_EXIT;
114
+ onShutdown();
115
+ },
116
+ gatherAccounts: gatherAccountsForAgents,
117
+ capabilities: accountStationCapabilities,
118
+ toolGroups: stationToolGroups,
119
+ prepareAccount,
120
+ });
121
+ }
122
+
123
+
124
+ async function main(): Promise<void> {
125
+ applyLocalOwner();
126
+ installBearerSessions(agentsDir(), localOwner);
127
+ migrateAgentLayout();
128
+ watchPolicySnapshot();
129
+ loadConnectorPolicies().catch((err: unknown) => {
130
+ log.warn({ err: errMsg(err) }, 'connector policy: loading the policies failed');
131
+ });
132
+ log.info({ agent: await ensureLocalAgent() }, 'local daemon: agent');
133
+ await materializeFrom(fileSource);
134
+ forgetOrphans(knownAccounts());
135
+ supervisor.start();
136
+ const metroMcp = await createMetroMcp();
137
+ webhookServer = await startWebhookServer(
138
+ emit,
139
+ sessionApis(),
140
+ metroMcp.httpHandler,
141
+ true,
142
+ );
143
+ metroMcp.startInbound();
144
+ startPromptExpiry();
145
+ syncPluginServers(readLocalConnectors());
146
+ startUploadReaper();
147
+ startAttachReaper();
148
+ announceLocalEndpoint();
149
+ tunnel?.start();
150
+ log.info(
151
+ { tunnel: !!tunnel, trainsDir: trainsDir(), mcp: '/', version: METRO_VERSION },
152
+ 'dispatcher ready',
153
+ );
154
+ markDaemonReady();
155
+ startClaude().catch((err: unknown) => {
156
+ log.warn({ err: errMsg(err) }, 'claude: could not start the Claude Code side');
157
+ });
158
+ }
159
+
160
+ async function startClaude(): Promise<void> {
161
+ ensureServiceOomPolicy();
162
+ const agentUser = await provisionAgentUser();
163
+ if (agentUser !== 'off') log.info({ agentUser }, 'agent-user: Claude Code runs as its own user');
164
+ if (agentUser === 'failed') return;
165
+ if (agentUser === 'ready') {
166
+ const switched = convertRootJobs(currentAgentUser());
167
+ if (switched > 0) log.info({ switched }, "schedules: jobs that pointed into root's home now run as the agent user");
168
+ const vault = (await applyVault()).status;
169
+ if (vault.enabled) log.info({ running: vault.running, problem: vault.problem }, 'vault: the agent reaches the internet through the vault');
170
+ }
171
+ ensureMetroPlugin()
172
+ .then((outcome) => {
173
+ log.info({ outcome }, 'plugin: metro plugin for Claude Code');
174
+ if (outcome !== 'skipped') syncPluginServers(readLocalConnectors());
175
+ })
176
+ .catch((err: unknown) => {
177
+ log.warn({ err: errMsg(err) }, 'plugin: could not ensure the Claude Code plugin');
178
+ });
179
+ tryClaudeSetup();
180
+ watchSession();
181
+ }
182
+
183
+ const SHUTDOWN_TIMEOUT_MS = 3_000;
184
+ const RESTART_EXIT = 75;
185
+ const HOLD_EXIT = 76;
186
+ let exitCode = 0;
187
+ let shuttingDown = false;
188
+ async function shutdown(): Promise<void> {
189
+ if (shuttingDown) return;
190
+ shuttingDown = true;
191
+ log.info('dispatcher shutting down');
192
+ unwatchSession();
193
+ tunnel?.stop();
194
+ if (webhookServer) {
195
+ const server = webhookServer;
196
+ await Promise.race([
197
+ new Promise<void>((r) => {
198
+ server.close(() => {
199
+ r();
200
+ });
201
+ }),
202
+ new Promise<void>((r) => {
203
+ setTimeout(r, SHUTDOWN_TIMEOUT_MS).unref();
204
+ }),
205
+ ]);
206
+ }
207
+ await supervisor.stop();
208
+ process.exit(exitCode);
209
+ }
210
+ const onShutdown = (): void => {
211
+ shutdown().catch((err: unknown) => {
212
+ log.error({ err: errMsg(err) }, 'dispatcher: shutdown failed');
213
+ process.exit(1);
214
+ });
215
+ };
216
+ for (const sig of ['SIGINT', 'SIGTERM'] as const) process.on(sig, onShutdown);
217
+
218
+ await main().catch((err: unknown) => {
219
+ logFatalSync({ err: errMsg(err) }, 'dispatcher failed to start');
220
+ process.exit(1);
221
+ });
@@ -0,0 +1,39 @@
1
+ import { hostname } from 'node:os';
2
+
3
+ const uiBase = (): string => process.env.METRO_UI_URL ?? 'https://metro.box';
4
+
5
+ const connectLink = (base: string): string =>
6
+ `${uiBase()}/#/${new URL(base).host}`;
7
+
8
+ const ownerLine = (owner: string | null): string =>
9
+ owner === null
10
+ ? 'No owner is set, so no wallet can sign in. Restart with: metro serve --owner <address>'
11
+ : `Only ${owner} can sign in.`;
12
+
13
+ export function localConnectHint(port: number, owner: string | null): string {
14
+ const here = `http://127.0.0.1:${String(port)}`;
15
+ const forward = `ssh -L ${String(port)}:127.0.0.1:${String(port)} ${hostname()}`;
16
+ return [
17
+ 'Manage this machine from the web UI:',
18
+ '',
19
+ ` ${connectLink(here)}`,
20
+ '',
21
+ `From another computer, forward the port first: ${forward}`,
22
+ ownerLine(owner),
23
+ '',
24
+ ].join('\n');
25
+ }
26
+
27
+ export function publicConnectHint(url: string, owner: string | null): string {
28
+ return [
29
+ 'Manage this machine from the web UI, from anywhere:',
30
+ '',
31
+ ` ${connectLink(url)}`,
32
+ '',
33
+ ownerLine(owner),
34
+ '',
35
+ ].join('\n');
36
+ }
37
+
38
+ export const tunnelPendingHint = (): string =>
39
+ 'Publishing this daemon through Tailscale Funnel… (if Tailscale asks to enable Funnel, its link is in the log)\n';
@@ -1,4 +1,4 @@
1
- import { errMsg, log, logFatalSync } from './log.js';
1
+ import { errMsg, log, logFatalSync } from '@metro-labs/core/log';
2
2
 
3
3
  export type CrashKind = 'unhandledRejection' | 'uncaughtException';
4
4
 
@@ -0,0 +1,21 @@
1
+ import { localOwner, setLocalOwner } from '../agents/file-admin.js';
2
+ import { isOrganizationId } from '@metro-labs/http/workos-token';
3
+ import { log } from '@metro-labs/core/log';
4
+
5
+ export function applyLocalOwner(): string | null {
6
+ const wanted = process.env.METRO_OWNER?.trim() ?? '';
7
+ const stored = localOwner();
8
+ if (stored !== null) {
9
+ if (wanted !== '' && wanted !== stored)
10
+ log.info({ owner: stored, ignored: wanted }, 'local daemon: this machine already belongs to an organization, so --owner is ignored');
11
+ return stored;
12
+ }
13
+ if (isOrganizationId(wanted)) {
14
+ const owner = setLocalOwner(wanted);
15
+ log.info({ owner }, 'local daemon: owner set from METRO_OWNER');
16
+ return owner;
17
+ }
18
+ if (wanted !== '') log.info({ ignored: wanted }, 'local daemon: --owner is not an organization id, so it is ignored');
19
+ log.warn('local daemon: no organization owns this machine, so nobody can sign in; restart with metro serve --owner <organization id>');
20
+ return null;
21
+ }
@@ -1,7 +1,6 @@
1
1
  import { execFileSync } from 'node:child_process';
2
2
  import {
3
3
  closeSync,
4
- existsSync,
5
4
  mkdirSync,
6
5
  openSync,
7
6
  readFileSync,
@@ -10,45 +9,18 @@ import {
10
9
  } from 'node:fs';
11
10
  import { homedir } from 'node:os';
12
11
  import { join } from 'node:path';
13
- import { log } from './log.js';
12
+ import { fileURLToPath } from 'node:url';
13
+ import { log } from '@metro-labs/core/log';
14
14
 
15
15
  export const STATE_DIR =
16
16
  process.env.METRO_STATE_DIR ?? join(homedir(), '.cache', 'metro');
17
17
  mkdirSync(STATE_DIR, { recursive: true });
18
18
 
19
- export const CONFIG_DIR =
20
- process.env.METRO_CONFIG_DIR ??
21
- join(process.env.XDG_CONFIG_HOME ?? join(homedir(), '.config'), 'metro');
22
- export const CONFIG_ENV_FILE = join(CONFIG_DIR, '.env');
23
19
 
24
- export const TRAINS_ENV_FILE = join(homedir(), '.metro', '.env');
25
-
26
- export const envSources = (): readonly string[] => [
27
- join(process.cwd(), '.env'),
28
- TRAINS_ENV_FILE,
29
- CONFIG_ENV_FILE,
30
- ];
31
-
32
- const LINE_RE = /^\s*([A-Za-z_]\w*)\s*=\s*(.*?)\s*$/;
33
- const QUOTED_RE = /^(['"])(.*)\1$/;
34
-
35
- export function readDotenv(path: string): Record<string, string> {
36
- if (!existsSync(path)) return {};
37
- const out: Record<string, string> = {};
38
- for (const line of readFileSync(path, 'utf8').split('\n')) {
39
- const m = LINE_RE.exec(line);
40
- if (m?.[1] !== undefined && m[2] !== undefined)
41
- out[m[1]] = m[2].replace(QUOTED_RE, '$2');
42
- }
43
- return out;
44
- }
45
-
46
- export function loadMetroEnv(): void {
47
- for (const path of envSources()) {
48
- for (const [k, v] of Object.entries(readDotenv(path))) {
49
- process.env[k] ??= v;
50
- }
51
- }
20
+ export function trainsDir(): string {
21
+ const env = process.env.METRO_TRAINS_DIR?.trim();
22
+ if (env !== undefined && env !== '') return env;
23
+ return fileURLToPath(new URL('../../trains', import.meta.url));
52
24
  }
53
25
 
54
26
  function readLockPid(lockFile: string): number {
@@ -0,0 +1,26 @@
1
+ import { str } from '@metro-labs/core/str';
2
+
3
+ export type Addressed = 'direct' | 'mention' | 'reply';
4
+
5
+ interface AddressFacts {
6
+ isPrivate?: unknown;
7
+ mentionsSelf?: unknown;
8
+ replyToSelf?: unknown;
9
+ }
10
+
11
+ export function addressedBy(facts: AddressFacts, replyTo: string, sent: ReadonlySet<string>): Addressed | undefined {
12
+ if (facts.isPrivate === true) return 'direct';
13
+ if (facts.mentionsSelf === true) return 'mention';
14
+ if (facts.replyToSelf === true || (replyTo !== '' && sent.has(replyTo))) return 'reply';
15
+ return undefined;
16
+ }
17
+
18
+ export function replyMeta(ev: Record<string, unknown>, sent: ReadonlySet<string>): Record<string, string> {
19
+ const replyTo = str(ev.replyTo);
20
+ const addressed = addressedBy(ev, replyTo, sent);
21
+ return {
22
+ ...(replyTo ? { reply_to: replyTo } : {}),
23
+ ...(addressed === undefined ? {} : { addressed }),
24
+ ...(typeof ev.senderVerified === 'boolean' ? { sender_verified: String(ev.senderVerified) } : {}),
25
+ };
26
+ }
@@ -0,0 +1,12 @@
1
+ const accountStrippedLine = (line: string): string => {
2
+ const parts = line.split('/');
3
+ if (parts.length < 5) return line;
4
+ return [parts[0], parts[1], parts[2], ...parts.slice(4)].join('/');
5
+ };
6
+
7
+ export const dedupeKey = (
8
+ station: string,
9
+ line: string,
10
+ kind: string,
11
+ messageId: string,
12
+ ): string => `${station} ${accountStrippedLine(line)} ${kind} ${messageId}`;
@@ -1,6 +1,7 @@
1
1
  import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
- import { str } from '../mcp/str.js';
2
+ import { str } from '@metro-labs/core/str';
3
3
  import { dedupeKey } from './dedupe.js';
4
+ import { PERMISSION_REPLY_RE } from './reply-id.js';
4
5
  import {
5
6
  buildMediaFailureNote,
6
7
  buildMediaNote,
@@ -8,6 +9,8 @@ import {
8
9
  type SavedMedia,
9
10
  } from './media-note.js';
10
11
  import { buildWebhookNote } from './webhook-note.js';
12
+ import { reactContent, reactionEmoji } from './react-note.js';
13
+ import { replyMeta } from './addressed.js';
11
14
  import {
12
15
  capSet,
13
16
  displayNameMeta,
@@ -18,31 +21,29 @@ import {
18
21
  type PendingAtt,
19
22
  type PendingMsg,
20
23
  } from './pending.js';
24
+ import { agentUser } from '../agent-user/user.js';
21
25
 
22
26
  interface InboundDeps {
23
27
  mcp: Server;
24
28
  log: (...a: unknown[]) => void;
25
29
  getStations: () => Set<string>;
26
- senderAllowed: (from: string, line: string) => boolean;
30
+ senderAllowed: (from: string, line: string, verified?: boolean) => boolean;
31
+ approves?: (station: string) => boolean;
32
+ answerPermission?: (requestId: string, behavior: 'allow' | 'deny', line: string, from: string) => Promise<boolean>;
27
33
  }
28
34
 
29
35
  const ATTACH_TIMEOUT_MS = 15_000;
30
36
  const DEDUPE_TTL_MS = 30_000;
31
37
  const DEDUPE_MAX = 2_000;
32
38
  const ALLOWED_LINES_MAX = 2_000;
33
- const PENDING_PERMISSIONS_MAX = 500;
34
-
35
- const PERMISSION_REPLY_RE = /^\s*(y|yes|n|no)\s+([a-km-z]{5})\s*$/i;
36
-
37
- const shortId = (id: string): string =>
38
- id.length > 10 ? `${id.slice(0, 6)}…` : id;
39
+ const SENT_IDS_MAX = 2_000;
39
40
 
40
41
  export class InboundRelay {
41
42
  private readonly deps: InboundDeps;
42
43
  private readonly pendingAttachments = new Map<string, PendingMsg>();
43
44
  private readonly seenEvents = new Map<string, number>();
44
45
  private readonly allowedLines = new Set<string>();
45
- private readonly pendingPermissions = new Set<string>();
46
+ private readonly sentIds = new Set<string>();
46
47
  private lastLine: string | undefined;
47
48
 
48
49
  constructor(deps: InboundDeps) {
@@ -53,9 +54,10 @@ export class InboundRelay {
53
54
  return this.lastLine;
54
55
  }
55
56
 
56
- registerPermission(requestId: string): void {
57
- this.pendingPermissions.add(requestId);
58
- capSet(this.pendingPermissions, PENDING_PERMISSIONS_MAX);
57
+ noteSent(messageId: string): void {
58
+ if (!messageId) return;
59
+ this.sentIds.add(messageId);
60
+ capSet(this.sentIds, SENT_IDS_MAX);
59
61
  }
60
62
 
61
63
  private notify(method: string, params: Record<string, unknown>): Promise<void> {
@@ -95,6 +97,7 @@ export class InboundRelay {
95
97
  from: ctx.from,
96
98
  station: ctx.station,
97
99
  ...senderMeta(ctx),
100
+ ...ctx.reply,
98
101
  kind: note.kind,
99
102
  mime: p.mime ?? '',
100
103
  name: note.name,
@@ -104,11 +107,12 @@ export class InboundRelay {
104
107
  }
105
108
 
106
109
  private async surfaceMedia(ctx: MediaCtx, p: SavedMedia): Promise<void> {
107
- const note = await buildMediaNote(p, ctx.text ?? '');
110
+ const ownUser = agentUser() !== null;
111
+ const note = await buildMediaNote(p, ctx.text ?? '', !ownUser);
108
112
  if (!note) return;
109
113
  await this.surfaceNote(ctx, p, note, {
110
114
  ...(p.url ? { url: p.url } : {}),
111
- local_path: note.path,
115
+ ...(ownUser ? {} : { local_path: note.path }),
112
116
  });
113
117
  }
114
118
 
@@ -140,6 +144,7 @@ export class InboundRelay {
140
144
  line_name: e.lineName,
141
145
  from_name: e.fromName,
142
146
  ...displayNameMeta(e.fromDisplayName),
147
+ ...e.reply,
143
148
  },
144
149
  });
145
150
  }
@@ -197,6 +202,7 @@ export class InboundRelay {
197
202
  lineName: str(ev.lineName),
198
203
  fromName: str(ev.fromName),
199
204
  fromDisplayName: str(ev.fromDisplayName),
205
+ reply: replyMeta(ev, this.sentIds),
200
206
  attachments: atts.map((a) => ({ kind: a.kind, name: a.name })),
201
207
  saved: new Set<number>(),
202
208
  timer: setTimeout(() => {
@@ -224,9 +230,7 @@ export class InboundRelay {
224
230
  const removed =
225
231
  (ev.payload as { removed?: boolean } | undefined)?.removed === true ||
226
232
  / \(removed\)\]?$/.test(base.text);
227
- const verb = removed ? 'removed from' : 'reacted to';
228
- const label = removed ? emoji || 'reaction' : emoji || 'reacted';
229
- const content = `${label} ${verb} message ${shortId(target)}`.trim();
233
+ const content = reactContent(emoji, target, removed);
230
234
  await this.notify('notifications/claude/channel', {
231
235
  content,
232
236
  meta: {
@@ -244,28 +248,33 @@ export class InboundRelay {
244
248
  });
245
249
  }
246
250
 
247
- private async handlePermissionReply(text: string): Promise<boolean> {
248
- const m = PERMISSION_REPLY_RE.exec(text);
249
- if (m?.[1] === undefined || m[2] === undefined || !this.pendingPermissions.size)
250
- return false;
251
- const id = m[2].toLowerCase();
252
- if (!this.pendingPermissions.has(id)) return false;
253
- this.pendingPermissions.delete(id);
254
- await this.notify('notifications/claude/channel/permission', {
255
- request_id: id,
256
- behavior: m[1].toLowerCase().startsWith('y') ? 'allow' : 'deny',
257
- });
258
- return true;
251
+ private async handlePermissionReply(ev: Record<string, unknown>, base: EventBase): Promise<boolean> {
252
+ const answer = this.deps.answerPermission;
253
+ if (answer === undefined || base.evType !== 'msg' || !this.approves(base.station) || ev.senderVerified === false) return false;
254
+ const m = PERMISSION_REPLY_RE.exec(base.text);
255
+ if (m?.[1] === undefined || m[2] === undefined) return false;
256
+ return answer(m[2].toLowerCase(), m[1].toLowerCase().startsWith('y') ? 'allow' : 'deny', base.line, base.from);
257
+ }
258
+
259
+ private approves(station: string): boolean {
260
+ return this.deps.approves?.(station) !== false;
259
261
  }
260
262
 
261
- private droppedSender(from: string, line: string): boolean {
263
+ private noteLine(base: EventBase): void {
264
+ if (base.evType !== 'system' && this.approves(base.station)) this.lastLine = base.line;
265
+ if (!base.line) return;
266
+ this.allowedLines.add(base.line);
267
+ capSet(this.allowedLines, ALLOWED_LINES_MAX);
268
+ }
269
+
270
+ private droppedSender(from: string, line: string, verified: unknown): boolean {
262
271
  if (
263
272
  from.startsWith('metro://claude') ||
264
273
  from === 'metro://user' ||
265
274
  !from.startsWith('metro://')
266
275
  )
267
276
  return true;
268
- if (!this.deps.senderAllowed(from, line)) {
277
+ if (!this.deps.senderAllowed(from, line, typeof verified === 'boolean' ? verified : undefined)) {
269
278
  this.deps.log('drop: sender not allowed', from);
270
279
  return true;
271
280
  }
@@ -284,7 +293,7 @@ export class InboundRelay {
284
293
  if (!this.deps.getStations().has(station)) return null;
285
294
  const from = str(ev.from);
286
295
  const line = str(ev.line);
287
- if (this.droppedSender(from, line)) return null;
296
+ if (this.droppedSender(from, line, ev.senderVerified)) return null;
288
297
  const text = str(ev.text);
289
298
  if (!replay && this.isDuplicate(station, line, evType, str(ev.messageId))) {
290
299
  this.deps.log(
@@ -302,8 +311,11 @@ export class InboundRelay {
302
311
  ev: Record<string, unknown>,
303
312
  base: EventBase,
304
313
  ): Promise<void> {
305
- if (base.evType === 'msg' && (await this.handlePermissionReply(base.text)))
314
+ if (base.evType === 'msg' && base.text.trim() === '') {
315
+ this.deps.log('drop: empty message', base.station, base.line, str(ev.messageId));
306
316
  return;
317
+ }
318
+ if (await this.handlePermissionReply(ev, base)) return;
307
319
  await this.notify('notifications/claude/channel', {
308
320
  content:
309
321
  base.evType === 'system'
@@ -318,6 +330,7 @@ export class InboundRelay {
318
330
  line_name: str(ev.lineName),
319
331
  from_name: str(ev.fromName),
320
332
  ...displayNameMeta(ev.fromDisplayName),
333
+ ...replyMeta(ev, this.sentIds),
321
334
  },
322
335
  });
323
336
  }
@@ -330,11 +343,7 @@ export class InboundRelay {
330
343
 
331
344
  const base = this.routable(ev, replay);
332
345
  if (!base) return;
333
- if (base.evType !== 'system') this.lastLine = base.line;
334
- if (base.line) {
335
- this.allowedLines.add(base.line);
336
- capSet(this.allowedLines, ALLOWED_LINES_MAX);
337
- }
346
+ this.noteLine(base);
338
347
 
339
348
  const atts = (ev.payload as { attachments?: PendingAtt[] } | undefined)
340
349
  ?.attachments;
@@ -347,7 +356,6 @@ export class InboundRelay {
347
356
  await this.handleReact(ev, base);
348
357
  return;
349
358
  }
350
-
351
359
  await this.emitMessage(ev, base);
352
360
  }
353
361
  }
@@ -360,8 +368,3 @@ interface EventBase {
360
368
  text: string;
361
369
  }
362
370
 
363
- function reactionEmoji(raw: unknown): string {
364
- if (typeof raw === 'string') return raw;
365
- const obj = raw as { name?: string; reaction?: string } | undefined;
366
- return obj?.name ?? obj?.reaction ?? '';
367
- }
@@ -50,22 +50,27 @@ function howToRead(url: string | undefined, tooBig: boolean): string {
50
50
  return 'Fetch the Public URL to view it. The path is on the daemon host, so the Read tool works only for an agent running there.';
51
51
  }
52
52
 
53
+ const headline = (kind: string, name: string, mime: string | undefined, size: number): string =>
54
+ `[${kind} attachment received: ${name}${mime ? `, ${mime}` : ''}${size ? ` (${(size / 1024 / 1024).toFixed(2)} MB)` : ''}]\n`;
55
+
56
+ const whereItIs = (path: string, url: string | undefined, size: number, showPath: boolean): string =>
57
+ showPath ? `Daemon-host path: ${path}\n${howToRead(url, size > MAX_INLINE_BYTES)}` : 'Fetch the Public URL to get the file.';
58
+
53
59
  export async function buildMediaNote(
54
60
  p: SavedMedia,
55
61
  caption: string,
62
+ showPath = true,
56
63
  ): Promise<MediaNote | null> {
57
64
  const path = p.attachmentPath ?? p.localPath;
58
65
  if (!path) return null;
59
66
  const kind = p.kind ?? mediaKind(p.mime, p.name);
60
67
  const name = p.name ?? path.split('/').pop() ?? 'attachment';
61
68
  const size = await fileSize(path);
62
- const sizeNote = size ? ` (${(size / 1024 / 1024).toFixed(2)} MB)` : '';
63
69
  const content =
64
70
  (caption ? `${caption}\n` : '') +
65
- `[${kind} attachment received: ${name}${p.mime ? `, ${p.mime}` : ''}${sizeNote}]\n` +
71
+ headline(kind, name, p.mime, size) +
66
72
  (p.url ? `Public URL: ${p.url}\n` : '') +
67
- `Daemon-host path: ${path}\n` +
68
- howToRead(p.url, size > MAX_INLINE_BYTES);
73
+ whereItIs(path, p.url, size, showPath);
69
74
  return { content, kind, name, path };
70
75
  }
71
76
 
@@ -1,4 +1,4 @@
1
- import { str } from '../mcp/str.js';
1
+ import { str } from '@metro-labs/core/str';
2
2
 
3
3
  export interface PendingAtt {
4
4
  kind?: string;
@@ -15,6 +15,7 @@ export interface PendingMsg {
15
15
  lineName: string;
16
16
  fromName: string;
17
17
  fromDisplayName: string;
18
+ reply: Record<string, string>;
18
19
  attachments: PendingAtt[];
19
20
  saved: Set<number>;
20
21
  timer: ReturnType<typeof setTimeout>;
@@ -30,6 +31,7 @@ export interface MediaCtx {
30
31
  lineName?: string;
31
32
  fromName?: string;
32
33
  fromDisplayName?: string;
34
+ reply?: Record<string, string>;
33
35
  }
34
36
 
35
37
  export function capSet(set: Set<string>, max: number): void {
@@ -69,6 +71,7 @@ export function takeMediaCtx(buf: PendingMsg): MediaCtx {
69
71
  lineName: buf.lineName,
70
72
  fromName: buf.fromName,
71
73
  fromDisplayName: buf.fromDisplayName,
74
+ reply: buf.reply,
72
75
  };
73
76
  buf.text = '';
74
77
  return ctx;