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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (327) hide show
  1. package/dist/api.js +9 -0
  2. package/dist/claude-settings.js +40 -0
  3. package/dist/claude.js +182 -0
  4. package/dist/cli.js +86 -0
  5. package/dist/control.js +74 -0
  6. package/dist/hold.js +211 -0
  7. package/dist/local.js +77 -0
  8. package/dist/mcp-config.js +25 -0
  9. package/dist/node-name.js +71 -0
  10. package/dist/onboarding.js +43 -0
  11. package/dist/provider-flags.js +9 -0
  12. package/dist/route.js +50 -0
  13. package/dist/runtime-install.js +97 -0
  14. package/dist/runtime.js +74 -0
  15. package/dist/serve.js +155 -0
  16. package/dist/service.js +242 -0
  17. package/dist/tail.js +119 -0
  18. package/dist/update.js +45 -0
  19. package/dist/version.js +97 -0
  20. package/package.json +14 -28
  21. package/runtime/marketplace/.claude-plugin/marketplace.json +12 -0
  22. package/runtime/marketplace/plugin/.claude-plugin/plugin.json +18 -0
  23. package/runtime/marketplace/plugin/.mcp.json +1 -0
  24. package/runtime/marketplace/plugin/bin/guard.mjs +55 -0
  25. package/runtime/marketplace/plugin/bin/metro-plugin.mjs +40 -0
  26. package/runtime/marketplace/plugin/bin/session-start.mjs +31 -0
  27. package/runtime/marketplace/plugin/hooks/hooks.json +25 -0
  28. package/runtime/marketplace/plugin/orchestrator.md +16 -0
  29. package/runtime/node_modules/@metro-labs/core/package.json +43 -0
  30. package/runtime/node_modules/@metro-labs/core/src/address.ts +6 -0
  31. package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
  32. package/runtime/node_modules/@metro-labs/core/src/events.ts +120 -0
  33. package/runtime/node_modules/@metro-labs/core/src/identity.ts +7 -0
  34. package/runtime/node_modules/@metro-labs/core/src/ids.ts +21 -0
  35. package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
  36. package/runtime/node_modules/@metro-labs/core/src/lines.ts +87 -0
  37. package/runtime/node_modules/@metro-labs/core/src/log.ts +42 -0
  38. package/runtime/node_modules/@metro-labs/core/src/protocol.ts +226 -0
  39. package/runtime/node_modules/@metro-labs/core/src/secure-fs.ts +57 -0
  40. package/runtime/node_modules/@metro-labs/core/src/station-names.ts +13 -0
  41. package/runtime/node_modules/@metro-labs/core/src/stations/account-store.ts +60 -0
  42. package/runtime/node_modules/@metro-labs/core/src/stations/attachments.ts +196 -0
  43. package/runtime/node_modules/@metro-labs/core/src/stations/messaging-normalize.ts +88 -0
  44. package/runtime/node_modules/@metro-labs/core/src/stations/station-runtime.ts +64 -0
  45. package/runtime/node_modules/@metro-labs/core/src/stations/types.ts +108 -0
  46. package/runtime/node_modules/@metro-labs/core/src/str.ts +5 -0
  47. package/runtime/node_modules/@metro-labs/core/src/train-error.ts +53 -0
  48. package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
  49. package/runtime/node_modules/@metro-labs/daemon/package.json +47 -0
  50. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-attach.ts +19 -0
  51. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-routes.ts +70 -0
  52. package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +365 -0
  53. package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +39 -0
  54. package/runtime/node_modules/@metro-labs/daemon/src/agents/allowlist.ts +37 -0
  55. package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +225 -0
  56. package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +122 -0
  57. package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +364 -0
  58. package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +185 -0
  59. package/runtime/node_modules/@metro-labs/daemon/src/agents/keys.ts +40 -0
  60. package/runtime/node_modules/@metro-labs/daemon/src/agents/map.ts +95 -0
  61. package/runtime/node_modules/@metro-labs/daemon/src/agents/scope.ts +64 -0
  62. package/runtime/node_modules/@metro-labs/daemon/src/agents/senders.ts +38 -0
  63. package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +200 -0
  64. package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +39 -0
  65. package/runtime/node_modules/@metro-labs/daemon/src/boot/crash-guard.ts +49 -0
  66. package/runtime/node_modules/@metro-labs/daemon/src/boot/local-owner.ts +30 -0
  67. package/runtime/node_modules/@metro-labs/daemon/src/boot/paths.ts +106 -0
  68. package/runtime/node_modules/@metro-labs/daemon/src/channels/addressed.ts +25 -0
  69. package/runtime/node_modules/@metro-labs/daemon/src/channels/dedupe.ts +24 -0
  70. package/runtime/node_modules/@metro-labs/daemon/src/channels/inbound.ts +380 -0
  71. package/runtime/node_modules/@metro-labs/daemon/src/channels/media-note.ts +85 -0
  72. package/runtime/node_modules/@metro-labs/daemon/src/channels/pending.ts +75 -0
  73. package/runtime/node_modules/@metro-labs/daemon/src/channels/relay.ts +129 -0
  74. package/runtime/node_modules/@metro-labs/daemon/src/channels/webhook-note.ts +51 -0
  75. package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +354 -0
  76. package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +358 -0
  77. package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +169 -0
  78. package/runtime/node_modules/@metro-labs/daemon/src/claude/onboarding.ts +56 -0
  79. package/runtime/node_modules/@metro-labs/daemon/src/claude/plugin-install.ts +140 -0
  80. package/runtime/node_modules/@metro-labs/daemon/src/claude/session-files.ts +90 -0
  81. package/runtime/node_modules/@metro-labs/daemon/src/claude/session.ts +253 -0
  82. package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +117 -0
  83. package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +263 -0
  84. package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +118 -0
  85. package/runtime/node_modules/@metro-labs/daemon/src/claude/version.ts +109 -0
  86. package/runtime/node_modules/@metro-labs/daemon/src/connectors/api.ts +313 -0
  87. package/runtime/node_modules/@metro-labs/daemon/src/connectors/config.ts +157 -0
  88. package/runtime/node_modules/@metro-labs/daemon/src/connectors/health.ts +18 -0
  89. package/runtime/node_modules/@metro-labs/daemon/src/connectors/model.ts +69 -0
  90. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-client.ts +166 -0
  91. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-discovery.ts +139 -0
  92. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-pending.ts +65 -0
  93. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-routes.ts +171 -0
  94. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth.ts +155 -0
  95. package/runtime/node_modules/@metro-labs/daemon/src/connectors/plugin-sync.ts +122 -0
  96. package/runtime/node_modules/@metro-labs/daemon/src/connectors/reach.ts +27 -0
  97. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-target.ts +39 -0
  98. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +304 -0
  99. package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +299 -0
  100. package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +108 -0
  101. package/runtime/node_modules/@metro-labs/daemon/src/connectors/url.ts +59 -0
  102. package/runtime/node_modules/@metro-labs/daemon/src/connectors/verify.ts +101 -0
  103. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-grant.ts +99 -0
  104. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-owner.ts +32 -0
  105. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-serve.ts +121 -0
  106. package/runtime/node_modules/@metro-labs/daemon/src/files/upload-api.ts +294 -0
  107. package/runtime/node_modules/@metro-labs/daemon/src/files/upload-store.ts +181 -0
  108. package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +259 -0
  109. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +231 -0
  110. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-device.ts +91 -0
  111. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +288 -0
  112. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +203 -0
  113. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +231 -0
  114. package/runtime/node_modules/@metro-labs/daemon/src/gateway/eventstream.ts +123 -0
  115. package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +187 -0
  116. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +247 -0
  117. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-auth.ts +182 -0
  118. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-client.ts +46 -0
  119. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-setup.ts +150 -0
  120. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-stream.ts +148 -0
  121. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-translate.ts +201 -0
  122. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini.ts +257 -0
  123. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +353 -0
  124. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +232 -0
  125. package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +90 -0
  126. package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +65 -0
  127. package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +17 -0
  128. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +242 -0
  129. package/runtime/node_modules/@metro-labs/daemon/src/mcp/accounts.ts +151 -0
  130. package/runtime/node_modules/@metro-labs/daemon/src/mcp/call-tools.ts +216 -0
  131. package/runtime/node_modules/@metro-labs/daemon/src/mcp/channel-owner.ts +29 -0
  132. package/runtime/node_modules/@metro-labs/daemon/src/mcp/ctx.ts +62 -0
  133. package/runtime/node_modules/@metro-labs/daemon/src/mcp/event-store.ts +91 -0
  134. package/runtime/node_modules/@metro-labs/daemon/src/mcp/frame-scope.ts +21 -0
  135. package/runtime/node_modules/@metro-labs/daemon/src/mcp/group-tools.ts +129 -0
  136. package/runtime/node_modules/@metro-labs/daemon/src/mcp/index.ts +186 -0
  137. package/runtime/node_modules/@metro-labs/daemon/src/mcp/member-tools.ts +72 -0
  138. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +66 -0
  139. package/runtime/node_modules/@metro-labs/daemon/src/mcp/raw-get-stream.ts +207 -0
  140. package/runtime/node_modules/@metro-labs/daemon/src/mcp/request-identity.ts +47 -0
  141. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-registry.ts +172 -0
  142. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-route.ts +43 -0
  143. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session.ts +215 -0
  144. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-dispatch.ts +215 -0
  145. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-schemas.ts +400 -0
  146. package/runtime/node_modules/@metro-labs/daemon/src/mcp/upload-tool.ts +66 -0
  147. package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +237 -0
  148. package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +389 -0
  149. package/runtime/node_modules/@metro-labs/daemon/src/routes/bearer.ts +35 -0
  150. package/runtime/node_modules/@metro-labs/daemon/src/routes/body.ts +24 -0
  151. package/runtime/node_modules/@metro-labs/daemon/src/routes/http.ts +370 -0
  152. package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +210 -0
  153. package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +58 -0
  154. package/runtime/node_modules/@metro-labs/daemon/src/routes/session.ts +29 -0
  155. package/runtime/node_modules/@metro-labs/daemon/src/routes/threema-callback.ts +103 -0
  156. package/runtime/node_modules/@metro-labs/daemon/src/server/control.ts +65 -0
  157. package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +80 -0
  158. package/runtime/node_modules/@metro-labs/daemon/src/server/owner.ts +48 -0
  159. package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +117 -0
  160. package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
  161. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-inline.ts +100 -0
  162. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-interactive.ts +161 -0
  163. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-resolve.ts +202 -0
  164. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-session.ts +280 -0
  165. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-xmtp.ts +111 -0
  166. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach.ts +248 -0
  167. package/runtime/node_modules/@metro-labs/daemon/src/stations/materialize.ts +261 -0
  168. package/runtime/node_modules/@metro-labs/daemon/src/stations/registry.ts +37 -0
  169. package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +82 -0
  170. package/runtime/node_modules/@metro-labs/daemon/src/stations/supervisor-io.ts +97 -0
  171. package/runtime/node_modules/@metro-labs/daemon/src/stations/supervisor.ts +320 -0
  172. package/runtime/node_modules/@metro-labs/daemon/src/stations/threema-callbacks.ts +32 -0
  173. package/runtime/node_modules/@metro-labs/daemon/src/stations/train-call.ts +22 -0
  174. package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +97 -0
  175. package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +123 -0
  176. package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +40 -0
  177. package/runtime/node_modules/@metro-labs/discord-bot/package.json +28 -0
  178. package/runtime/node_modules/@metro-labs/discord-bot/src/accounts.ts +118 -0
  179. package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +388 -0
  180. package/runtime/node_modules/@metro-labs/discord-bot/src/api-base.ts +1 -0
  181. package/runtime/node_modules/@metro-labs/discord-bot/src/attachments.ts +29 -0
  182. package/runtime/node_modules/@metro-labs/discord-bot/src/format.ts +220 -0
  183. package/runtime/node_modules/@metro-labs/discord-bot/src/group-actions.ts +50 -0
  184. package/runtime/node_modules/@metro-labs/discord-bot/src/group.ts +115 -0
  185. package/runtime/node_modules/@metro-labs/discord-bot/src/index.ts +127 -0
  186. package/runtime/node_modules/@metro-labs/discord-bot/src/members.ts +215 -0
  187. package/runtime/node_modules/@metro-labs/discord-bot/src/send-files.ts +43 -0
  188. package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +19 -0
  189. package/runtime/node_modules/@metro-labs/discord-bot/src/verify.ts +82 -0
  190. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-speak.ts +195 -0
  191. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-transcribe.ts +292 -0
  192. package/runtime/node_modules/@metro-labs/discord-bot/src/voice.ts +197 -0
  193. package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +5 -0
  194. package/runtime/node_modules/@metro-labs/http/package.json +29 -0
  195. package/runtime/node_modules/@metro-labs/http/src/api-error.ts +8 -0
  196. package/runtime/node_modules/@metro-labs/http/src/api-http.ts +106 -0
  197. package/runtime/node_modules/@metro-labs/http/src/cors.ts +29 -0
  198. package/runtime/node_modules/@metro-labs/http/src/mode-api.ts +32 -0
  199. package/runtime/node_modules/@metro-labs/http/src/return-to.ts +21 -0
  200. package/runtime/node_modules/@metro-labs/http/src/workos-token.ts +150 -0
  201. package/runtime/node_modules/@metro-labs/telegram/package.json +26 -0
  202. package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +80 -0
  203. package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +254 -0
  204. package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +87 -0
  205. package/runtime/node_modules/@metro-labs/telegram/src/client.ts +77 -0
  206. package/runtime/node_modules/@metro-labs/telegram/src/format.ts +156 -0
  207. package/runtime/node_modules/@metro-labs/telegram/src/group.ts +261 -0
  208. package/runtime/node_modules/@metro-labs/telegram/src/history.ts +52 -0
  209. package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +78 -0
  210. package/runtime/node_modules/@metro-labs/telegram/src/index.ts +46 -0
  211. package/runtime/node_modules/@metro-labs/telegram/src/login.ts +166 -0
  212. package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +80 -0
  213. package/runtime/node_modules/@metro-labs/telegram/src/members.ts +75 -0
  214. package/runtime/node_modules/@metro-labs/telegram/src/normalize.ts +22 -0
  215. package/runtime/node_modules/@metro-labs/telegram/src/reactions.ts +167 -0
  216. package/runtime/node_modules/@metro-labs/telegram/src/station.ts +24 -0
  217. package/runtime/node_modules/@metro-labs/telegram/src/types.ts +7 -0
  218. package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +1 -0
  219. package/runtime/node_modules/@metro-labs/telegram-bot/package.json +25 -0
  220. package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +120 -0
  221. package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +295 -0
  222. package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +128 -0
  223. package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +201 -0
  224. package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +109 -0
  225. package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +166 -0
  226. package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +47 -0
  227. package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +17 -0
  228. package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +58 -0
  229. package/runtime/node_modules/@metro-labs/telegram-bot/src/verify.ts +38 -0
  230. package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +3 -0
  231. package/runtime/node_modules/@metro-labs/threema/package.json +26 -0
  232. package/runtime/node_modules/@metro-labs/threema/src/accounts.ts +100 -0
  233. package/runtime/node_modules/@metro-labs/threema/src/actions.ts +223 -0
  234. package/runtime/node_modules/@metro-labs/threema/src/api.ts +130 -0
  235. package/runtime/node_modules/@metro-labs/threema/src/crypto.ts +132 -0
  236. package/runtime/node_modules/@metro-labs/threema/src/format.ts +123 -0
  237. package/runtime/node_modules/@metro-labs/threema/src/ids.ts +21 -0
  238. package/runtime/node_modules/@metro-labs/threema/src/index.ts +29 -0
  239. package/runtime/node_modules/@metro-labs/threema/src/station.ts +10 -0
  240. package/runtime/node_modules/@metro-labs/threema/src/verify.ts +117 -0
  241. package/runtime/node_modules/@metro-labs/webhook/package.json +23 -0
  242. package/runtime/node_modules/@metro-labs/webhook/src/station.ts +37 -0
  243. package/runtime/node_modules/@metro-labs/whatsapp/package.json +27 -0
  244. package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +66 -0
  245. package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +101 -0
  246. package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +190 -0
  247. package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +72 -0
  248. package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +129 -0
  249. package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +347 -0
  250. package/runtime/node_modules/@metro-labs/whatsapp/src/delivery.ts +49 -0
  251. package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +138 -0
  252. package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +57 -0
  253. package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +40 -0
  254. package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +59 -0
  255. package/runtime/node_modules/@metro-labs/whatsapp/src/logger.ts +60 -0
  256. package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +176 -0
  257. package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +84 -0
  258. package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +22 -0
  259. package/runtime/node_modules/@metro-labs/whatsapp/src/outbox.ts +38 -0
  260. package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +185 -0
  261. package/runtime/node_modules/@metro-labs/whatsapp/src/resolve.ts +52 -0
  262. package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +18 -0
  263. package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +98 -0
  264. package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +6 -0
  265. package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +5 -0
  266. package/runtime/node_modules/@metro-labs/xmtp/package.json +33 -0
  267. package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +112 -0
  268. package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +110 -0
  269. package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +299 -0
  270. package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +157 -0
  271. package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +87 -0
  272. package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +375 -0
  273. package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +107 -0
  274. package/runtime/node_modules/@metro-labs/xmtp/src/codecs.ts +171 -0
  275. package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +239 -0
  276. package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +55 -0
  277. package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +335 -0
  278. package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +80 -0
  279. package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +34 -0
  280. package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +56 -0
  281. package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +33 -0
  282. package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +125 -0
  283. package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +157 -0
  284. package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +40 -0
  285. package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +349 -0
  286. package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +13 -0
  287. package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +126 -0
  288. package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +212 -0
  289. package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +90 -0
  290. package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +84 -0
  291. package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +53 -0
  292. package/runtime/runtime.json +3 -0
  293. package/runtime/server.ts +1 -0
  294. package/runtime/stations.json +37 -0
  295. package/runtime/trains/.keep +0 -0
  296. package/LICENSE +0 -21
  297. package/README.md +0 -139
  298. package/dist/broker/claims.js +0 -144
  299. package/dist/broker/history-stream.js +0 -149
  300. package/dist/cli/config.js +0 -179
  301. package/dist/cli/index.js +0 -175
  302. package/dist/cli/messenger-api.js +0 -214
  303. package/dist/cli/messenger-transcribe.js +0 -43
  304. package/dist/cli/messenger-uploads.js +0 -116
  305. package/dist/cli/monitor-api.js +0 -205
  306. package/dist/cli/tail.js +0 -95
  307. package/dist/cli/util.js +0 -72
  308. package/dist/cli/webhook.js +0 -181
  309. package/dist/codex-rc/client.js +0 -225
  310. package/dist/codex-rc/protocol.js +0 -38
  311. package/dist/dispatcher/server.js +0 -122
  312. package/dist/dispatcher.js +0 -97
  313. package/dist/history.js +0 -143
  314. package/dist/ipc.js +0 -90
  315. package/dist/lines.js +0 -54
  316. package/dist/local-identity.js +0 -80
  317. package/dist/log.js +0 -15
  318. package/dist/paths.js +0 -114
  319. package/dist/trains/protocol.js +0 -99
  320. package/dist/trains/supervisor.js +0 -210
  321. package/dist/tunnel.js +0 -102
  322. package/docs/broker.md +0 -166
  323. package/docs/monitor.md +0 -241
  324. package/docs/uri-scheme.md +0 -127
  325. package/examples/README.md +0 -32
  326. package/examples/telegram.ts +0 -121
  327. package/skills/metro/SKILL.md +0 -110
@@ -1,97 +0,0 @@
1
- /** Daemon: supervises ~/.metro/trains/*, multiplexes their stdout to one JSON event stream, */
2
- /** routes outbound `forward-call` IPC back to trains' stdin. Two builtin event sources stay */
3
- /** in core: the HTTP webhook receiver + cross-user `notify` IPC. */
4
- import { join } from 'node:path';
5
- import pkg from '../package.json' with { type: 'json' };
6
- import { Line } from './lines.js';
7
- import { CodexRC } from './codex-rc/client.js';
8
- import { startIpcServer, stopIpcServer } from './ipc.js';
9
- import { mintId, noteUserFromLine, selfLine, userSelf } from './history.js';
10
- import { errMsg, log } from './log.js';
11
- import { acquireLock, loadMetroEnv, STATE_DIR } from './paths.js';
12
- import { setCodexSessionId } from './local-identity.js';
13
- import { loadTunnelConfig, Tunnel, webhookPort } from './tunnel.js';
14
- import { TrainSupervisor, TRAINS_DIR } from './trains/supervisor.js';
15
- import { makeEmit, startWebhookServer, trainEventToHistoryEntry } from './dispatcher/server.js';
16
- loadMetroEnv();
17
- acquireLock(join(STATE_DIR, '.tail-lock'));
18
- const self = userSelf();
19
- log.info({ self, line: selfLine() }, 'user identity');
20
- const seedSelf = () => { const l = selfLine(); if (l)
21
- noteUserFromLine(l); };
22
- seedSelf();
23
- /** Suppress EPIPE so the daemon survives the reader (Monitor) restarting. */
24
- process.stdout.on('error', err => {
25
- if (err.code !== 'EPIPE')
26
- log.warn({ err: errMsg(err) }, 'stdout error');
27
- });
28
- const codexRc = process.env.METRO_CODEX_RC ? new CodexRC(process.env.METRO_CODEX_RC, pkg.version) : null;
29
- codexRc?.onThread(id => { setCodexSessionId(id); seedSelf(); });
30
- codexRc?.start();
31
- const supervisor = new TrainSupervisor();
32
- const emit = makeEmit(codexRc);
33
- supervisor.onTrainEvent((env, train) => {
34
- const entry = trainEventToHistoryEntry(env, train);
35
- if (entry)
36
- emit(entry);
37
- });
38
- let webhookServer = null;
39
- const tunnelCfg = loadTunnelConfig();
40
- const tunnel = tunnelCfg ? new Tunnel(tunnelCfg, webhookPort()) : null;
41
- const ipc = startIpcServer(async (req) => {
42
- if (req.op === 'notify') {
43
- const line = req.line;
44
- emit({
45
- id: mintId(), ts: new Date().toISOString(),
46
- station: Line.station(line) ?? '?', line,
47
- from: (req.from ?? userSelf()), to: line, text: req.text,
48
- });
49
- return { ok: true };
50
- }
51
- if (req.op === 'forward-call') {
52
- try {
53
- const r = await supervisor.call(req.train, req.action, req.args);
54
- return { ok: true, response: r };
55
- }
56
- catch (err) {
57
- return { ok: false, error: errMsg(err) };
58
- }
59
- }
60
- if (req.op === 'trains-list') {
61
- return { ok: true, trains: supervisor.list() };
62
- }
63
- if (req.op === 'train-restart') {
64
- try {
65
- await supervisor.restart(req.name);
66
- return { ok: true };
67
- }
68
- catch (err) {
69
- return { ok: false, error: errMsg(err) };
70
- }
71
- }
72
- return { ok: false, error: `unknown op: ${req.op ?? '(none)'}` };
73
- });
74
- async function main() {
75
- supervisor.start();
76
- webhookServer = await startWebhookServer(emit);
77
- tunnel?.start();
78
- log.info({ codexRc: !!codexRc, tunnel: !!tunnel, trainsDir: TRAINS_DIR }, 'dispatcher ready');
79
- }
80
- let shuttingDown = false;
81
- async function shutdown() {
82
- if (shuttingDown)
83
- return;
84
- shuttingDown = true;
85
- log.info('dispatcher shutting down');
86
- codexRc?.stop();
87
- tunnel?.stop();
88
- await stopIpcServer(ipc).catch(() => { });
89
- if (webhookServer)
90
- await new Promise(r => webhookServer.close(() => r()));
91
- await supervisor.stop();
92
- process.exit(0);
93
- }
94
- process.stdin.on('end', shutdown).on('close', shutdown);
95
- for (const sig of ['SIGINT', 'SIGTERM'])
96
- process.on(sig, shutdown);
97
- await main();
package/dist/history.js DELETED
@@ -1,143 +0,0 @@
1
- /** Append-only JSONL history of every message that flows through metro (inbound + outbound). */
2
- import { randomBytes } from 'node:crypto';
3
- import { appendFileSync, existsSync, readFileSync, writeFileSync } from 'node:fs';
4
- import { join } from 'node:path';
5
- import { errMsg, log } from './log.js';
6
- import { STATE_DIR } from './paths.js';
7
- import { Line } from './lines.js';
8
- import { claudeUserId, claudeSessionId, codexUserId, codexSessionId } from './local-identity.js';
9
- /** Pre-render a chat-bubble line. Direction is derived: from === local agent → outbound (📤), else inbound (📩). */
10
- export function formatDisplay(e) {
11
- const headerFor = (icon, parts) => `**${icon} ${parts.filter(Boolean).join(' · ')}**`;
12
- const body = e.text ?? '';
13
- if (e.station === 'webhook' && !Line.isLocal(e.from)) {
14
- const ev = e.payload
15
- ?.headers?.['x-github-event'] ?? e.payload
16
- ?.headers?.['x-intercom-topic'];
17
- return `${headerFor('🪝', ['webhook', e.lineName, ev])}\n> ${body}`;
18
- }
19
- if (Line.isLocal(e.from)) {
20
- return `${headerFor('📤', [e.station, '→', e.fromName ?? e.to])}\n> ${body}`;
21
- }
22
- return `${headerFor('📩', [e.station, e.fromName ?? e.from, e.lineName])}\n> ${body}`;
23
- }
24
- const FILE = join(STATE_DIR, 'history.jsonl');
25
- /** Mint a universal metro message ID. Short, prefixed, URL-safe. */
26
- export const mintId = () => `msg_${randomBytes(6).toString('base64url')}`;
27
- /** Append one entry as a JSON line. POSIX-atomic for sub-PIPE_BUF writes (we're well under). */
28
- export function appendHistory(entry) {
29
- try {
30
- appendFileSync(FILE, JSON.stringify(entry) + '\n');
31
- }
32
- catch (err) {
33
- log.warn({ err: errMsg(err), path: FILE }, 'history append failed');
34
- }
35
- }
36
- /** Read JSONL, parse, filter (most-recent-first), apply `skip` then `limit`. Empty array if file is missing. */
37
- export function readHistory(filter = {}) {
38
- if (!existsSync(FILE))
39
- return [];
40
- const lines = readFileSync(FILE, 'utf8').split('\n');
41
- const out = [];
42
- const skip = filter.skip ?? 0;
43
- let skipped = 0;
44
- /** Walk backwards so `limit` clamps without scanning the whole file body twice. */
45
- for (let i = lines.length - 1; i >= 0; i--) {
46
- const raw = lines[i].trim();
47
- if (!raw)
48
- continue;
49
- let e;
50
- try {
51
- e = JSON.parse(raw);
52
- }
53
- catch {
54
- continue;
55
- }
56
- if (!matches(e, filter))
57
- continue;
58
- if (skipped < skip) {
59
- skipped++;
60
- continue;
61
- }
62
- out.push(e);
63
- if (filter.limit && out.length >= filter.limit)
64
- break;
65
- }
66
- return out;
67
- }
68
- function matches(e, f) {
69
- if (f.line && e.line !== f.line)
70
- return false;
71
- if (f.station && e.station !== f.station)
72
- return false;
73
- if (f.from && e.from !== f.from)
74
- return false;
75
- if (f.textContains && !(e.text ?? '').toLowerCase().includes(f.textContains.toLowerCase()))
76
- return false;
77
- if (f.since && new Date(e.ts) < f.since)
78
- return false;
79
- return true;
80
- }
81
- /** The current user's **participant** URI for `from`/`to`. Precedence: METRO_FROM > runtime env > generic. */
82
- export function userSelf() {
83
- const explicit = process.env.METRO_FROM;
84
- if (explicit)
85
- return explicit;
86
- if (process.env.CLAUDECODE)
87
- return Line.user('claude', claudeUserId());
88
- if (process.env.METRO_CODEX_RC || process.env.CODEX_HOME)
89
- return Line.user('codex', codexUserId());
90
- return 'metro://user';
91
- }
92
- /** The current user's **line** URI `<user-id>/<session>`. Null until session is known (rc thread pending). */
93
- export function selfLine() {
94
- if (process.env.CLAUDECODE) {
95
- const s = claudeSessionId();
96
- return s ? Line.claude(claudeUserId(), s) : null;
97
- }
98
- if (process.env.METRO_CODEX_RC || process.env.CODEX_HOME) {
99
- const s = codexSessionId();
100
- return s ? Line.codex(codexUserId(), s) : null;
101
- }
102
- return null;
103
- }
104
- /* ──────────── user-registry: append-only (station, userId, sessions[]) tuples ──────────── */
105
- const REGISTRY_FILE = join(STATE_DIR, 'user-registry.json');
106
- function readRegistry() {
107
- if (!existsSync(REGISTRY_FILE))
108
- return {};
109
- try {
110
- return JSON.parse(readFileSync(REGISTRY_FILE, 'utf8'));
111
- }
112
- catch (err) {
113
- log.warn({ err: errMsg(err) }, 'user-registry: malformed, resetting');
114
- return {};
115
- }
116
- }
117
- function record(station, userId, sessionId) {
118
- const reg = readRegistry();
119
- const rows = (reg[station] ??= []);
120
- let row = rows.find(r => r.userId === userId);
121
- if (!row) {
122
- row = { userId, sessions: [], lastSeen: '' };
123
- rows.push(row);
124
- }
125
- if (sessionId && !row.sessions.includes(sessionId))
126
- row.sessions.push(sessionId);
127
- row.lastSeen = new Date().toISOString();
128
- try {
129
- writeFileSync(REGISTRY_FILE, JSON.stringify(reg, null, 2));
130
- }
131
- catch (err) {
132
- log.warn({ err: errMsg(err) }, 'user-registry: write failed');
133
- }
134
- }
135
- /** Scan a line URI for `(station, userId, sessionId)` and record it. No-op on non-user or participant URIs. */
136
- export function noteUserFromLine(line) {
137
- const station = Line.station(line);
138
- if (station !== 'claude' && station !== 'codex')
139
- return;
140
- const p = station === 'claude' ? Line.parseClaude(line) : Line.parseCodex(line);
141
- if (p)
142
- record(station, p.userId, p.sessionId);
143
- }
package/dist/ipc.js DELETED
@@ -1,90 +0,0 @@
1
- /** Unix-socket IPC: `notify` re-emits a cross-user message, `forward-call` reaches a train's */
2
- /** stdin and awaits its response, `trains-list` snapshots supervisor state. */
3
- import { createConnection, createServer } from 'node:net';
4
- import { existsSync, unlinkSync } from 'node:fs';
5
- import { join } from 'node:path';
6
- import { errMsg, log } from './log.js';
7
- import { STATE_DIR } from './paths.js';
8
- const SOCKET_PATH = join(STATE_DIR, 'metro.sock');
9
- export function startIpcServer(handler) {
10
- if (existsSync(SOCKET_PATH)) {
11
- try {
12
- unlinkSync(SOCKET_PATH);
13
- }
14
- catch { /* ignore */ }
15
- }
16
- /** allowHalfOpen: any `await` in the handler races Node's auto-end-on-client-FIN, dropping the response. */
17
- const server = createServer({ allowHalfOpen: true }, s => handleConnection(s, handler));
18
- server.on('error', err => log.warn({ err: errMsg(err) }, 'ipc server error'));
19
- server.listen(SOCKET_PATH, () => log.debug({ path: SOCKET_PATH }, 'ipc socket listening'));
20
- return server;
21
- }
22
- export async function stopIpcServer(server) {
23
- await new Promise(resolve => server.close(() => resolve()));
24
- try {
25
- if (existsSync(SOCKET_PATH))
26
- unlinkSync(SOCKET_PATH);
27
- }
28
- catch { /* ignore */ }
29
- }
30
- async function handleConnection(socket, handler) {
31
- /** Newline-delimited request/response. Avoids races between `end()` writes and FIN under Bun. */
32
- let buf = '';
33
- socket.setEncoding('utf8');
34
- socket.on('data', async (chunk) => {
35
- buf += chunk;
36
- const nl = buf.indexOf('\n');
37
- if (nl === -1)
38
- return;
39
- const line = buf.slice(0, nl).trim();
40
- buf = buf.slice(nl + 1);
41
- let resp;
42
- try {
43
- const req = JSON.parse(line);
44
- resp = await handler(req);
45
- }
46
- catch (err) {
47
- resp = { ok: false, error: errMsg(err) };
48
- }
49
- socket.write(JSON.stringify(resp) + '\n');
50
- socket.end();
51
- });
52
- socket.on('error', err => log.debug({ err: errMsg(err) }, 'ipc connection error'));
53
- }
54
- /** CLI-side: send one request, get one response. Throws if the daemon isn't running. */
55
- export function ipcCall(req, timeoutMs = 60_000) {
56
- return new Promise((resolve, reject) => {
57
- if (!existsSync(SOCKET_PATH)) {
58
- reject(new Error('metro daemon is not running (start it with `metro`)'));
59
- return;
60
- }
61
- const socket = createConnection({ path: SOCKET_PATH });
62
- let buf = '';
63
- const timer = setTimeout(() => {
64
- socket.destroy();
65
- reject(new Error(`ipc timeout after ${timeoutMs}ms`));
66
- }, timeoutMs);
67
- socket.on('connect', () => { socket.write(JSON.stringify(req) + '\n'); });
68
- socket.on('data', chunk => {
69
- buf += chunk.toString('utf8');
70
- const nl = buf.indexOf('\n');
71
- if (nl === -1)
72
- return;
73
- clearTimeout(timer);
74
- const line = buf.slice(0, nl).trim();
75
- socket.end();
76
- try {
77
- resolve(JSON.parse(line));
78
- }
79
- catch (err) {
80
- reject(new Error(`ipc bad response: ${errMsg(err)}`));
81
- }
82
- });
83
- socket.on('end', () => {
84
- clearTimeout(timer);
85
- if (!buf)
86
- reject(new Error('ipc connection closed without response'));
87
- });
88
- socket.on('error', err => { clearTimeout(timer); reject(err); });
89
- });
90
- }
package/dist/lines.js DELETED
@@ -1,54 +0,0 @@
1
- /** Line URI helpers. The whole metro:// vocabulary. */
2
- export const asLine = (s) => s;
3
- const PREFIX = 'metro://';
4
- const build = (station, ...seg) => asLine(`${PREFIX}${station}/${seg.map(String).join('/')}`);
5
- /** Shared parser for `metro://{claude,codex}/<userId>/<sessionId>`. Skips the `/user/…` participant URI. */
6
- function parseLocalSession(line, station) {
7
- const p = Line.parse(line);
8
- if (p?.station !== station || p.path[0] === 'user' || p.path.length < 2)
9
- return null;
10
- return { userId: p.path[0], sessionId: p.path[1] };
11
- }
12
- /** URI helpers. Lives on a const that doubles as the `Line` type's value-side namespace. */
13
- export const Line = {
14
- discord: (channelId) => build('discord', channelId),
15
- telegram: (chatId, topicId) => topicId !== undefined ? build('telegram', chatId, topicId) : build('telegram', chatId),
16
- claude: (orgId, sessionId) => build('claude', orgId, sessionId),
17
- codex: (accountId, threadId) => build('codex', accountId, threadId),
18
- webhook: (endpointId) => build('webhook', endpointId),
19
- /** Participant URI — `metro://<station>/user/<id>`. */
20
- user: (station, id) => build(station, 'user', id),
21
- parse(line) {
22
- if (!line.startsWith(PREFIX))
23
- return null;
24
- const rest = line.slice(PREFIX.length);
25
- const slash = rest.indexOf('/');
26
- if (slash <= 0)
27
- return null;
28
- const path = rest.slice(slash + 1).split('/').filter(Boolean);
29
- return path.length ? { station: rest.slice(0, slash), path } : null;
30
- },
31
- station: (line) => Line.parse(line)?.station ?? null,
32
- parseTelegram(line) {
33
- const p = Line.parse(line);
34
- if (p?.station !== 'telegram')
35
- return null;
36
- const chatId = Number(p.path[0]);
37
- if (!Number.isFinite(chatId))
38
- return null;
39
- if (p.path.length === 1)
40
- return { chatId };
41
- const topicId = Number(p.path[1]);
42
- return Number.isFinite(topicId) ? { chatId, topicId } : null;
43
- },
44
- parseClaude: (line) => parseLocalSession(line, 'claude'),
45
- parseCodex: (line) => parseLocalSession(line, 'codex'),
46
- parseWebhook(line) {
47
- const p = Line.parse(line);
48
- return p?.station === 'webhook' && p.path.length === 1 ? p.path[0] : null;
49
- },
50
- isLocal: (line) => {
51
- const s = Line.station(line);
52
- return s === 'claude' || s === 'codex';
53
- },
54
- };
@@ -1,80 +0,0 @@
1
- /** Resolve the local user identity for Claude Code / Codex hosts — used to mint */
2
- /** `metro://claude/<orgId>/<sessionId>` and `metro://codex/<accountId>/<threadId>` URIs. */
3
- import { execFileSync } from 'node:child_process';
4
- import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
5
- import { homedir } from 'node:os';
6
- import { dirname, join } from 'node:path';
7
- import { STATE_DIR } from './paths.js';
8
- const TTL_MS = 5_000;
9
- /** Memoize an account-id resolver for TTL_MS to avoid hammering `claude auth` / re-reading auth.json. */
10
- function memo(loader) {
11
- let cache = null;
12
- return () => {
13
- if (cache && Date.now() - cache.at < TTL_MS)
14
- return cache.id;
15
- const id = loader();
16
- cache = { id, at: Date.now() };
17
- return id;
18
- };
19
- }
20
- const claudeAccountId = memo(() => {
21
- let raw;
22
- try {
23
- raw = execFileSync('claude', ['auth', 'status', '--json'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
24
- }
25
- catch (e) {
26
- throw new Error(`metro: failed to run 'claude auth status --json' — is Claude Code installed? (${e.message})`);
27
- }
28
- let p;
29
- try {
30
- p = JSON.parse(raw);
31
- }
32
- catch {
33
- throw new Error(`metro: 'claude auth status --json' returned non-JSON: ${raw.slice(0, 200)}`);
34
- }
35
- if (!p.loggedIn || !p.orgId)
36
- throw new Error('metro: Claude Code is not logged in — run \'claude auth login\'');
37
- return p.orgId;
38
- });
39
- const codexAccountId = memo(() => {
40
- const path = join(process.env.CODEX_HOME || join(homedir(), '.codex'), 'auth.json');
41
- let raw;
42
- try {
43
- raw = readFileSync(path, 'utf8');
44
- }
45
- catch (e) {
46
- throw new Error(`metro: failed to read ${path} — is Codex logged in? (${e.message})`);
47
- }
48
- let p;
49
- try {
50
- p = JSON.parse(raw);
51
- }
52
- catch {
53
- throw new Error(`metro: ${path} is not valid JSON`);
54
- }
55
- const id = p.tokens?.account_id;
56
- if (!id)
57
- throw new Error(`metro: no Codex account_id in ${path} (auth_mode=${p.auth_mode ?? 'unknown'}) — sign in with 'codex login' (ChatGPT mode required)`);
58
- return id;
59
- });
60
- export const claudeUserId = () => process.env.METRO_USER_ID || claudeAccountId();
61
- export const codexUserId = () => process.env.METRO_USER_ID || codexAccountId();
62
- export const claudeSessionId = () => process.env.METRO_USER_SESSION_ID || process.env.CLAUDE_CODE_SESSION_ID || null;
63
- const CODEX_SESSION_FILE = join(STATE_DIR, 'codex-session-id');
64
- export function codexSessionId() {
65
- if (process.env.METRO_USER_SESSION_ID)
66
- return process.env.METRO_USER_SESSION_ID;
67
- try {
68
- return readFileSync(CODEX_SESSION_FILE, 'utf8').trim() || null;
69
- }
70
- catch {
71
- return null;
72
- }
73
- }
74
- export function setCodexSessionId(threadId) {
75
- try {
76
- mkdirSync(dirname(CODEX_SESSION_FILE), { recursive: true });
77
- writeFileSync(CODEX_SESSION_FILE, threadId ?? '');
78
- }
79
- catch { /* CLI just won't have a session segment */ }
80
- }
package/dist/log.js DELETED
@@ -1,15 +0,0 @@
1
- /** Pino → stderr. TTY → pino-pretty (colorized, hostname/pid stripped); else JSON. */
2
- import pino from 'pino';
3
- import pinoPretty from 'pino-pretty';
4
- const stream = process.stderr.isTTY
5
- ? pinoPretty({ colorize: true, translateTime: 'HH:MM:ss', ignore: 'pid,hostname,name', destination: 2 })
6
- : pino.destination(2);
7
- /** `base: { name }` strips pino's default pid+hostname from JSON output too (not just from the TTY pretty stream). */
8
- export const log = pino({ base: { name: 'metro' }, level: process.env.METRO_LOG_LEVEL || 'info' }, stream);
9
- export const errMsg = (err) => {
10
- if (err instanceof Error)
11
- return err.message;
12
- if (err && typeof err === 'object' && 'message' in err)
13
- return String(err.message);
14
- return String(err);
15
- };
package/dist/paths.js DELETED
@@ -1,114 +0,0 @@
1
- import { chmodSync, existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
2
- import { homedir } from 'node:os';
3
- import { dirname, join } from 'node:path';
4
- import { errMsg, log } from './log.js';
5
- export const STATE_DIR = process.env.METRO_STATE_DIR ?? join(homedir(), '.cache', 'metro');
6
- mkdirSync(STATE_DIR, { recursive: true });
7
- const CONFIG_DIR = process.env.METRO_CONFIG_DIR ?? join(process.env.XDG_CONFIG_HOME || join(homedir(), '.config'), 'metro');
8
- export const CONFIG_ENV_FILE = join(CONFIG_DIR, '.env');
9
- /** Train-owned env file. Trains read their tokens from here (passed through via process.env). */
10
- const TRAINS_ENV_FILE = join(homedir(), '.metro', '.env');
11
- const LINE_RE = /^\s*([A-Za-z_]\w*)\s*=\s*(.*?)\s*$/;
12
- const QUOTED_RE = /^(['"])(.*)\1$/;
13
- export function readDotenv(path) {
14
- if (!existsSync(path))
15
- return {};
16
- const out = {};
17
- for (const line of readFileSync(path, 'utf8').split('\n')) {
18
- const m = line.match(LINE_RE);
19
- if (m)
20
- out[m[1]] = m[2].replace(QUOTED_RE, '$2');
21
- }
22
- return out;
23
- }
24
- export function writeDotenv(path, env) {
25
- mkdirSync(dirname(path), { recursive: true });
26
- writeFileSync(path, Object.entries(env).map(([k, v]) => `${k}=${v}`).join('\n') + '\n');
27
- chmodSync(path, 0o600);
28
- }
29
- /** Precedence: process.env > cwd/.env > ~/.metro/.env > $METRO_CONFIG_DIR/.env. First-set wins. */
30
- /** ~/.metro/.env is the canonical location for train credentials. */
31
- export function loadMetroEnv() {
32
- for (const path of [join(process.cwd(), '.env'), TRAINS_ENV_FILE, CONFIG_ENV_FILE]) {
33
- for (const [k, v] of Object.entries(readDotenv(path))) {
34
- if (process.env[k] === undefined)
35
- process.env[k] = v;
36
- }
37
- }
38
- }
39
- /** Singleton pidfile. Exits if another instance owns it; reclaims stale locks. */
40
- export function acquireLock(lockFile) {
41
- if (existsSync(lockFile)) {
42
- const pid = Number(readFileSync(lockFile, 'utf8').trim());
43
- try {
44
- if (Number.isInteger(pid) && pid > 0) {
45
- process.kill(pid, 0);
46
- log.info({ pid }, 'another `metro` is running; exiting');
47
- process.exit(0);
48
- }
49
- }
50
- catch { /* stale */ }
51
- try {
52
- unlinkSync(lockFile);
53
- }
54
- catch { /* ignore */ }
55
- }
56
- writeFileSync(lockFile, String(process.pid));
57
- process.on('exit', () => { try {
58
- if (readFileSync(lockFile, 'utf8').trim() === String(process.pid))
59
- unlinkSync(lockFile);
60
- }
61
- catch { /* ignore */ } });
62
- }
63
- const cacheFile = join(STATE_DIR, 'lines.json');
64
- const FLUSH_DELAY_MS = 5_000;
65
- let cache = null;
66
- let dirty = false;
67
- let flushTimer = null;
68
- function readCache() {
69
- if (cache)
70
- return cache;
71
- if (!existsSync(cacheFile))
72
- return cache = {};
73
- try {
74
- cache = JSON.parse(readFileSync(cacheFile, 'utf8'));
75
- }
76
- catch (err) {
77
- log.warn({ err: errMsg(err), path: cacheFile }, 'lines cache read failed; treating as empty');
78
- cache = {};
79
- }
80
- return cache;
81
- }
82
- function flush() {
83
- if (!dirty || !cache)
84
- return;
85
- try {
86
- writeFileSync(cacheFile, JSON.stringify(cache, null, 2));
87
- dirty = false;
88
- }
89
- catch (err) {
90
- log.warn({ err: errMsg(err), path: cacheFile }, 'lines cache write failed');
91
- }
92
- }
93
- process.on('exit', flush);
94
- export function noteSeen(line, name) {
95
- const c = readCache();
96
- const entry = c[line] ??= { createdAt: new Date().toISOString() };
97
- entry.lastSeenAt = new Date().toISOString();
98
- if (name && entry.name !== name)
99
- entry.name = name;
100
- dirty = true;
101
- if (!flushTimer)
102
- flushTimer = setTimeout(() => { flushTimer = null; flush(); }, FLUSH_DELAY_MS);
103
- }
104
- export const listLines = () => Object.entries(readCache()).map(([line, entry]) => ({ line: line, entry }));
105
- /** Bot identity cache: `{discord: "<userId>", telegram: "<userId>"}`. Trains may populate this. */
106
- const botIdsFile = join(STATE_DIR, 'bot-ids.json');
107
- export const readBotIds = () => {
108
- try {
109
- return existsSync(botIdsFile) ? JSON.parse(readFileSync(botIdsFile, 'utf8')) : {};
110
- }
111
- catch {
112
- return {};
113
- }
114
- };