@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,220 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import type { IncomingMessage, ServerResponse } from 'node:http';
3
+ import { arch, platform, release } from 'node:os';
4
+ import { isRecord } from '@metro-labs/core/is-record';
5
+ import { errMsg, log } from '@metro-labs/core/log';
6
+ import { refreshTokens, tokensStale, type CodexTokens } from './codex-auth.js';
7
+ import { assembleMessage, CodexEventTranslator, parseEvent, SseParser } from './codex-stream.js';
8
+ import { ToolNames, toResponsesRequest } from './codex-translate.js';
9
+ import { GatewayError, idleMessage, providerStatus, sendError, upstreamMessage, type Watch } from './forward.js';
10
+ import type { ModelConfig } from './model-config.js';
11
+
12
+ export const CODEX_BASE = 'https://chatgpt.com/backend-api/codex';
13
+ const CODEX_VERSION = '0.153.4';
14
+ const VERSION_RE = /^\d+\.\d+\.\d+(?:-[A-Za-z0-9.]+)?$/;
15
+ const PING_MS = 25_000;
16
+ const STATUS_OF: Record<string, number> = { rate_limit_error: 429, invalid_request_error: 400, permission_error: 403, overloaded_error: 529 };
17
+
18
+ export interface CodexDeps {
19
+ base?: string;
20
+ issuer?: string;
21
+ fetchImpl?: typeof fetch;
22
+ save: (tokens: CodexTokens) => void;
23
+ }
24
+
25
+ export interface CodexState {
26
+ refreshing: Promise<CodexTokens> | null;
27
+ latest: CodexTokens | null;
28
+ }
29
+
30
+ export const freshCodexState = (): CodexState => ({ refreshing: null, latest: null });
31
+
32
+ const OS_NAMES: Record<string, string> = { darwin: 'Mac OS', linux: 'Linux', win32: 'Windows' };
33
+
34
+ export function codexVersion(): string {
35
+ const wanted = process.env.METRO_CODEX_VERSION?.trim() ?? '';
36
+ if (wanted === '') return CODEX_VERSION;
37
+ if (VERSION_RE.test(wanted)) return wanted;
38
+ log.warn({ value: wanted }, 'gateway: METRO_CODEX_VERSION is not a version like 0.153.4; using the built-in one');
39
+ return CODEX_VERSION;
40
+ }
41
+
42
+ export const userAgent = (): string => `codex_cli_rs/${codexVersion()} (${OS_NAMES[platform()] ?? platform()} ${release()}; ${arch()}) metro`;
43
+
44
+ function headersFor(tokens: CodexTokens, sessionId: string): Record<string, string> {
45
+ return {
46
+ authorization: `Bearer ${tokens.accessToken}`,
47
+ 'chatgpt-account-id': tokens.accountId,
48
+ 'content-type': 'application/json',
49
+ accept: 'text/event-stream',
50
+ originator: 'codex_cli_rs',
51
+ 'user-agent': userAgent(),
52
+ 'openai-beta': 'responses=experimental',
53
+ 'session-id': sessionId,
54
+ };
55
+ }
56
+
57
+ const newerThan = (a: CodexTokens, b: CodexTokens): boolean => Date.parse(a.savedAt) > Date.parse(b.savedAt);
58
+
59
+ function refreshed(tokens: CodexTokens, deps: CodexDeps, state: CodexState): Promise<CodexTokens> {
60
+ const latest = state.latest;
61
+ if (latest !== null && newerThan(latest, tokens) && !tokensStale(latest)) return Promise.resolve(latest);
62
+ if (state.refreshing !== null) return state.refreshing;
63
+ const run = refreshTokens(tokens, deps.issuer, deps.fetchImpl)
64
+ .then((fresh) => {
65
+ deps.save(fresh);
66
+ state.latest = fresh;
67
+ return fresh;
68
+ })
69
+ .catch((err: unknown) => {
70
+ throw new GatewayError(403, 'permission_error', `Codex sign-in expired (${errMsg(err)}): connect again on the Model page`);
71
+ })
72
+ .finally(() => {
73
+ state.refreshing = null;
74
+ });
75
+ state.refreshing = run;
76
+ return run;
77
+ }
78
+
79
+ export function currentTokens(cfg: ModelConfig, deps: CodexDeps, state: CodexState): Promise<CodexTokens> {
80
+ const tokens = cfg.codex.auth;
81
+ if (tokens === null) throw new GatewayError(400, 'invalid_request_error', 'Codex is not connected: sign in on the Model page.');
82
+ return tokensStale(tokens) ? refreshed(tokens, deps, state) : Promise.resolve(tokens);
83
+ }
84
+
85
+ function errorKind(status: number): string {
86
+ if (status === 401 || status === 403) return 'permission_error';
87
+ if (status === 429) return 'rate_limit_error';
88
+ if (status === 400 || status === 404 || status === 422) return 'invalid_request_error';
89
+ return 'api_error';
90
+ }
91
+
92
+ const sessionIdOf = (req: IncomingMessage): string => {
93
+ const raw = req.headers['x-claude-code-session-id'];
94
+ const given = (Array.isArray(raw) ? raw[0] : raw)?.trim() ?? '';
95
+ return given === '' ? randomUUID() : given;
96
+ };
97
+
98
+ interface Call {
99
+ body: Record<string, unknown>;
100
+ model: string;
101
+ sessionId: string;
102
+ watch: Watch;
103
+ deps: CodexDeps;
104
+ names: ToolNames;
105
+ }
106
+
107
+ function send(call: Call, tokens: CodexTokens): Promise<Response> {
108
+ const request = toResponsesRequest(call.body, call.model, { promptCacheKey: call.sessionId, names: call.names });
109
+ return (call.deps.fetchImpl ?? fetch)(`${call.deps.base ?? CODEX_BASE}/responses`, {
110
+ method: 'POST',
111
+ headers: headersFor(tokens, call.sessionId),
112
+ body: JSON.stringify(request),
113
+ signal: call.watch.signal,
114
+ redirect: 'manual',
115
+ });
116
+ }
117
+
118
+ async function reach(call: Call, cfg: ModelConfig, state: CodexState): Promise<Response> {
119
+ let tokens = await currentTokens(cfg, call.deps, state);
120
+ let upstream = await send(call, tokens);
121
+ if (upstream.status === 401) {
122
+ await upstream.body?.cancel();
123
+ tokens = await refreshed(tokens, call.deps, state);
124
+ upstream = await send(call, tokens);
125
+ }
126
+ return upstream;
127
+ }
128
+
129
+ async function relayStream(upstream: Response, res: ServerResponse, model: string, names: ToolNames, watch: Watch): Promise<void> {
130
+ res.writeHead(200, { 'content-type': 'text/event-stream', 'cache-control': 'no-store', connection: 'keep-alive' });
131
+ const translator = new CodexEventTranslator(model, (name) => names.restore(name));
132
+ const body = upstream.body;
133
+ if (body === null) {
134
+ res.end(translator.close());
135
+ return;
136
+ }
137
+ const ping = setInterval(() => res.write('event: ping\ndata: {"type":"ping"}\n\n'), PING_MS);
138
+ try {
139
+ const parser = new SseParser();
140
+ const decoder = new TextDecoder();
141
+ const reader = body.getReader();
142
+ for (;;) {
143
+ const { done, value } = await reader.read();
144
+ if (done) break;
145
+ watch.touch();
146
+ for (const raw of parser.push(decoder.decode(value, { stream: true }))) {
147
+ const parsed = parseEvent(raw);
148
+ if (parsed !== null) res.write(translator.push(parsed.event, parsed.data));
149
+ }
150
+ }
151
+ res.write(translator.close());
152
+ } catch (err) {
153
+ if (!watch.idle()) throw err;
154
+ res.write(translator.finished ? '' : translator.close(idleMessage(watch.ms)));
155
+ } finally {
156
+ clearInterval(ping);
157
+ watch.stop();
158
+ res.end();
159
+ }
160
+ }
161
+
162
+ async function relayWhole(upstream: Response, res: ServerResponse, model: string, names: ToolNames): Promise<void> {
163
+ const translator = new CodexEventTranslator(model, (name) => names.restore(name));
164
+ let frames = '';
165
+ const parser = new SseParser();
166
+ for (const raw of parser.push(await upstream.text())) {
167
+ const parsed = parseEvent(raw);
168
+ if (parsed !== null) frames += translator.push(parsed.event, parsed.data);
169
+ }
170
+ frames += translator.close();
171
+ const message = assembleMessage(frames);
172
+ const kind = isRecord(message.error) ? String(message.error.type) : '';
173
+ res.writeHead(message.type === 'error' ? (STATUS_OF[kind] ?? 502) : 200, { 'content-type': 'application/json' });
174
+ res.end(JSON.stringify(message));
175
+ }
176
+
177
+ export async function codexMessages(
178
+ req: IncomingMessage,
179
+ res: ServerResponse,
180
+ body: Record<string, unknown>,
181
+ model: string,
182
+ cfg: ModelConfig,
183
+ deps: CodexDeps,
184
+ state: CodexState,
185
+ watch: Watch,
186
+ ): Promise<void> {
187
+ const call: Call = { body, model, sessionId: sessionIdOf(req), watch, deps, names: new ToolNames() };
188
+ const upstream = await reach(call, cfg, state);
189
+ if (!upstream.ok) {
190
+ const text = await upstream.text();
191
+ sendError(res, providerStatus(upstream.status), errorKind(upstream.status), upstreamMessage(text, `Codex answered ${String(upstream.status)}`));
192
+ return;
193
+ }
194
+ if (body.stream === true) await relayStream(upstream, res, model, call.names, watch);
195
+ else await relayWhole(upstream, res, model, call.names);
196
+ }
197
+
198
+ export function codexCount(res: ServerResponse, body: Record<string, unknown>): void {
199
+ res.writeHead(200, { 'content-type': 'application/json' });
200
+ res.end(JSON.stringify({ input_tokens: Math.ceil(JSON.stringify(body).length / 4) }));
201
+ }
202
+
203
+ export async function codexModels(tokens: CodexTokens, deps: Omit<CodexDeps, 'save'>): Promise<string[]> {
204
+ const res = await (deps.fetchImpl ?? fetch)(`${deps.base ?? CODEX_BASE}/models?client_version=${codexVersion()}`, {
205
+ headers: { ...headersFor(tokens, randomUUID()), accept: 'application/json' },
206
+ redirect: 'manual',
207
+ });
208
+ if (!res.ok) throw new GatewayError(res.status, errorKind(res.status), `Codex would not list models (${String(res.status)})`);
209
+ const slugs = new Set<string>();
210
+ const walk = (value: unknown): void => {
211
+ if (Array.isArray(value)) value.forEach(walk);
212
+ else if (typeof value === 'object' && value !== null) {
213
+ const record = value as Record<string, unknown>;
214
+ if (typeof record.slug === 'string' && record.slug !== '') slugs.add(record.slug);
215
+ Object.values(record).forEach(walk);
216
+ }
217
+ };
218
+ walk(await res.json());
219
+ return [...slugs];
220
+ }
@@ -0,0 +1,123 @@
1
+ export interface EventStreamMessage {
2
+ headers: Record<string, string>;
3
+ payload: Buffer;
4
+ }
5
+
6
+ const PRELUDE_BYTES = 12;
7
+ const CRC_BYTES = 4;
8
+
9
+ const HEADER_TRUE = 0;
10
+ const HEADER_FALSE = 1;
11
+ const HEADER_BYTE = 2;
12
+ const HEADER_SHORT = 3;
13
+ const HEADER_INT = 4;
14
+ const HEADER_LONG = 5;
15
+ const HEADER_BYTES = 6;
16
+ const HEADER_STRING = 7;
17
+ const HEADER_TIMESTAMP = 8;
18
+ const HEADER_UUID = 9;
19
+
20
+ const FIXED_WIDTH: Record<number, number> = {
21
+ [HEADER_TRUE]: 0,
22
+ [HEADER_FALSE]: 0,
23
+ [HEADER_BYTE]: 1,
24
+ [HEADER_SHORT]: 2,
25
+ [HEADER_INT]: 4,
26
+ [HEADER_LONG]: 8,
27
+ [HEADER_TIMESTAMP]: 8,
28
+ [HEADER_UUID]: 16,
29
+ };
30
+
31
+ function readHeaderValue(buf: Buffer, at: number, type: number): { value: string; next: number } {
32
+ if (type === HEADER_BYTES || type === HEADER_STRING) {
33
+ const len = buf.readUInt16BE(at);
34
+ const raw = buf.subarray(at + 2, at + 2 + len);
35
+ const value = type === HEADER_STRING ? raw.toString('utf8') : raw.toString('base64');
36
+ return { value, next: at + 2 + len };
37
+ }
38
+ const width = FIXED_WIDTH[type];
39
+ if (width === undefined) throw new Error(`eventstream: unknown header type ${String(type)}`);
40
+ if (type === HEADER_TRUE) return { value: 'true', next: at };
41
+ if (type === HEADER_FALSE) return { value: 'false', next: at };
42
+ return { value: buf.subarray(at, at + width).toString('hex'), next: at + width };
43
+ }
44
+
45
+ function readHeaders(buf: Buffer): Record<string, string> {
46
+ const out: Record<string, string> = {};
47
+ let at = 0;
48
+ while (at < buf.length) {
49
+ const nameLen = buf.readUInt8(at);
50
+ const name = buf.subarray(at + 1, at + 1 + nameLen).toString('utf8');
51
+ const type = buf.readUInt8(at + 1 + nameLen);
52
+ const parsed = readHeaderValue(buf, at + 2 + nameLen, type);
53
+ out[name] = parsed.value;
54
+ at = parsed.next;
55
+ }
56
+ return out;
57
+ }
58
+
59
+ export function decodeFrame(buf: Buffer, offset: number): { message: EventStreamMessage; end: number } | null {
60
+ if (buf.length - offset < PRELUDE_BYTES) return null;
61
+ const total = buf.readUInt32BE(offset);
62
+ const headersLen = buf.readUInt32BE(offset + 4);
63
+ if (total < PRELUDE_BYTES + CRC_BYTES || headersLen > total) throw new Error('eventstream: malformed frame prelude');
64
+ if (buf.length - offset < total) return null;
65
+ const headersStart = offset + PRELUDE_BYTES;
66
+ const payloadStart = headersStart + headersLen;
67
+ const payloadEnd = offset + total - CRC_BYTES;
68
+ return {
69
+ message: {
70
+ headers: readHeaders(buf.subarray(headersStart, payloadStart)),
71
+ payload: Buffer.from(buf.subarray(payloadStart, payloadEnd)),
72
+ },
73
+ end: offset + total,
74
+ };
75
+ }
76
+
77
+ export class EventStreamDecoder {
78
+ private pending: Buffer = Buffer.alloc(0);
79
+
80
+ push(chunk: Buffer): EventStreamMessage[] {
81
+ this.pending = this.pending.length === 0 ? chunk : Buffer.concat([this.pending, chunk]);
82
+ const out: EventStreamMessage[] = [];
83
+ let offset = 0;
84
+ for (;;) {
85
+ const frame = decodeFrame(this.pending, offset);
86
+ if (frame === null) break;
87
+ out.push(frame.message);
88
+ offset = frame.end;
89
+ }
90
+ this.pending = this.pending.subarray(offset);
91
+ return out;
92
+ }
93
+ }
94
+
95
+ function encodeHeader(name: string, value: string): Buffer {
96
+ const nameBuf = Buffer.from(name, 'utf8');
97
+ const valueBuf = Buffer.from(value, 'utf8');
98
+ const out = Buffer.alloc(1 + nameBuf.length + 1 + 2 + valueBuf.length);
99
+ let at = 0;
100
+ out.writeUInt8(nameBuf.length, at);
101
+ at += 1;
102
+ nameBuf.copy(out, at);
103
+ at += nameBuf.length;
104
+ out.writeUInt8(HEADER_STRING, at);
105
+ at += 1;
106
+ out.writeUInt16BE(valueBuf.length, at);
107
+ at += 2;
108
+ valueBuf.copy(out, at);
109
+ return out;
110
+ }
111
+
112
+ export function encodeFrame(headers: Record<string, string>, payload: Buffer): Buffer {
113
+ const headerBuf = Buffer.concat(Object.entries(headers).map(([name, value]) => encodeHeader(name, value)));
114
+ const total = PRELUDE_BYTES + headerBuf.length + payload.length + CRC_BYTES;
115
+ const out = Buffer.alloc(total);
116
+ out.writeUInt32BE(total, 0);
117
+ out.writeUInt32BE(headerBuf.length, 4);
118
+ out.writeUInt32BE(0, 8);
119
+ headerBuf.copy(out, PRELUDE_BYTES);
120
+ payload.copy(out, PRELUDE_BYTES + headerBuf.length);
121
+ out.writeUInt32BE(0, total - CRC_BYTES);
122
+ return out;
123
+ }
@@ -0,0 +1,182 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+
3
+ export class GatewayError extends Error {
4
+ constructor(
5
+ readonly status: number,
6
+ readonly kind: string,
7
+ message: string,
8
+ ) {
9
+ super(message);
10
+ }
11
+ }
12
+
13
+ export const BODY_MAX = 64 * 1024 * 1024;
14
+ const DRAIN_FACTOR = 2;
15
+ const PING_MS = 25_000;
16
+ const IDLE_MS = 300_000;
17
+ const HOP_BY_HOP = new Set([
18
+ 'host',
19
+ 'connection',
20
+ 'content-length',
21
+ 'transfer-encoding',
22
+ 'keep-alive',
23
+ 'proxy-authorization',
24
+ 'te',
25
+ 'trailer',
26
+ 'upgrade',
27
+ 'accept-encoding',
28
+ 'x-metro-key',
29
+ ]);
30
+ const RESPONSE_DROP = new Set(['content-length', 'content-encoding', 'transfer-encoding', 'connection', 'keep-alive']);
31
+
32
+ export function sendError(res: ServerResponse, status: number, kind: string, message: string): void {
33
+ res.writeHead(status, { 'content-type': 'application/json' });
34
+ res.end(JSON.stringify({ type: 'error', error: { type: kind, message } }));
35
+ }
36
+
37
+ export const errorFrame = (kind: string, message: string): string => `event: error\ndata: ${JSON.stringify({ type: 'error', error: { type: kind, message } })}\n\n`;
38
+
39
+ export const providerStatus = (status: number): number => (status === 401 ? 403 : status);
40
+
41
+ export const idleMs = (): number => Number(process.env.METRO_GATEWAY_IDLE_MS) || IDLE_MS;
42
+
43
+ export const idleMessage = (ms: number): string => `metro gateway: the provider sent nothing for ${String(Math.round(ms / 1000))}s; giving up on this request`;
44
+
45
+ export interface Watch {
46
+ signal: AbortSignal;
47
+ ms: number;
48
+ touch: () => void;
49
+ idle: () => boolean;
50
+ stop: () => void;
51
+ }
52
+
53
+ export function watchUpstream(res: ServerResponse, ms = idleMs()): Watch {
54
+ const control = new AbortController();
55
+ let expired = false;
56
+ let timer: NodeJS.Timeout | null = null;
57
+ const stop = (): void => {
58
+ if (timer !== null) clearTimeout(timer);
59
+ timer = null;
60
+ };
61
+ const arm = (): void => {
62
+ stop();
63
+ timer = setTimeout(() => {
64
+ expired = true;
65
+ control.abort();
66
+ }, ms);
67
+ timer.unref();
68
+ };
69
+ res.on('close', () => {
70
+ stop();
71
+ if (!res.writableEnded) control.abort();
72
+ });
73
+ arm();
74
+ return { signal: control.signal, ms, touch: arm, idle: () => expired, stop };
75
+ }
76
+
77
+ export async function readBody(req: IncomingMessage): Promise<Buffer> {
78
+ const chunks: Buffer[] = [];
79
+ let total = 0;
80
+ let over = false;
81
+ for await (const chunk of req) {
82
+ const buf = chunk as Buffer;
83
+ total += buf.length;
84
+ if (total > BODY_MAX) {
85
+ over = true;
86
+ if (total > BODY_MAX * DRAIN_FACTOR) break;
87
+ continue;
88
+ }
89
+ chunks.push(buf);
90
+ }
91
+ if (over) throw new GatewayError(413, 'invalid_request_error', 'request too large');
92
+ return Buffer.concat(chunks);
93
+ }
94
+
95
+ export function parseJson(raw: Buffer): Record<string, unknown> {
96
+ let parsed: unknown;
97
+ try {
98
+ parsed = JSON.parse(raw.toString('utf8'));
99
+ } catch {
100
+ throw new GatewayError(400, 'invalid_request_error', 'body must be JSON');
101
+ }
102
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
103
+ throw new GatewayError(400, 'invalid_request_error', 'body must be a JSON object');
104
+ return parsed as Record<string, unknown>;
105
+ }
106
+
107
+ export function forwardedHeaders(req: IncomingMessage): Record<string, string> {
108
+ const out: Record<string, string> = {};
109
+ for (const [name, value] of Object.entries(req.headers)) {
110
+ if (HOP_BY_HOP.has(name) || value === undefined) continue;
111
+ out[name] = Array.isArray(value) ? value.join(', ') : value;
112
+ }
113
+ return out;
114
+ }
115
+
116
+ export function anthropicHeaders(req: IncomingMessage, apiKey: string): Record<string, string> {
117
+ const headers = forwardedHeaders(req);
118
+ delete headers.authorization;
119
+ const betas = (headers['anthropic-beta'] ?? '')
120
+ .split(',')
121
+ .map((beta) => beta.trim())
122
+ .filter((beta) => beta !== '' && !beta.includes('oauth'));
123
+ if (betas.length > 0) headers['anthropic-beta'] = betas.join(',');
124
+ else delete headers['anthropic-beta'];
125
+ headers['x-api-key'] = apiKey;
126
+ return headers;
127
+ }
128
+
129
+ export interface PipeOptions {
130
+ keepalive?: boolean;
131
+ ownCredential?: boolean;
132
+ }
133
+
134
+ function openResponse(upstream: Response, res: ServerResponse, opts: PipeOptions): boolean {
135
+ const headers: Record<string, string> = {};
136
+ upstream.headers.forEach((value, name) => {
137
+ if (!RESPONSE_DROP.has(name)) headers[name] = value;
138
+ });
139
+ res.writeHead(opts.ownCredential === true ? providerStatus(upstream.status) : upstream.status, headers);
140
+ return (upstream.headers.get('content-type') ?? '').startsWith('text/event-stream');
141
+ }
142
+
143
+ async function pump(body: ReadableStream<Uint8Array>, res: ServerResponse, watch: Watch): Promise<void> {
144
+ const reader = body.getReader();
145
+ for (;;) {
146
+ const { done, value } = await reader.read();
147
+ if (done) return;
148
+ watch.touch();
149
+ res.write(value);
150
+ }
151
+ }
152
+
153
+ export async function pipeResponse(upstream: Response, res: ServerResponse, watch: Watch, opts: PipeOptions = {}): Promise<void> {
154
+ const streaming = openResponse(upstream, res, opts);
155
+ const body = upstream.body;
156
+ if (body === null) {
157
+ res.end();
158
+ return;
159
+ }
160
+ const ping = opts.keepalive === true && streaming ? setInterval(() => res.write('event: ping\ndata: {"type":"ping"}\n\n'), PING_MS) : null;
161
+ try {
162
+ await pump(body, res, watch);
163
+ } catch (err) {
164
+ if (!watch.idle()) throw err;
165
+ if (streaming) res.write(errorFrame('api_error', idleMessage(watch.ms)));
166
+ } finally {
167
+ if (ping !== null) clearInterval(ping);
168
+ watch.stop();
169
+ res.end();
170
+ }
171
+ }
172
+
173
+ export function upstreamMessage(text: string, fallback: string): string {
174
+ if (text === '') return fallback;
175
+ try {
176
+ const parsed = JSON.parse(text) as { message?: unknown; Message?: unknown; error?: { message?: unknown } };
177
+ const message = parsed.message ?? parsed.Message ?? parsed.error?.message;
178
+ return typeof message === 'string' && message !== '' ? message : text;
179
+ } catch {
180
+ return text;
181
+ }
182
+ }