@stage-labs/metro 0.1.0-beta.8 → 0.1.0-beta.80

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 (282) hide show
  1. package/dist/api.js +14 -0
  2. package/dist/claude-settings.js +40 -0
  3. package/dist/claude.js +107 -0
  4. package/dist/cli.js +101 -0
  5. package/dist/control.js +74 -0
  6. package/dist/hold.js +211 -0
  7. package/dist/local.js +93 -0
  8. package/dist/node-name.js +71 -0
  9. package/dist/plugin.js +80 -0
  10. package/dist/provider-flags.js +9 -0
  11. package/dist/runtime-install.js +87 -0
  12. package/dist/runtime.js +74 -0
  13. package/dist/serve.js +146 -0
  14. package/dist/service.js +242 -0
  15. package/dist/tail.js +119 -0
  16. package/dist/update.js +45 -0
  17. package/dist/version.js +97 -0
  18. package/package.json +14 -25
  19. package/runtime/node_modules/@metro-labs/core/package.json +43 -0
  20. package/runtime/node_modules/@metro-labs/core/src/address.ts +6 -0
  21. package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
  22. package/runtime/node_modules/@metro-labs/core/src/events.ts +120 -0
  23. package/runtime/node_modules/@metro-labs/core/src/identity.ts +7 -0
  24. package/runtime/node_modules/@metro-labs/core/src/ids.ts +21 -0
  25. package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
  26. package/runtime/node_modules/@metro-labs/core/src/lines.ts +82 -0
  27. package/runtime/node_modules/@metro-labs/core/src/log.ts +42 -0
  28. package/runtime/node_modules/@metro-labs/core/src/protocol.ts +226 -0
  29. package/runtime/node_modules/@metro-labs/core/src/secure-fs.ts +57 -0
  30. package/runtime/node_modules/@metro-labs/core/src/station-names.ts +12 -0
  31. package/runtime/node_modules/@metro-labs/core/src/stations/account-store.ts +60 -0
  32. package/runtime/node_modules/@metro-labs/core/src/stations/attachments.ts +196 -0
  33. package/runtime/node_modules/@metro-labs/core/src/stations/messaging-normalize.ts +88 -0
  34. package/runtime/node_modules/@metro-labs/core/src/stations/station-runtime.ts +64 -0
  35. package/runtime/node_modules/@metro-labs/core/src/stations/types.ts +107 -0
  36. package/runtime/node_modules/@metro-labs/core/src/str.ts +5 -0
  37. package/runtime/node_modules/@metro-labs/core/src/train-error.ts +53 -0
  38. package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
  39. package/runtime/node_modules/@metro-labs/daemon/package.json +47 -0
  40. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-attach.ts +19 -0
  41. package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +311 -0
  42. package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +43 -0
  43. package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +302 -0
  44. package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +111 -0
  45. package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +329 -0
  46. package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +155 -0
  47. package/runtime/node_modules/@metro-labs/daemon/src/agents/keys.ts +45 -0
  48. package/runtime/node_modules/@metro-labs/daemon/src/agents/map.ts +84 -0
  49. package/runtime/node_modules/@metro-labs/daemon/src/agents/scope.ts +64 -0
  50. package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +176 -0
  51. package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +39 -0
  52. package/runtime/node_modules/@metro-labs/daemon/src/boot/crash-guard.ts +49 -0
  53. package/runtime/node_modules/@metro-labs/daemon/src/boot/local-owner.ts +14 -0
  54. package/runtime/node_modules/@metro-labs/daemon/src/boot/paths.ts +106 -0
  55. package/runtime/node_modules/@metro-labs/daemon/src/channels/addressed.ts +25 -0
  56. package/runtime/node_modules/@metro-labs/daemon/src/channels/dedupe.ts +24 -0
  57. package/runtime/node_modules/@metro-labs/daemon/src/channels/inbound.ts +377 -0
  58. package/runtime/node_modules/@metro-labs/daemon/src/channels/media-note.ts +85 -0
  59. package/runtime/node_modules/@metro-labs/daemon/src/channels/pending.ts +75 -0
  60. package/runtime/node_modules/@metro-labs/daemon/src/channels/relay.ts +129 -0
  61. package/runtime/node_modules/@metro-labs/daemon/src/channels/webhook-note.ts +51 -0
  62. package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +148 -0
  63. package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +329 -0
  64. package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +167 -0
  65. package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +117 -0
  66. package/runtime/node_modules/@metro-labs/daemon/src/connectors/api.ts +307 -0
  67. package/runtime/node_modules/@metro-labs/daemon/src/connectors/cli-api.ts +63 -0
  68. package/runtime/node_modules/@metro-labs/daemon/src/connectors/config.ts +144 -0
  69. package/runtime/node_modules/@metro-labs/daemon/src/connectors/json.ts +21 -0
  70. package/runtime/node_modules/@metro-labs/daemon/src/connectors/model.ts +69 -0
  71. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-client.ts +159 -0
  72. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-discovery.ts +117 -0
  73. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-pending.ts +65 -0
  74. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth-routes.ts +157 -0
  75. package/runtime/node_modules/@metro-labs/daemon/src/connectors/oauth.ts +127 -0
  76. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-target.ts +39 -0
  77. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +295 -0
  78. package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +277 -0
  79. package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +98 -0
  80. package/runtime/node_modules/@metro-labs/daemon/src/connectors/url.ts +70 -0
  81. package/runtime/node_modules/@metro-labs/daemon/src/connectors/verify.ts +330 -0
  82. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-grant.ts +99 -0
  83. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-owner.ts +32 -0
  84. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-serve.ts +121 -0
  85. package/runtime/node_modules/@metro-labs/daemon/src/files/upload-api.ts +294 -0
  86. package/runtime/node_modules/@metro-labs/daemon/src/files/upload-store.ts +181 -0
  87. package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +252 -0
  88. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +231 -0
  89. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-device.ts +91 -0
  90. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +288 -0
  91. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +203 -0
  92. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +220 -0
  93. package/runtime/node_modules/@metro-labs/daemon/src/gateway/eventstream.ts +123 -0
  94. package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +182 -0
  95. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +197 -0
  96. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +195 -0
  97. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +198 -0
  98. package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +40 -0
  99. package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +17 -0
  100. package/runtime/node_modules/@metro-labs/daemon/src/mcp/accounts.ts +137 -0
  101. package/runtime/node_modules/@metro-labs/daemon/src/mcp/call-tools.ts +216 -0
  102. package/runtime/node_modules/@metro-labs/daemon/src/mcp/channel-owner.ts +29 -0
  103. package/runtime/node_modules/@metro-labs/daemon/src/mcp/ctx.ts +62 -0
  104. package/runtime/node_modules/@metro-labs/daemon/src/mcp/event-store.ts +91 -0
  105. package/runtime/node_modules/@metro-labs/daemon/src/mcp/frame-scope.ts +21 -0
  106. package/runtime/node_modules/@metro-labs/daemon/src/mcp/group-tools.ts +129 -0
  107. package/runtime/node_modules/@metro-labs/daemon/src/mcp/index.ts +191 -0
  108. package/runtime/node_modules/@metro-labs/daemon/src/mcp/member-tools.ts +72 -0
  109. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +66 -0
  110. package/runtime/node_modules/@metro-labs/daemon/src/mcp/raw-get-stream.ts +207 -0
  111. package/runtime/node_modules/@metro-labs/daemon/src/mcp/request-identity.ts +47 -0
  112. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-registry.ts +172 -0
  113. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-route.ts +43 -0
  114. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session.ts +215 -0
  115. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-dispatch.ts +215 -0
  116. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-schemas.ts +400 -0
  117. package/runtime/node_modules/@metro-labs/daemon/src/mcp/upload-tool.ts +66 -0
  118. package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +237 -0
  119. package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +389 -0
  120. package/runtime/node_modules/@metro-labs/daemon/src/routes/http.ts +390 -0
  121. package/runtime/node_modules/@metro-labs/daemon/src/routes/identity.ts +54 -0
  122. package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +187 -0
  123. package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +60 -0
  124. package/runtime/node_modules/@metro-labs/daemon/src/routes/session.ts +29 -0
  125. package/runtime/node_modules/@metro-labs/daemon/src/server/control.ts +64 -0
  126. package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +61 -0
  127. package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +116 -0
  128. package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
  129. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-inline.ts +100 -0
  130. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-interactive.ts +161 -0
  131. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-resolve.ts +202 -0
  132. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-session.ts +280 -0
  133. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-xmtp.ts +111 -0
  134. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach.ts +184 -0
  135. package/runtime/node_modules/@metro-labs/daemon/src/stations/materialize.ts +248 -0
  136. package/runtime/node_modules/@metro-labs/daemon/src/stations/registry.ts +35 -0
  137. package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +82 -0
  138. package/runtime/node_modules/@metro-labs/daemon/src/stations/supervisor-io.ts +97 -0
  139. package/runtime/node_modules/@metro-labs/daemon/src/stations/supervisor.ts +320 -0
  140. package/runtime/node_modules/@metro-labs/daemon/src/stations/train-call.ts +22 -0
  141. package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +71 -0
  142. package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +123 -0
  143. package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +40 -0
  144. package/runtime/node_modules/@metro-labs/discord-bot/package.json +28 -0
  145. package/runtime/node_modules/@metro-labs/discord-bot/src/accounts.ts +118 -0
  146. package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +388 -0
  147. package/runtime/node_modules/@metro-labs/discord-bot/src/api-base.ts +1 -0
  148. package/runtime/node_modules/@metro-labs/discord-bot/src/attachments.ts +29 -0
  149. package/runtime/node_modules/@metro-labs/discord-bot/src/format.ts +220 -0
  150. package/runtime/node_modules/@metro-labs/discord-bot/src/group-actions.ts +50 -0
  151. package/runtime/node_modules/@metro-labs/discord-bot/src/group.ts +115 -0
  152. package/runtime/node_modules/@metro-labs/discord-bot/src/index.ts +127 -0
  153. package/runtime/node_modules/@metro-labs/discord-bot/src/members.ts +215 -0
  154. package/runtime/node_modules/@metro-labs/discord-bot/src/send-files.ts +43 -0
  155. package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +19 -0
  156. package/runtime/node_modules/@metro-labs/discord-bot/src/verify.ts +82 -0
  157. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-speak.ts +195 -0
  158. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-transcribe.ts +292 -0
  159. package/runtime/node_modules/@metro-labs/discord-bot/src/voice.ts +197 -0
  160. package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +5 -0
  161. package/runtime/node_modules/@metro-labs/http/package.json +33 -0
  162. package/runtime/node_modules/@metro-labs/http/src/api-error.ts +8 -0
  163. package/runtime/node_modules/@metro-labs/http/src/api-http.ts +95 -0
  164. package/runtime/node_modules/@metro-labs/http/src/cors.ts +29 -0
  165. package/runtime/node_modules/@metro-labs/http/src/identity-key.ts +33 -0
  166. package/runtime/node_modules/@metro-labs/http/src/identity-registry.ts +13 -0
  167. package/runtime/node_modules/@metro-labs/http/src/mode-api.ts +32 -0
  168. package/runtime/node_modules/@metro-labs/http/src/return-to.ts +21 -0
  169. package/runtime/node_modules/@metro-labs/http/src/signed-identity.ts +36 -0
  170. package/runtime/node_modules/@metro-labs/telegram/package.json +26 -0
  171. package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +80 -0
  172. package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +254 -0
  173. package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +87 -0
  174. package/runtime/node_modules/@metro-labs/telegram/src/client.ts +77 -0
  175. package/runtime/node_modules/@metro-labs/telegram/src/format.ts +156 -0
  176. package/runtime/node_modules/@metro-labs/telegram/src/group.ts +261 -0
  177. package/runtime/node_modules/@metro-labs/telegram/src/history.ts +52 -0
  178. package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +78 -0
  179. package/runtime/node_modules/@metro-labs/telegram/src/index.ts +46 -0
  180. package/runtime/node_modules/@metro-labs/telegram/src/login.ts +166 -0
  181. package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +80 -0
  182. package/runtime/node_modules/@metro-labs/telegram/src/members.ts +75 -0
  183. package/runtime/node_modules/@metro-labs/telegram/src/normalize.ts +22 -0
  184. package/runtime/node_modules/@metro-labs/telegram/src/reactions.ts +167 -0
  185. package/runtime/node_modules/@metro-labs/telegram/src/station.ts +24 -0
  186. package/runtime/node_modules/@metro-labs/telegram/src/types.ts +7 -0
  187. package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +1 -0
  188. package/runtime/node_modules/@metro-labs/telegram-bot/package.json +25 -0
  189. package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +120 -0
  190. package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +295 -0
  191. package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +128 -0
  192. package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +201 -0
  193. package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +109 -0
  194. package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +166 -0
  195. package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +47 -0
  196. package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +17 -0
  197. package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +58 -0
  198. package/runtime/node_modules/@metro-labs/telegram-bot/src/verify.ts +38 -0
  199. package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +3 -0
  200. package/runtime/node_modules/@metro-labs/webhook/package.json +23 -0
  201. package/runtime/node_modules/@metro-labs/webhook/src/station.ts +37 -0
  202. package/runtime/node_modules/@metro-labs/whatsapp/package.json +27 -0
  203. package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +66 -0
  204. package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +101 -0
  205. package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +178 -0
  206. package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +72 -0
  207. package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +129 -0
  208. package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +327 -0
  209. package/runtime/node_modules/@metro-labs/whatsapp/src/delivery.ts +49 -0
  210. package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +138 -0
  211. package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +57 -0
  212. package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +40 -0
  213. package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +59 -0
  214. package/runtime/node_modules/@metro-labs/whatsapp/src/logger.ts +60 -0
  215. package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +176 -0
  216. package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +84 -0
  217. package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +22 -0
  218. package/runtime/node_modules/@metro-labs/whatsapp/src/outbox.ts +38 -0
  219. package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +185 -0
  220. package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +17 -0
  221. package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +98 -0
  222. package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +6 -0
  223. package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +5 -0
  224. package/runtime/node_modules/@metro-labs/xmtp/package.json +33 -0
  225. package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +112 -0
  226. package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +110 -0
  227. package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +299 -0
  228. package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +157 -0
  229. package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +87 -0
  230. package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +375 -0
  231. package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +107 -0
  232. package/runtime/node_modules/@metro-labs/xmtp/src/codecs.ts +171 -0
  233. package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +239 -0
  234. package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +55 -0
  235. package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +335 -0
  236. package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +80 -0
  237. package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +34 -0
  238. package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +56 -0
  239. package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +33 -0
  240. package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +125 -0
  241. package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +157 -0
  242. package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +40 -0
  243. package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +349 -0
  244. package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +13 -0
  245. package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +126 -0
  246. package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +212 -0
  247. package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +90 -0
  248. package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +84 -0
  249. package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +53 -0
  250. package/runtime/runtime.json +3 -0
  251. package/runtime/server.ts +1 -0
  252. package/runtime/stations.json +36 -0
  253. package/runtime/trains/.keep +0 -0
  254. package/LICENSE +0 -21
  255. package/README.md +0 -249
  256. package/dist/cache.js +0 -75
  257. package/dist/cli/actions.js +0 -139
  258. package/dist/cli/config.js +0 -185
  259. package/dist/cli/index.js +0 -177
  260. package/dist/cli/skill.js +0 -62
  261. package/dist/cli/util.js +0 -72
  262. package/dist/cli/webhook.js +0 -83
  263. package/dist/codex-rc.js +0 -245
  264. package/dist/dispatcher.js +0 -122
  265. package/dist/history.js +0 -99
  266. package/dist/ipc.js +0 -72
  267. package/dist/log.js +0 -15
  268. package/dist/paths.js +0 -68
  269. package/dist/registry.js +0 -48
  270. package/dist/stations/claude.js +0 -45
  271. package/dist/stations/codex.js +0 -68
  272. package/dist/stations/discord.js +0 -200
  273. package/dist/stations/index.js +0 -133
  274. package/dist/stations/telegram-md.js +0 -34
  275. package/dist/stations/telegram-upload.js +0 -113
  276. package/dist/stations/telegram.js +0 -213
  277. package/dist/stations/webhook.js +0 -100
  278. package/dist/tunnel.js +0 -49
  279. package/dist/webhooks.js +0 -40
  280. package/docs/agents.md +0 -216
  281. package/docs/uri-scheme.md +0 -125
  282. package/skills/metro/SKILL.md +0 -249
@@ -0,0 +1,215 @@
1
+ import { errMsg } from '@metro-labs/core/log';
2
+ import type { MemberList, MetroMember } from '@metro-labs/core/stations/types';
3
+ import { rest } from './accounts.js';
4
+
5
+ export interface DiscordRole {
6
+ id: string;
7
+ name: string;
8
+ permissions: string;
9
+ }
10
+
11
+ export interface DiscordUser {
12
+ id: string;
13
+ username?: string;
14
+ global_name?: string | null;
15
+ bot?: boolean;
16
+ }
17
+
18
+ export interface DiscordGuildMember {
19
+ user?: DiscordUser;
20
+ nick?: string | null;
21
+ roles?: string[];
22
+ }
23
+
24
+ const ADMINISTRATOR = 1n << 3n;
25
+ const PAGE = 1000;
26
+
27
+ export interface RoleInfo {
28
+ name: string;
29
+ admin: boolean;
30
+ }
31
+
32
+ function roleIsAdmin(permissions: string): boolean {
33
+ try {
34
+ return (BigInt(permissions) & ADMINISTRATOR) === ADMINISTRATOR;
35
+ } catch {
36
+ return false;
37
+ }
38
+ }
39
+
40
+ export function indexRoles(roles: DiscordRole[]): Map<string, RoleInfo> {
41
+ const out = new Map<string, RoleInfo>();
42
+ for (const r of roles)
43
+ out.set(r.id, { name: r.name, admin: roleIsAdmin(r.permissions) });
44
+ return out;
45
+ }
46
+
47
+ function isAdmin(
48
+ userId: string,
49
+ roleIds: string[],
50
+ roles: Map<string, RoleInfo>,
51
+ ownerId?: string,
52
+ ): boolean {
53
+ if (ownerId !== undefined && userId === ownerId) return true;
54
+ return roleIds.some((id) => roles.get(id)?.admin === true);
55
+ }
56
+
57
+ export function mapGuildMember(
58
+ m: DiscordGuildMember,
59
+ roles: Map<string, RoleInfo>,
60
+ ownerId?: string,
61
+ ): MetroMember | null {
62
+ const user = m.user;
63
+ if (!user?.id) return null;
64
+ const member: MetroMember = { id: user.id };
65
+ if (user.username) member.name = user.username;
66
+ const display = m.nick ?? user.global_name ?? undefined;
67
+ if (display) member.display_name = display;
68
+ const roleIds = m.roles ?? [];
69
+ const roleNames = roleIds
70
+ .map((id) => roles.get(id)?.name)
71
+ .filter((n): n is string => Boolean(n));
72
+ if (roleNames.length) member.roles = roleNames;
73
+ member.is_admin = isAdmin(user.id, roleIds, roles, ownerId);
74
+ member.is_bot = Boolean(user.bot);
75
+ return member;
76
+ }
77
+
78
+ export function mapGuildMembers(
79
+ members: DiscordGuildMember[],
80
+ roles: Map<string, RoleInfo>,
81
+ ownerId?: string,
82
+ ): MetroMember[] {
83
+ return members
84
+ .map((m) => mapGuildMember(m, roles, ownerId))
85
+ .filter((x): x is MetroMember => x !== null);
86
+ }
87
+
88
+ export function mapRecipients(users: DiscordUser[]): MetroMember[] {
89
+ return users
90
+ .filter((u) => Boolean(u?.id))
91
+ .map((u) => {
92
+ const m: MetroMember = { id: u.id };
93
+ if (u.username) m.name = u.username;
94
+ if (u.global_name) m.display_name = u.global_name;
95
+ m.is_bot = Boolean(u.bot);
96
+ return m;
97
+ });
98
+ }
99
+
100
+ async function fetchRoles(
101
+ accountId: string,
102
+ guildId: string,
103
+ ): Promise<Map<string, RoleInfo>> {
104
+ try {
105
+ const roles = await rest<DiscordRole[]>(
106
+ accountId,
107
+ 'GET',
108
+ `/guilds/${guildId}/roles`,
109
+ );
110
+ return indexRoles(roles);
111
+ } catch {
112
+ return new Map();
113
+ }
114
+ }
115
+
116
+ async function fetchOwnerId(
117
+ accountId: string,
118
+ guildId: string,
119
+ ): Promise<string | undefined> {
120
+ try {
121
+ const g = await rest<{ owner_id?: string }>(
122
+ accountId,
123
+ 'GET',
124
+ `/guilds/${guildId}`,
125
+ );
126
+ return g.owner_id;
127
+ } catch {
128
+ return undefined;
129
+ }
130
+ }
131
+
132
+ interface Collected {
133
+ raw: DiscordGuildMember[];
134
+ exhausted: boolean;
135
+ }
136
+
137
+ async function paginate(
138
+ accountId: string,
139
+ guildId: string,
140
+ cap: number,
141
+ ): Promise<Collected> {
142
+ const raw: DiscordGuildMember[] = [];
143
+ let after: string | undefined;
144
+ for (;;) {
145
+ const want = Math.min(PAGE, cap - raw.length);
146
+ if (want <= 0) return { raw, exhausted: false };
147
+ const qs = new URLSearchParams({ limit: String(want) });
148
+ if (after) qs.set('after', after);
149
+ const page = await rest<DiscordGuildMember[]>(
150
+ accountId,
151
+ 'GET',
152
+ `/guilds/${guildId}/members?${qs}`,
153
+ );
154
+ raw.push(...page);
155
+ if (page.length < want) return { raw, exhausted: true };
156
+ after = page[page.length - 1]?.user?.id;
157
+ if (!after) return { raw, exhausted: true };
158
+ }
159
+ }
160
+
161
+ const INTENT_HINT =
162
+ 'Discord bot lacks the privileged GUILD_MEMBERS intent (enable it in the ' +
163
+ 'Developer Portal) or channel access; returning what is reachable.';
164
+
165
+ export async function listGuildMembers(
166
+ accountId: string,
167
+ guildId: string,
168
+ limit?: number,
169
+ ): Promise<MemberList> {
170
+ const cap = Math.min(Math.max(1, limit ?? PAGE), 10_000);
171
+ const roles = await fetchRoles(accountId, guildId);
172
+ const ownerId = await fetchOwnerId(accountId, guildId);
173
+ try {
174
+ const { raw, exhausted } = await paginate(accountId, guildId, cap);
175
+ const members = mapGuildMembers(raw, roles, ownerId);
176
+ return {
177
+ members,
178
+ capability: exhausted
179
+ ? { supported: true, complete: true, total: members.length }
180
+ : {
181
+ supported: true,
182
+ complete: false,
183
+ reason: `truncated at limit ${cap}`,
184
+ },
185
+ };
186
+ } catch (e) {
187
+ const msg = errMsg(e);
188
+ if (/\b40[13]\b/.test(msg))
189
+ return {
190
+ members: [],
191
+ capability: { supported: false, complete: false, reason: INTENT_HINT },
192
+ };
193
+ throw e;
194
+ }
195
+ }
196
+
197
+ export async function discordMembers(
198
+ accountId: string,
199
+ channelId: string,
200
+ limit?: number,
201
+ ): Promise<MemberList> {
202
+ const chan = await rest<{ guild_id?: string; recipients?: DiscordUser[] }>(
203
+ accountId,
204
+ 'GET',
205
+ `/channels/${channelId}`,
206
+ );
207
+ if (!chan.guild_id) {
208
+ const members = mapRecipients(chan.recipients ?? []);
209
+ return {
210
+ members,
211
+ capability: { supported: true, complete: true, total: members.length },
212
+ };
213
+ }
214
+ return listGuildMembers(accountId, chan.guild_id, limit);
215
+ }
@@ -0,0 +1,43 @@
1
+ import { appendFile } from '@metro-labs/core/stations/attachments';
2
+
3
+ export interface OutgoingFile {
4
+ path: string;
5
+ name: string;
6
+ kind: string;
7
+ }
8
+
9
+ const basenameOf = (path: string, index: number): string =>
10
+ path.split('/').pop() ?? `file-${index}`;
11
+
12
+ export function outgoingFiles(
13
+ paths: string[],
14
+ names: string[] | undefined,
15
+ kinds: string[] | undefined,
16
+ ): OutgoingFile[] {
17
+ const out: OutgoingFile[] = [];
18
+ for (let i = 0; i < paths.length; i++) {
19
+ const path = paths[i];
20
+ if (path === undefined || path === '') continue;
21
+ const given = names?.[i];
22
+ out.push({
23
+ path,
24
+ name: given !== undefined && given !== '' ? given : basenameOf(path, i),
25
+ kind: kinds?.[i] ?? 'file',
26
+ });
27
+ }
28
+ return out;
29
+ }
30
+
31
+ export async function appendFiles(
32
+ form: FormData,
33
+ files: OutgoingFile[],
34
+ ): Promise<string[]> {
35
+ const delivered: string[] = [];
36
+ for (let i = 0; i < files.length; i++) {
37
+ const file = files[i];
38
+ if (!file) continue;
39
+ await appendFile(form, `files[${i}]`, file.path, file.name);
40
+ delivered.push(file.kind);
41
+ }
42
+ return delivered;
43
+ }
@@ -0,0 +1,19 @@
1
+ import type { GroupOp, Station, Verb } from '@metro-labs/core/stations/types';
2
+
3
+ export const discordBotStation: Station = {
4
+ name: 'discord-bot',
5
+ hasAccounts: true,
6
+ hasTrain: true,
7
+ messageVerbs: new Set<Verb>([
8
+ 'send',
9
+ 'reply',
10
+ 'react',
11
+ 'unreact',
12
+ 'edit',
13
+ 'delete',
14
+ 'read',
15
+ ]),
16
+ groupOps: new Set<GroupOp>(['create_group', 'add_members', 'remove_members']),
17
+ attachmentMode: 'canonical',
18
+ tools: [],
19
+ };
@@ -0,0 +1,82 @@
1
+ import { API } from './api-base.js';
2
+
3
+ export class DiscordTokenError extends Error {}
4
+
5
+ export interface DiscordBotIdentity {
6
+ userId: string;
7
+ username: string;
8
+ messageContent: boolean;
9
+ }
10
+
11
+ const MESSAGE_CONTENT = 1 << 18;
12
+ const MESSAGE_CONTENT_LIMITED = 1 << 19;
13
+ const TIMEOUT_MS = 10_000;
14
+
15
+ function botFetch(token: string, path: string): Promise<Response> {
16
+ return fetch(`${API}${path}`, {
17
+ headers: {
18
+ authorization: `Bot ${token}`,
19
+ 'user-agent': 'metro-daemon (https://github.com/bonustrack/metro)',
20
+ },
21
+ signal: AbortSignal.timeout(TIMEOUT_MS),
22
+ });
23
+ }
24
+
25
+ async function readJson(res: Response): Promise<Record<string, unknown>> {
26
+ try {
27
+ const body: unknown = await res.json();
28
+ return typeof body === 'object' && body !== null
29
+ ? (body as Record<string, unknown>)
30
+ : {};
31
+ } catch {
32
+ throw new DiscordTokenError('Discord returned a response Metro could not read');
33
+ }
34
+ }
35
+
36
+ async function selfUser(token: string): Promise<Record<string, unknown>> {
37
+ let res: Response;
38
+ try {
39
+ res = await botFetch(token, '/users/@me');
40
+ } catch {
41
+ throw new DiscordTokenError(
42
+ 'could not reach the Discord API to check that bot token',
43
+ );
44
+ }
45
+ if (res.status === 401 || res.status === 403)
46
+ throw new DiscordTokenError('Discord rejected that bot token');
47
+ if (!res.ok)
48
+ throw new DiscordTokenError(
49
+ `Discord answered ${res.status} while checking that bot token`,
50
+ );
51
+ return readJson(res);
52
+ }
53
+
54
+ async function messageContentEnabled(token: string): Promise<boolean> {
55
+ try {
56
+ const res = await botFetch(token, '/applications/@me');
57
+ if (!res.ok) return true;
58
+ const flags = (await readJson(res)).flags;
59
+ if (typeof flags !== 'number') return true;
60
+ return (flags & (MESSAGE_CONTENT | MESSAGE_CONTENT_LIMITED)) !== 0;
61
+ } catch {
62
+ return true;
63
+ }
64
+ }
65
+
66
+ export async function verifyDiscordBotToken(
67
+ token: string,
68
+ ): Promise<DiscordBotIdentity> {
69
+ const me = await selfUser(token);
70
+ const userId = typeof me.id === 'string' ? me.id : '';
71
+ if (userId === '')
72
+ throw new DiscordTokenError('Discord returned no bot identity for that token');
73
+ if (me.bot !== true)
74
+ throw new DiscordTokenError(
75
+ 'that token belongs to a Discord user, not a bot application',
76
+ );
77
+ return {
78
+ userId,
79
+ username: typeof me.username === 'string' ? me.username : '',
80
+ messageContent: await messageContentEnabled(token),
81
+ };
82
+ }
@@ -0,0 +1,195 @@
1
+ import { errMsg } from '@metro-labs/core/log';
2
+ import { spawn } from 'node:child_process';
3
+ import { unlink } from 'node:fs/promises';
4
+ import {
5
+ createAudioPlayer,
6
+ createAudioResource,
7
+ getVoiceConnection,
8
+ entersState,
9
+ AudioPlayerStatus,
10
+ StreamType,
11
+ NoSubscriberBehavior,
12
+ type VoiceConnection,
13
+ } from '@discordjs/voice';
14
+ import type { Client } from 'discord.js';
15
+ import { accountFor, accounts, routeOf } from './accounts.js';
16
+ import { respond } from './wire.js';
17
+
18
+ const TTS_VOICE = 'Samantha';
19
+
20
+ function clientFor(account?: string): { accountId: string; client: Client } {
21
+ const accountId = accountFor({ account });
22
+ const acct = accounts.get(accountId);
23
+ if (!acct) throw new Error(`unknown account '${accountId}'`);
24
+ return { accountId, client: acct.client };
25
+ }
26
+
27
+ function run(cmd: string, args: string[]): Promise<void> {
28
+ return new Promise((resolve, reject) => {
29
+ const p = spawn(cmd, args, { stdio: ['ignore', 'ignore', 'pipe'] });
30
+ let err = '';
31
+ p.stderr?.on('data', (d: Buffer) => {
32
+ err += d.toString();
33
+ });
34
+ p.on('error', reject);
35
+ p.on('close', (code) => {
36
+ if (code === 0) resolve();
37
+ else reject(new Error(`${cmd} exited ${code}: ${err.slice(-400)}`));
38
+ });
39
+ });
40
+ }
41
+
42
+ function channelName(ch: unknown, fallback: string): string {
43
+ return ch && typeof ch === 'object' && 'name' in ch
44
+ ? String((ch as { name?: string }).name)
45
+ : fallback;
46
+ }
47
+
48
+ function resolveChannelId(args: {
49
+ channelId?: string;
50
+ line?: string;
51
+ account?: string;
52
+ }): string | undefined {
53
+ if (args.channelId) return args.channelId;
54
+ if (!args.line) return undefined;
55
+ try {
56
+ return routeOf(args.line, args.account).channelId;
57
+ } catch {
58
+ return undefined;
59
+ }
60
+ }
61
+
62
+ function connByChannel(
63
+ client: Client,
64
+ channelId: string | undefined,
65
+ ): { conn: VoiceConnection; channelName: string } | null {
66
+ if (!channelId) return null;
67
+ const ch = client.channels.cache.get(channelId);
68
+ const gid =
69
+ ch && 'guildId' in ch ? (ch as { guildId: string }).guildId : undefined;
70
+ if (!gid) return null;
71
+ const conn = getVoiceConnection(gid);
72
+ if (!conn) return null;
73
+ return { conn, channelName: channelName(ch, gid) };
74
+ }
75
+
76
+ function connByGuildScan(
77
+ client: Client,
78
+ ): { conn: VoiceConnection; channelName: string } | null {
79
+ for (const guild of client.guilds.cache.values()) {
80
+ const conn = getVoiceConnection(guild.id);
81
+ if (conn) {
82
+ const chId = (conn.joinConfig as { channelId?: string }).channelId;
83
+ const ch = chId ? client.channels.cache.get(chId) : undefined;
84
+ return { conn, channelName: channelName(ch, guild.name) };
85
+ }
86
+ }
87
+ return null;
88
+ }
89
+
90
+ function resolveConnection(
91
+ client: Client,
92
+ args: { channelId?: string; line?: string; account?: string },
93
+ ): { conn: VoiceConnection; channelName: string } | { error: string } {
94
+ const channelId = resolveChannelId(args);
95
+ return (
96
+ connByChannel(client, channelId) ??
97
+ connByGuildScan(client) ?? {
98
+ error: 'no active voice connection — run joinVoice first',
99
+ }
100
+ );
101
+ }
102
+
103
+ export async function speak(
104
+ id: string,
105
+ rawArgs: Record<string, unknown>,
106
+ ): Promise<void> {
107
+ const args = rawArgs as {
108
+ account?: string;
109
+ text?: string;
110
+ channelId?: string;
111
+ line?: string;
112
+ voice?: string;
113
+ };
114
+ const text = (args.text ?? '').trim();
115
+ if (!text) {
116
+ respond(id, { result: { ok: false, error: 'text is required' } });
117
+ return;
118
+ }
119
+
120
+ const { accountId, client } = clientFor(args.account);
121
+ if (!client.isReady()) {
122
+ respond(id, {
123
+ result: { ok: false, error: `gateway not ready for '${accountId}'` },
124
+ });
125
+ return;
126
+ }
127
+
128
+ const resolved = resolveConnection(client, args);
129
+ if ('error' in resolved) {
130
+ respond(id, { result: { ok: false, error: resolved.error } });
131
+ return;
132
+ }
133
+ const { conn, channelName } = resolved;
134
+
135
+ const ts = Date.now();
136
+ const aiff = `/tmp/metro-tts-${ts}.aiff`;
137
+ const ogg = `/tmp/metro-tts-${ts}.ogg`;
138
+ const cleanup = async () => {
139
+ await Promise.allSettled([unlink(aiff), unlink(ogg)]);
140
+ };
141
+
142
+ try {
143
+ await run('say', ['-v', args.voice ?? TTS_VOICE, '-o', aiff, text]);
144
+ await run('ffmpeg', [
145
+ '-hide_banner',
146
+ '-loglevel',
147
+ 'error',
148
+ '-y',
149
+ '-i',
150
+ aiff,
151
+ '-ac',
152
+ '2',
153
+ '-ar',
154
+ '48000',
155
+ '-c:a',
156
+ 'libopus',
157
+ '-b:a',
158
+ '64k',
159
+ '-f',
160
+ 'ogg',
161
+ ogg,
162
+ ]);
163
+
164
+ const player = createAudioPlayer({
165
+ behaviors: { noSubscriber: NoSubscriberBehavior.Play },
166
+ });
167
+ const resource = createAudioResource(ogg, {
168
+ inputType: StreamType.OggOpus,
169
+ });
170
+ conn.subscribe(player);
171
+ try {
172
+ (conn as { rejoin: (c: object) => void }).rejoin({ selfMute: false });
173
+ } catch {
174
+ }
175
+ player.play(resource);
176
+
177
+ await entersState(player, AudioPlayerStatus.Playing, 10_000);
178
+ await entersState(player, AudioPlayerStatus.Idle, 120_000);
179
+ player.stop();
180
+ try {
181
+ (conn as { rejoin: (c: object) => void }).rejoin({ selfMute: true });
182
+ } catch {
183
+ }
184
+
185
+ respond(id, {
186
+ result: { ok: true, spoke: text, channelName, account: accountId },
187
+ });
188
+ } catch (err) {
189
+ respond(id, {
190
+ result: { ok: false, error: errMsg(err), account: accountId },
191
+ });
192
+ } finally {
193
+ await cleanup();
194
+ }
195
+ }