@stage-labs/metro 0.1.0-beta.7 → 0.1.0-beta.71

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 (279) hide show
  1. package/dist/api.js +14 -0
  2. package/dist/bedrock-eventstream.js +120 -0
  3. package/dist/bedrock-proxy.js +260 -0
  4. package/dist/bedrock-upstream.js +72 -0
  5. package/dist/bedrock.js +37 -0
  6. package/dist/claude-settings.js +40 -0
  7. package/dist/claude.js +107 -0
  8. package/dist/cli.js +101 -0
  9. package/dist/control.js +74 -0
  10. package/dist/hold.js +211 -0
  11. package/dist/local.js +93 -0
  12. package/dist/node-name.js +51 -0
  13. package/dist/plugin.js +80 -0
  14. package/dist/provider-flags.js +9 -0
  15. package/dist/runtime-install.js +84 -0
  16. package/dist/runtime.js +70 -0
  17. package/dist/serve.js +147 -0
  18. package/dist/service.js +224 -0
  19. package/dist/tail.js +119 -0
  20. package/dist/update.js +45 -0
  21. package/dist/version.js +97 -0
  22. package/package.json +14 -25
  23. package/runtime/node_modules/@metro-labs/discord-bot/package.json +28 -0
  24. package/runtime/node_modules/@metro-labs/discord-bot/src/accounts.ts +118 -0
  25. package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +388 -0
  26. package/runtime/node_modules/@metro-labs/discord-bot/src/api-base.ts +1 -0
  27. package/runtime/node_modules/@metro-labs/discord-bot/src/attachments.ts +29 -0
  28. package/runtime/node_modules/@metro-labs/discord-bot/src/format.ts +220 -0
  29. package/runtime/node_modules/@metro-labs/discord-bot/src/group-actions.ts +50 -0
  30. package/runtime/node_modules/@metro-labs/discord-bot/src/group.ts +115 -0
  31. package/runtime/node_modules/@metro-labs/discord-bot/src/index.ts +127 -0
  32. package/runtime/node_modules/@metro-labs/discord-bot/src/members.ts +215 -0
  33. package/runtime/node_modules/@metro-labs/discord-bot/src/send-files.ts +43 -0
  34. package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +19 -0
  35. package/runtime/node_modules/@metro-labs/discord-bot/src/verify.ts +82 -0
  36. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-speak.ts +195 -0
  37. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-transcribe.ts +292 -0
  38. package/runtime/node_modules/@metro-labs/discord-bot/src/voice.ts +197 -0
  39. package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +5 -0
  40. package/runtime/node_modules/@metro-labs/mcp/package.json +64 -0
  41. package/runtime/node_modules/@metro-labs/mcp/src/channels/addressed.ts +25 -0
  42. package/runtime/node_modules/@metro-labs/mcp/src/channels/dedupe.ts +24 -0
  43. package/runtime/node_modules/@metro-labs/mcp/src/channels/inbound.ts +377 -0
  44. package/runtime/node_modules/@metro-labs/mcp/src/channels/media-note.ts +85 -0
  45. package/runtime/node_modules/@metro-labs/mcp/src/channels/pending.ts +75 -0
  46. package/runtime/node_modules/@metro-labs/mcp/src/channels/relay.ts +129 -0
  47. package/runtime/node_modules/@metro-labs/mcp/src/channels/webhook-note.ts +51 -0
  48. package/runtime/node_modules/@metro-labs/mcp/src/daemon/account-api.ts +311 -0
  49. package/runtime/node_modules/@metro-labs/mcp/src/daemon/agent-api.ts +302 -0
  50. package/runtime/node_modules/@metro-labs/mcp/src/daemon/api-error.ts +8 -0
  51. package/runtime/node_modules/@metro-labs/mcp/src/daemon/api-http.ts +95 -0
  52. package/runtime/node_modules/@metro-labs/mcp/src/daemon/attach-grant.ts +99 -0
  53. package/runtime/node_modules/@metro-labs/mcp/src/daemon/attach-owner.ts +32 -0
  54. package/runtime/node_modules/@metro-labs/mcp/src/daemon/attach-serve.ts +128 -0
  55. package/runtime/node_modules/@metro-labs/mcp/src/daemon/attach-session.ts +280 -0
  56. package/runtime/node_modules/@metro-labs/mcp/src/daemon/boot.ts +204 -0
  57. package/runtime/node_modules/@metro-labs/mcp/src/daemon/bundle-api.ts +111 -0
  58. package/runtime/node_modules/@metro-labs/mcp/src/daemon/claude-api.ts +97 -0
  59. package/runtime/node_modules/@metro-labs/mcp/src/daemon/claude-files.ts +329 -0
  60. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connect-hint.ts +39 -0
  61. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-api.ts +307 -0
  62. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-json.ts +21 -0
  63. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-oauth-routes.ts +157 -0
  64. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-oauth.ts +127 -0
  65. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-tools.ts +98 -0
  66. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-url.ts +70 -0
  67. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-verify.ts +330 -0
  68. package/runtime/node_modules/@metro-labs/mcp/src/daemon/control-api.ts +64 -0
  69. package/runtime/node_modules/@metro-labs/mcp/src/daemon/cors.ts +29 -0
  70. package/runtime/node_modules/@metro-labs/mcp/src/daemon/crash-guard.ts +49 -0
  71. package/runtime/node_modules/@metro-labs/mcp/src/daemon/events.ts +120 -0
  72. package/runtime/node_modules/@metro-labs/mcp/src/daemon/http.ts +390 -0
  73. package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity-key.ts +33 -0
  74. package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity-registry.ts +13 -0
  75. package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity-routes.ts +54 -0
  76. package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity.ts +7 -0
  77. package/runtime/node_modules/@metro-labs/mcp/src/daemon/is-record.ts +2 -0
  78. package/runtime/node_modules/@metro-labs/mcp/src/daemon/local-cli-api.ts +63 -0
  79. package/runtime/node_modules/@metro-labs/mcp/src/daemon/local-mode.ts +187 -0
  80. package/runtime/node_modules/@metro-labs/mcp/src/daemon/local-owner.ts +14 -0
  81. package/runtime/node_modules/@metro-labs/mcp/src/daemon/log.ts +42 -0
  82. package/runtime/node_modules/@metro-labs/mcp/src/daemon/machine-api.ts +61 -0
  83. package/runtime/node_modules/@metro-labs/mcp/src/daemon/mode-api.ts +32 -0
  84. package/runtime/node_modules/@metro-labs/mcp/src/daemon/model-api.ts +169 -0
  85. package/runtime/node_modules/@metro-labs/mcp/src/daemon/oauth-client.ts +159 -0
  86. package/runtime/node_modules/@metro-labs/mcp/src/daemon/oauth-discovery.ts +117 -0
  87. package/runtime/node_modules/@metro-labs/mcp/src/daemon/oauth-pending.ts +65 -0
  88. package/runtime/node_modules/@metro-labs/mcp/src/daemon/paths.ts +109 -0
  89. package/runtime/node_modules/@metro-labs/mcp/src/daemon/protocol.ts +226 -0
  90. package/runtime/node_modules/@metro-labs/mcp/src/daemon/relay.ts +295 -0
  91. package/runtime/node_modules/@metro-labs/mcp/src/daemon/return-to.ts +21 -0
  92. package/runtime/node_modules/@metro-labs/mcp/src/daemon/runtime-deps.ts +82 -0
  93. package/runtime/node_modules/@metro-labs/mcp/src/daemon/secure-fs.ts +57 -0
  94. package/runtime/node_modules/@metro-labs/mcp/src/daemon/server-types.ts +21 -0
  95. package/runtime/node_modules/@metro-labs/mcp/src/daemon/servers-api.ts +80 -0
  96. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session-api.ts +29 -0
  97. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session-apis.ts +66 -0
  98. package/runtime/node_modules/@metro-labs/mcp/src/daemon/signed-identity.ts +36 -0
  99. package/runtime/node_modules/@metro-labs/mcp/src/daemon/supervisor-io.ts +97 -0
  100. package/runtime/node_modules/@metro-labs/mcp/src/daemon/supervisor.ts +320 -0
  101. package/runtime/node_modules/@metro-labs/mcp/src/daemon/terminal-api.ts +71 -0
  102. package/runtime/node_modules/@metro-labs/mcp/src/daemon/terminal-tickets.ts +40 -0
  103. package/runtime/node_modules/@metro-labs/mcp/src/daemon/terminal-ws.ts +114 -0
  104. package/runtime/node_modules/@metro-labs/mcp/src/daemon/train-call.ts +22 -0
  105. package/runtime/node_modules/@metro-labs/mcp/src/daemon/train-error.ts +53 -0
  106. package/runtime/node_modules/@metro-labs/mcp/src/daemon/tunnel.ts +352 -0
  107. package/runtime/node_modules/@metro-labs/mcp/src/daemon/update-api.ts +116 -0
  108. package/runtime/node_modules/@metro-labs/mcp/src/daemon/upload-api.ts +294 -0
  109. package/runtime/node_modules/@metro-labs/mcp/src/daemon/upload-store.ts +181 -0
  110. package/runtime/node_modules/@metro-labs/mcp/src/daemon/vault-api.ts +78 -0
  111. package/runtime/node_modules/@metro-labs/mcp/src/daemon/vault-types.ts +12 -0
  112. package/runtime/node_modules/@metro-labs/mcp/src/daemon/version.ts +2 -0
  113. package/runtime/node_modules/@metro-labs/mcp/src/db/account-attach.ts +19 -0
  114. package/runtime/node_modules/@metro-labs/mcp/src/db/address.ts +6 -0
  115. package/runtime/node_modules/@metro-labs/mcp/src/db/agent-admin.ts +43 -0
  116. package/runtime/node_modules/@metro-labs/mcp/src/db/agent-map.ts +84 -0
  117. package/runtime/node_modules/@metro-labs/mcp/src/db/agent-scope.ts +64 -0
  118. package/runtime/node_modules/@metro-labs/mcp/src/db/client.ts +32 -0
  119. package/runtime/node_modules/@metro-labs/mcp/src/db/connector-config.ts +144 -0
  120. package/runtime/node_modules/@metro-labs/mcp/src/db/connector-relay.ts +39 -0
  121. package/runtime/node_modules/@metro-labs/mcp/src/db/connectors.ts +69 -0
  122. package/runtime/node_modules/@metro-labs/mcp/src/db/file-admin.ts +329 -0
  123. package/runtime/node_modules/@metro-labs/mcp/src/db/file-source.ts +155 -0
  124. package/runtime/node_modules/@metro-labs/mcp/src/db/ids.ts +21 -0
  125. package/runtime/node_modules/@metro-labs/mcp/src/db/key-map.ts +45 -0
  126. package/runtime/node_modules/@metro-labs/mcp/src/db/local-connectors.ts +277 -0
  127. package/runtime/node_modules/@metro-labs/mcp/src/db/materialize.ts +253 -0
  128. package/runtime/node_modules/@metro-labs/mcp/src/db/schema.ts +33 -0
  129. package/runtime/node_modules/@metro-labs/mcp/src/db/servers.ts +83 -0
  130. package/runtime/node_modules/@metro-labs/mcp/src/db/stations.ts +12 -0
  131. package/runtime/node_modules/@metro-labs/mcp/src/db/vault.ts +109 -0
  132. package/runtime/node_modules/@metro-labs/mcp/src/gateway/bedrock.ts +252 -0
  133. package/runtime/node_modules/@metro-labs/mcp/src/gateway/codex-auth.ts +231 -0
  134. package/runtime/node_modules/@metro-labs/mcp/src/gateway/codex-device.ts +91 -0
  135. package/runtime/node_modules/@metro-labs/mcp/src/gateway/codex-stream.ts +288 -0
  136. package/runtime/node_modules/@metro-labs/mcp/src/gateway/codex-translate.ts +203 -0
  137. package/runtime/node_modules/@metro-labs/mcp/src/gateway/codex.ts +211 -0
  138. package/runtime/node_modules/@metro-labs/mcp/src/gateway/eventstream.ts +123 -0
  139. package/runtime/node_modules/@metro-labs/mcp/src/gateway/forward.ts +169 -0
  140. package/runtime/node_modules/@metro-labs/mcp/src/gateway/gateway.ts +193 -0
  141. package/runtime/node_modules/@metro-labs/mcp/src/gateway/model-config.ts +180 -0
  142. package/runtime/node_modules/@metro-labs/mcp/src/mcp/accounts.ts +141 -0
  143. package/runtime/node_modules/@metro-labs/mcp/src/mcp/call-tools.ts +216 -0
  144. package/runtime/node_modules/@metro-labs/mcp/src/mcp/channel-owner.ts +29 -0
  145. package/runtime/node_modules/@metro-labs/mcp/src/mcp/ctx.ts +62 -0
  146. package/runtime/node_modules/@metro-labs/mcp/src/mcp/event-store.ts +91 -0
  147. package/runtime/node_modules/@metro-labs/mcp/src/mcp/frame-scope.ts +21 -0
  148. package/runtime/node_modules/@metro-labs/mcp/src/mcp/group-tools.ts +129 -0
  149. package/runtime/node_modules/@metro-labs/mcp/src/mcp/index.ts +191 -0
  150. package/runtime/node_modules/@metro-labs/mcp/src/mcp/member-tools.ts +72 -0
  151. package/runtime/node_modules/@metro-labs/mcp/src/mcp/permission-relay.ts +66 -0
  152. package/runtime/node_modules/@metro-labs/mcp/src/mcp/raw-get-stream.ts +207 -0
  153. package/runtime/node_modules/@metro-labs/mcp/src/mcp/request-identity.ts +47 -0
  154. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-registry.ts +172 -0
  155. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-route.ts +43 -0
  156. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session.ts +215 -0
  157. package/runtime/node_modules/@metro-labs/mcp/src/mcp/str.ts +5 -0
  158. package/runtime/node_modules/@metro-labs/mcp/src/mcp/tool-dispatch.ts +215 -0
  159. package/runtime/node_modules/@metro-labs/mcp/src/mcp/tool-schemas.ts +400 -0
  160. package/runtime/node_modules/@metro-labs/mcp/src/mcp/upload-tool.ts +66 -0
  161. package/runtime/node_modules/@metro-labs/mcp/src/monitor/api.ts +237 -0
  162. package/runtime/node_modules/@metro-labs/mcp/src/server.ts +2 -0
  163. package/runtime/node_modules/@metro-labs/mcp/src/stations/account-store.ts +60 -0
  164. package/runtime/node_modules/@metro-labs/mcp/src/stations/attach-inline.ts +100 -0
  165. package/runtime/node_modules/@metro-labs/mcp/src/stations/attach-interactive.ts +161 -0
  166. package/runtime/node_modules/@metro-labs/mcp/src/stations/attach-resolve.ts +200 -0
  167. package/runtime/node_modules/@metro-labs/mcp/src/stations/attach-xmtp.ts +111 -0
  168. package/runtime/node_modules/@metro-labs/mcp/src/stations/attach.ts +184 -0
  169. package/runtime/node_modules/@metro-labs/mcp/src/stations/attachments.ts +196 -0
  170. package/runtime/node_modules/@metro-labs/mcp/src/stations/lines.ts +82 -0
  171. package/runtime/node_modules/@metro-labs/mcp/src/stations/messaging-normalize.ts +88 -0
  172. package/runtime/node_modules/@metro-labs/mcp/src/stations/registry.ts +35 -0
  173. package/runtime/node_modules/@metro-labs/mcp/src/stations/station-runtime.ts +64 -0
  174. package/runtime/node_modules/@metro-labs/mcp/src/stations/types.ts +107 -0
  175. package/runtime/node_modules/@metro-labs/telegram/package.json +26 -0
  176. package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +80 -0
  177. package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +254 -0
  178. package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +87 -0
  179. package/runtime/node_modules/@metro-labs/telegram/src/client.ts +77 -0
  180. package/runtime/node_modules/@metro-labs/telegram/src/format.ts +156 -0
  181. package/runtime/node_modules/@metro-labs/telegram/src/group.ts +261 -0
  182. package/runtime/node_modules/@metro-labs/telegram/src/history.ts +52 -0
  183. package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +78 -0
  184. package/runtime/node_modules/@metro-labs/telegram/src/index.ts +46 -0
  185. package/runtime/node_modules/@metro-labs/telegram/src/login.ts +166 -0
  186. package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +80 -0
  187. package/runtime/node_modules/@metro-labs/telegram/src/members.ts +75 -0
  188. package/runtime/node_modules/@metro-labs/telegram/src/normalize.ts +22 -0
  189. package/runtime/node_modules/@metro-labs/telegram/src/reactions.ts +167 -0
  190. package/runtime/node_modules/@metro-labs/telegram/src/station.ts +24 -0
  191. package/runtime/node_modules/@metro-labs/telegram/src/types.ts +7 -0
  192. package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +1 -0
  193. package/runtime/node_modules/@metro-labs/telegram-bot/package.json +25 -0
  194. package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +120 -0
  195. package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +295 -0
  196. package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +128 -0
  197. package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +201 -0
  198. package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +109 -0
  199. package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +166 -0
  200. package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +47 -0
  201. package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +17 -0
  202. package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +58 -0
  203. package/runtime/node_modules/@metro-labs/telegram-bot/src/verify.ts +38 -0
  204. package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +3 -0
  205. package/runtime/node_modules/@metro-labs/webhook/package.json +23 -0
  206. package/runtime/node_modules/@metro-labs/webhook/src/station.ts +37 -0
  207. package/runtime/node_modules/@metro-labs/whatsapp/package.json +27 -0
  208. package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +66 -0
  209. package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +101 -0
  210. package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +178 -0
  211. package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +72 -0
  212. package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +129 -0
  213. package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +327 -0
  214. package/runtime/node_modules/@metro-labs/whatsapp/src/delivery.ts +49 -0
  215. package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +138 -0
  216. package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +57 -0
  217. package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +40 -0
  218. package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +59 -0
  219. package/runtime/node_modules/@metro-labs/whatsapp/src/logger.ts +60 -0
  220. package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +176 -0
  221. package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +84 -0
  222. package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +22 -0
  223. package/runtime/node_modules/@metro-labs/whatsapp/src/outbox.ts +38 -0
  224. package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +185 -0
  225. package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +17 -0
  226. package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +98 -0
  227. package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +6 -0
  228. package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +5 -0
  229. package/runtime/node_modules/@metro-labs/xmtp/package.json +33 -0
  230. package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +112 -0
  231. package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +110 -0
  232. package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +299 -0
  233. package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +157 -0
  234. package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +87 -0
  235. package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +375 -0
  236. package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +107 -0
  237. package/runtime/node_modules/@metro-labs/xmtp/src/codecs.ts +171 -0
  238. package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +239 -0
  239. package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +55 -0
  240. package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +335 -0
  241. package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +80 -0
  242. package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +34 -0
  243. package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +56 -0
  244. package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +33 -0
  245. package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +125 -0
  246. package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +157 -0
  247. package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +40 -0
  248. package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +349 -0
  249. package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +13 -0
  250. package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +126 -0
  251. package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +212 -0
  252. package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +90 -0
  253. package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +84 -0
  254. package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +53 -0
  255. package/runtime/runtime.json +3 -0
  256. package/runtime/stations.json +36 -0
  257. package/runtime/trains/.keep +0 -0
  258. package/LICENSE +0 -21
  259. package/README.md +0 -193
  260. package/dist/cache.js +0 -75
  261. package/dist/cli/actions.js +0 -139
  262. package/dist/cli/config.js +0 -185
  263. package/dist/cli/index.js +0 -159
  264. package/dist/cli/skill.js +0 -62
  265. package/dist/cli/util.js +0 -72
  266. package/dist/codex-rc.js +0 -236
  267. package/dist/dispatcher.js +0 -95
  268. package/dist/history.js +0 -84
  269. package/dist/ipc.js +0 -72
  270. package/dist/log.js +0 -15
  271. package/dist/paths.js +0 -68
  272. package/dist/stations/discord.js +0 -200
  273. package/dist/stations/index.js +0 -73
  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/docs/agents.md +0 -185
  278. package/docs/uri-scheme.md +0 -71
  279. package/skills/metro/SKILL.md +0 -241
@@ -0,0 +1,390 @@
1
+ import { handleSessionApis, type SessionApis } from './session-apis.js';
2
+ import { handleGatewayRequest } from '../gateway/gateway.js';
3
+ import { handleRelayRequest } from './relay.js';
4
+ import {
5
+ createServer,
6
+ type IncomingMessage,
7
+ type Server,
8
+ type ServerResponse,
9
+ } from 'node:http';
10
+ import { Line } from '../stations/lines.js';
11
+ import { errMsg, log } from './log.js';
12
+ import {
13
+ classifyEvent,
14
+ formatDisplay,
15
+ mintId,
16
+ publishEvent,
17
+ userSelf,
18
+ type MetroEvent,
19
+ } from './events.js';
20
+ import type { TrainEvent } from './protocol.js';
21
+ import { agentForLine, agentIdForLine } from '../db/agent-map.js';
22
+ import {
23
+ findEndpointByWebhookId,
24
+ listEndpoints,
25
+ tokenMatches,
26
+ webhookPort,
27
+ type Endpoint,
28
+ } from './tunnel.js';
29
+ import { attachmentEventUrl, handleAttachRequest } from './attach-serve.js';
30
+ import { webhookEntry } from '@metro-labs/webhook';
31
+ import { handleIdentityRequest } from './identity-routes.js';
32
+ import { attachTerminalSockets } from './terminal-ws.js';
33
+ import { tmuxCommand } from './terminal-api.js';
34
+ import { handleModeRequest } from './mode-api.js';
35
+ import { handleUploadRequest } from './upload-api.js';
36
+ import {
37
+ handleMonitorRequest,
38
+ type MonitorCall,
39
+ } from '../monitor/api.js';
40
+ import { applyMcpCors, handleMcpPreflight } from './cors.js';
41
+ import { METRO_VERSION } from './version.js';
42
+
43
+ const LRU_CAP = 2_000;
44
+
45
+ function dedupKey(
46
+ e: Pick<MetroEvent, 'station' | 'line' | 'messageId'>,
47
+ ): string | null {
48
+ if (!e.messageId) return null;
49
+ return `${e.station} ${e.line} ${e.messageId}`;
50
+ }
51
+
52
+ export interface DedupSeq {
53
+ admit(entry: MetroEvent): number | null;
54
+ }
55
+
56
+ export function makeDedupSeq(): DedupSeq {
57
+ const seen = new Map<string, true>();
58
+ const seqByLine = new Map<string, number>();
59
+
60
+ log.info('dedup+seq: live-from-boot (no persisted seed)');
61
+
62
+ const isInbound = (e: MetroEvent): boolean => !Line.isLocal(e.from);
63
+
64
+ return {
65
+ admit(entry: MetroEvent): number | null {
66
+ const key = dedupKey(entry);
67
+ if (key && isInbound(entry)) {
68
+ if (seen.has(key)) {
69
+ log.debug(
70
+ {
71
+ station: entry.station,
72
+ line: entry.line,
73
+ messageId: entry.messageId,
74
+ },
75
+ 'dedup: dropped duplicate inbound message',
76
+ );
77
+ return null;
78
+ }
79
+ seen.set(key, true);
80
+ while (seen.size > LRU_CAP) {
81
+ const oldest = seen.keys().next();
82
+ if (oldest.done) break;
83
+ seen.delete(oldest.value);
84
+ }
85
+ }
86
+ const next = (seqByLine.get(entry.line) ?? 0) + 1;
87
+ seqByLine.set(entry.line, next);
88
+ while (seqByLine.size > LRU_CAP) {
89
+ const oldest = seqByLine.keys().next();
90
+ if (oldest.done) break;
91
+ seqByLine.delete(oldest.value);
92
+ }
93
+ return next;
94
+ },
95
+ };
96
+ }
97
+
98
+ function withAttachmentUrl(entry: MetroEvent): MetroEvent {
99
+ const payload = entry.payload;
100
+ if (!payload || typeof payload !== 'object') return entry;
101
+ const agentId = agentIdForLine(entry.line);
102
+ if (agentId === undefined) return entry;
103
+ const url = attachmentEventUrl(payload as Record<string, unknown>, agentId);
104
+ if (!url) return entry;
105
+ return { ...entry, payload: { ...payload, url } };
106
+ }
107
+
108
+ type Emit = (entry: MetroEvent) => void;
109
+
110
+ export function makeEmit(dedupSeq?: DedupSeq): Emit {
111
+ const tracker = dedupSeq ?? makeDedupSeq();
112
+ return function emit(entry: MetroEvent): void {
113
+ const seq = tracker.admit(entry);
114
+ if (seq === null) return;
115
+ const enriched: MetroEvent = withAttachmentUrl({
116
+ ...entry,
117
+ seq,
118
+ agent: entry.agent ?? agentForLine(entry.line),
119
+ display: entry.display ?? formatDisplay(entry),
120
+ event: entry.event ?? classifyEvent(entry),
121
+ });
122
+ process.stdout.write(JSON.stringify(enriched) + '\n');
123
+ publishEvent(enriched);
124
+ };
125
+ }
126
+
127
+ function eventText(env: TrainEvent): string | undefined {
128
+ if (env.text !== undefined) return env.text;
129
+ return env.emoji ? `[react ${env.emoji}]` : undefined;
130
+ }
131
+
132
+ function addressingFacts(
133
+ env: TrainEvent,
134
+ isPrivate: boolean,
135
+ ): Pick<MetroEvent, 'isPrivate' | 'mentionsSelf' | 'replyToSelf'> {
136
+ return {
137
+ ...(isPrivate ? { isPrivate: true } : {}),
138
+ ...(env.mentions_self === true ? { mentionsSelf: true } : {}),
139
+ ...(env.reply_to_self === true ? { replyToSelf: true } : {}),
140
+ };
141
+ }
142
+
143
+ export function trainEventToMetroEvent(
144
+ env: TrainEvent,
145
+ trainName: string,
146
+ ): MetroEvent | null {
147
+ const line = env.line;
148
+ if (typeof line !== 'string') {
149
+ log.warn({ train: trainName }, 'train: dropped event without `line`');
150
+ return null;
151
+ }
152
+ const station = env.station ?? Line.station(line) ?? trainName;
153
+ const isPrivate = env.is_private === true;
154
+ const text = eventText(env);
155
+ return {
156
+ event: env.event,
157
+ agent: agentForLine(line),
158
+ id: env.id ?? mintId(),
159
+ ts: env.ts ?? new Date().toISOString(),
160
+ station,
161
+ line: line as MetroEvent['line'],
162
+ lineName: env.line_name,
163
+ from: (env.from ?? `metro://${station}`) as MetroEvent['from'],
164
+ fromName: env.from_name,
165
+ fromDisplayName: env.from_display_name,
166
+ to: (env.to ?? (isPrivate ? userSelf() : line)) as MetroEvent['to'],
167
+ text,
168
+ messageId: env.message_id,
169
+ replyTo: env.reply_to,
170
+ ...addressingFacts(env, isPrivate),
171
+ payload: env.payload,
172
+ };
173
+ }
174
+
175
+ type McpHandler = (req: IncomingMessage, res: ServerResponse) => Promise<void>;
176
+
177
+ export async function startWebhookServer(
178
+ emit: Emit,
179
+ apis: SessionApis = {},
180
+ mcp?: McpHandler,
181
+ monitorCall?: MonitorCall,
182
+ ): Promise<Server> {
183
+ const port = webhookPort();
184
+ const server = createServer((req, res) => {
185
+ handleRequest(req, res, emit, apis, mcp, monitorCall).catch(
186
+ (err: unknown) => {
187
+ log.warn({ err: errMsg(err) }, 'webhook handler error');
188
+ if (!res.headersSent) res.writeHead(500).end();
189
+ });
190
+ });
191
+ if (apis.terminalApi !== undefined)
192
+ attachTerminalSockets(server, { command: apis.terminalApi.command ?? tmuxCommand });
193
+ await new Promise<void>((resolve, reject) => {
194
+ server.once('error', reject);
195
+ const host = process.env.METRO_HTTP_HOST ?? '127.0.0.1';
196
+ server.listen(port, host, () => {
197
+ log.info(
198
+ {
199
+ host,
200
+ port,
201
+ endpoints: listEndpoints().length,
202
+ mcp: mcp ? '/' : 'off',
203
+ },
204
+ 'webhook + mcp ready',
205
+ );
206
+ resolve();
207
+ });
208
+ });
209
+ return server;
210
+ }
211
+
212
+ function isMcpPath(req: IncomingMessage): boolean {
213
+ const path = (req.url ?? '').split('?')[0];
214
+ return path === '/' || path === '/mcp';
215
+ }
216
+
217
+ export const WEBHOOK_BODY_MAX = 25 * 1024 * 1024;
218
+
219
+ export class BodyTooLargeError extends Error {
220
+ constructor(readonly limit: number) {
221
+ super(`request body exceeds ${limit} bytes`);
222
+ }
223
+ }
224
+
225
+ export async function readBody(
226
+ req: IncomingMessage,
227
+ maxBytes: number,
228
+ ): Promise<Buffer> {
229
+ const chunks: Buffer[] = [];
230
+ let total = 0;
231
+ for await (const c of req) {
232
+ const buf = c as Buffer;
233
+ total += buf.length;
234
+ if (total > maxBytes) throw new BodyTooLargeError(maxBytes);
235
+ chunks.push(buf);
236
+ }
237
+ return Buffer.concat(chunks);
238
+ }
239
+
240
+ function flatHeaders(req: IncomingMessage): Record<string, string> {
241
+ return Object.fromEntries(
242
+ Object.entries(req.headers).map(([k, v]) => [
243
+ k,
244
+ Array.isArray(v) ? v.join(',') : (v ?? ''),
245
+ ]),
246
+ );
247
+ }
248
+
249
+ function parseBody(raw: Buffer): unknown {
250
+ const text = raw.toString('utf8');
251
+ try {
252
+ return JSON.parse(text);
253
+ } catch {
254
+ return text;
255
+ }
256
+ }
257
+
258
+ async function handleWebhookPost(
259
+ req: IncomingMessage,
260
+ res: ServerResponse,
261
+ emit: Emit,
262
+ endpointId: string,
263
+ endpoint: Endpoint,
264
+ ): Promise<void> {
265
+ let raw: Buffer;
266
+ try {
267
+ raw = await readBody(req, WEBHOOK_BODY_MAX);
268
+ } catch (err) {
269
+ if (!(err instanceof BodyTooLargeError)) throw err;
270
+ log.warn({ endpoint: endpointId, limit: err.limit }, 'webhook body too large — rejecting');
271
+ res.writeHead(413).end('payload too large');
272
+ return;
273
+ }
274
+ const body = parseBody(raw);
275
+ emit(
276
+ webhookEntry(
277
+ endpoint,
278
+ flatHeaders(req),
279
+ body,
280
+ req.method ?? 'POST',
281
+ hookPath(endpointId),
282
+ ),
283
+ );
284
+ res.writeHead(200).end('ok');
285
+ }
286
+
287
+ function handleHealth(req: IncomingMessage, res: ServerResponse): boolean {
288
+ const reqPath = (req.url ?? '').split('?')[0];
289
+ if (reqPath !== '/health' && reqPath !== '/healthz') return false;
290
+ res.writeHead(200, { 'content-type': 'application/json' }).end(
291
+ JSON.stringify({
292
+ status: 'ok',
293
+ version: METRO_VERSION,
294
+ uptime: Math.round(process.uptime()),
295
+ }),
296
+ );
297
+ return true;
298
+ }
299
+
300
+ const HOOK_PATH =
301
+ /^\/api\/webhooks\/([0-9]{17,20})\/([A-Za-z0-9_-]{32,128})$/;
302
+
303
+ const HOOK_PREFIX = '/api/webhooks/';
304
+
305
+ const hookPath = (webhookId: string): string => `${HOOK_PREFIX}${webhookId}`;
306
+
307
+ function hookTarget(
308
+ path: string,
309
+ ): { id: string; endpoint: Endpoint } | null {
310
+ const m = HOOK_PATH.exec(path);
311
+ const webhookId = m?.[1];
312
+ const token = m?.[2];
313
+ if (webhookId === undefined || token === undefined) return null;
314
+ const endpoint = findEndpointByWebhookId(webhookId);
315
+ if (!endpoint?.secret || !tokenMatches(endpoint.secret, token)) return null;
316
+ return { id: webhookId, endpoint };
317
+ }
318
+
319
+ async function handleWebhookRoute(
320
+ req: IncomingMessage,
321
+ res: ServerResponse,
322
+ emit: Emit,
323
+ ): Promise<boolean> {
324
+ const path = (req.url ?? '').split('?')[0] ?? '';
325
+ if (!path.startsWith(HOOK_PREFIX)) return false;
326
+ const target = hookTarget(path);
327
+ if (target === null) {
328
+ res.writeHead(404).end();
329
+ return true;
330
+ }
331
+ if (req.method === 'GET') {
332
+ res.writeHead(200).end(`metro webhook ${target.id} ready\n`);
333
+ return true;
334
+ }
335
+ if (req.method !== 'POST') {
336
+ res.writeHead(405).end();
337
+ return true;
338
+ }
339
+ await handleWebhookPost(req, res, emit, target.id, target.endpoint);
340
+ return true;
341
+ }
342
+
343
+ function handleSignInRoutes(
344
+ req: IncomingMessage,
345
+ res: ServerResponse,
346
+ apis: SessionApis,
347
+ ): boolean {
348
+ if (apis.identity !== undefined && handleIdentityRequest(req, res, apis.identity)) return true;
349
+ return apis.mode !== undefined && handleModeRequest(req, res, apis.mode);
350
+ }
351
+
352
+ function handleEarlyRoutes(req: IncomingMessage, res: ServerResponse, apis: SessionApis): boolean {
353
+ if (handleHealth(req, res)) return true;
354
+ if (apis.gateway !== undefined && handleGatewayRequest(req, res, apis.gateway)) return true;
355
+ if (handleSignInRoutes(req, res, apis)) return true;
356
+ return handleSessionApis(req, res, apis);
357
+ }
358
+
359
+ async function handlePreMcpRoutes(
360
+ req: IncomingMessage,
361
+ res: ServerResponse,
362
+ emit: Emit,
363
+ apis: SessionApis,
364
+ monitorCall?: MonitorCall,
365
+ ): Promise<boolean> {
366
+ if (handleEarlyRoutes(req, res, apis)) return true;
367
+ if (handleUploadRequest(req, res)) return true;
368
+ if (handleAttachRequest(req, res)) return true;
369
+ if (apis.relayApi && handleRelayRequest(req, res, apis.relayApi)) return true;
370
+ if (await handleWebhookRoute(req, res, emit)) return true;
371
+ return Boolean(monitorCall && handleMonitorRequest(req, res, monitorCall));
372
+ }
373
+
374
+ async function handleRequest(
375
+ req: IncomingMessage,
376
+ res: ServerResponse,
377
+ emit: Emit,
378
+ apis: SessionApis = {},
379
+ mcp?: McpHandler,
380
+ monitorCall?: MonitorCall,
381
+ ): Promise<void> {
382
+ if (await handlePreMcpRoutes(req, res, emit, apis, monitorCall)) return;
383
+ if (mcp && isMcpPath(req)) {
384
+ applyMcpCors(req, res);
385
+ if (handleMcpPreflight(req, res)) return;
386
+ await mcp(req, res);
387
+ return;
388
+ }
389
+ res.writeHead(404).end();
390
+ }
@@ -0,0 +1,33 @@
1
+ import { hkdfSync } from 'node:crypto';
2
+ import { secp256k1 } from '@noble/curves/secp256k1';
3
+ import { mapHashToField } from '@noble/curves/abstract/modular';
4
+ import { privateKeyToAccount } from 'viem/accounts';
5
+
6
+ export const ENCRYPTION_KEY_TYPED_DATA = {
7
+ domain: { name: 'metro', version: '1' },
8
+ types: {
9
+ EncryptionKey: [
10
+ { name: 'purpose', type: 'string' },
11
+ { name: 'keyVersion', type: 'uint256' },
12
+ ],
13
+ },
14
+ primaryType: 'EncryptionKey',
15
+ message: { purpose: 'encryption-key', keyVersion: 1n },
16
+ } as const;
17
+
18
+ const KEY_SALT = 'metro';
19
+ const IDENTITY_INFO = 'vault-secp256k1';
20
+ const KEY_HASH_BYTES = 48;
21
+
22
+ const toHex = (bytes: Uint8Array): `0x${string}` =>
23
+ `0x${[...bytes].map((b) => b.toString(16).padStart(2, '0')).join('')}`;
24
+
25
+ export function deriveIdentityKey(signature: `0x${string}`): `0x${string}` {
26
+ const ikm = Buffer.from(signature.slice(2), 'hex');
27
+ const hash = new Uint8Array(hkdfSync('sha256', ikm, KEY_SALT, IDENTITY_INFO, KEY_HASH_BYTES));
28
+ return toHex(mapHashToField(hash, secp256k1.CURVE.n));
29
+ }
30
+
31
+ export function deriveIdentityAddress(signature: `0x${string}`): string {
32
+ return privateKeyToAccount(deriveIdentityKey(signature)).address.toLowerCase();
33
+ }
@@ -0,0 +1,13 @@
1
+ const subjects = new Map<string, string>();
2
+
3
+ export function authorizeIdentity(address: string, subject: string): void {
4
+ subjects.set(address.toLowerCase(), subject.toLowerCase());
5
+ }
6
+
7
+ export function identitySubject(address: string): string | undefined {
8
+ return subjects.get(address.toLowerCase());
9
+ }
10
+
11
+ export function resetIdentities(): void {
12
+ subjects.clear();
13
+ }
@@ -0,0 +1,54 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { verifyTypedData } from 'viem';
3
+ import { log } from './log.js';
4
+ import { ApiError } from './api-error.js';
5
+ import { apiFailure, bodyField, cors, readJsonBody, sendJson } from './api-http.js';
6
+ import { ENCRYPTION_KEY_TYPED_DATA, deriveIdentityAddress } from './identity-key.js';
7
+ import { authorizeIdentity } from './identity-registry.js';
8
+
9
+ const PATH = '/auth/identity';
10
+ const SIGNATURE_RE = /^0x[0-9a-fA-F]{130}$/;
11
+
12
+ export interface IdentityRouteDeps {
13
+ owner: () => string | null;
14
+ }
15
+
16
+ async function register(req: IncomingMessage, deps: IdentityRouteDeps): Promise<{ address: string; owner: string }> {
17
+ const signature = bodyField(await readJsonBody(req), 'signature');
18
+ if (typeof signature !== 'string' || !SIGNATURE_RE.test(signature))
19
+ throw new ApiError('signature is required: the EncryptionKey signature of the owner wallet', 400);
20
+ const owner = deps.owner();
21
+ if (owner === null)
22
+ throw new ApiError('this machine has no owner yet: start it with metro serve --owner <address>', 403);
23
+ const ok = await verifyTypedData({
24
+ ...ENCRYPTION_KEY_TYPED_DATA,
25
+ address: owner as `0x${string}`,
26
+ signature: signature as `0x${string}`,
27
+ }).catch(() => false);
28
+ if (!ok) throw new ApiError('this machine belongs to another wallet', 403);
29
+ const address = deriveIdentityAddress(signature as `0x${string}`);
30
+ authorizeIdentity(address, owner);
31
+ log.info({ owner, identity: address }, 'identity: owner signed in');
32
+ return { address, owner };
33
+ }
34
+
35
+ export function handleIdentityRequest(req: IncomingMessage, res: ServerResponse, deps: IdentityRouteDeps): boolean {
36
+ const path = (req.url ?? '').split('?')[0] ?? '';
37
+ if (path !== PATH) return false;
38
+ if (req.method === 'OPTIONS') {
39
+ res.writeHead(204, cors(req)).end();
40
+ return true;
41
+ }
42
+ if (req.method !== 'POST') {
43
+ sendJson(req, res, 405, { error: 'method not allowed' });
44
+ return true;
45
+ }
46
+ register(req, deps)
47
+ .then((body) => {
48
+ sendJson(req, res, 200, body);
49
+ })
50
+ .catch((err: unknown) => {
51
+ apiFailure(req, res, err, 'identity');
52
+ });
53
+ return true;
54
+ }
@@ -0,0 +1,7 @@
1
+ import { Line } from '../stations/lines.js';
2
+
3
+ export const userSelf = (): Line =>
4
+ (process.env.METRO_FROM ?? 'metro://user') as Line;
5
+
6
+ export const daemonSelf = (): Line =>
7
+ (process.env.METRO_FROM ?? process.env.METRO_SELF_URI ?? 'metro://user') as Line;
@@ -0,0 +1,2 @@
1
+ export const isRecord = (v: unknown): v is Record<string, unknown> =>
2
+ typeof v === 'object' && v !== null && !Array.isArray(v);
@@ -0,0 +1,63 @@
1
+ import type { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { errMsg, log } from './log.js';
3
+ import { cors, sendJson, type AgentIdentity } from './api-http.js';
4
+ import { publicBaseOrDefault } from './attach-serve.js';
5
+ import { relayServersJson, type RelayServerEntry } from './connector-json.js';
6
+ import { agentIdForKey } from '../db/key-map.js';
7
+
8
+ const PATH = '/api/cli/mcp';
9
+
10
+ export interface LocalCliDeps {
11
+ agentName: (agentId: string) => string | null;
12
+ connectorEntries: (agentId: string) => Promise<RelayServerEntry[]>;
13
+ }
14
+
15
+ function keyOf(req: IncomingMessage): string {
16
+ const header = req.headers.authorization ?? '';
17
+ if (header.toLowerCase().startsWith('bearer ')) return header.slice(7).trim();
18
+ const query = new URLSearchParams((req.url ?? '').split('?')[1] ?? '');
19
+ return query.get('token')?.trim() ?? '';
20
+ }
21
+
22
+ export function keyIdentity(req: IncomingMessage): AgentIdentity | null {
23
+ const key = keyOf(req);
24
+ const agentId = key === '' ? undefined : agentIdForKey(key);
25
+ return agentId === undefined ? null : { subject: 'agent-key', agentId };
26
+ }
27
+
28
+ export function handleLocalCliRequest(
29
+ req: IncomingMessage,
30
+ res: ServerResponse,
31
+ deps: LocalCliDeps,
32
+ ): boolean {
33
+ const path = (req.url ?? '').split('?')[0] ?? '';
34
+ if (path !== PATH && !path.startsWith('/api/cli/')) return false;
35
+ if (req.method === 'OPTIONS') {
36
+ res.writeHead(204, cors(req)).end();
37
+ return true;
38
+ }
39
+ if (path !== PATH) {
40
+ sendJson(req, res, 404, { error: 'not on a local daemon' });
41
+ return true;
42
+ }
43
+ if (req.method !== 'GET') {
44
+ sendJson(req, res, 405, { error: 'method not allowed' });
45
+ return true;
46
+ }
47
+ const who = keyIdentity(req);
48
+ if (who === null) {
49
+ sendJson(req, res, 401, { error: 'unauthorized' });
50
+ return true;
51
+ }
52
+ deps
53
+ .connectorEntries(who.agentId)
54
+ .then((entries) => {
55
+ const agent = deps.agentName(who.agentId) ?? '';
56
+ sendJson(req, res, 200, { json: relayServersJson(entries, publicBaseOrDefault(), keyOf(req)), agent });
57
+ })
58
+ .catch((err: unknown) => {
59
+ log.warn({ err: errMsg(err) }, 'local cli: request failed');
60
+ if (!res.headersSent) sendJson(req, res, 500, { error: 'cli failed' });
61
+ });
62
+ return true;
63
+ }