@stage-labs/metro 0.1.0-beta.32 → 0.1.0-beta.321

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 (616) hide show
  1. package/dist/agent.js +123 -0
  2. package/dist/api.js +9 -129
  3. package/dist/automation.js +56 -0
  4. package/dist/child.js +33 -0
  5. package/dist/claude-env.js +113 -0
  6. package/dist/claude-settings.js +40 -0
  7. package/dist/cli.js +60 -139
  8. package/dist/control.js +19 -103
  9. package/dist/hold.js +210 -0
  10. package/dist/local.js +43 -0
  11. package/dist/lock.js +62 -0
  12. package/dist/memory.js +206 -0
  13. package/dist/node-name.js +71 -0
  14. package/dist/provider-flags.js +9 -0
  15. package/dist/root-release-io.js +160 -0
  16. package/dist/root-release.js +74 -0
  17. package/dist/route.js +65 -0
  18. package/dist/runtime-install.js +106 -0
  19. package/dist/runtime.js +29 -55
  20. package/dist/serve.js +117 -17
  21. package/dist/service.js +328 -0
  22. package/dist/tail.js +10 -11
  23. package/dist/update.js +13 -1
  24. package/hooks/guard.mjs +77 -0
  25. package/hooks/policy.mjs +74 -0
  26. package/hooks/session-start.mjs +31 -0
  27. package/package.json +6 -25
  28. package/runtime/node_modules/@metro-labs/core/package.json +61 -0
  29. package/runtime/node_modules/@metro-labs/core/src/automation-files.ts +216 -0
  30. package/runtime/node_modules/@metro-labs/core/src/automation-store.ts +171 -0
  31. package/runtime/node_modules/@metro-labs/core/src/automation-types.ts +141 -0
  32. package/runtime/node_modules/@metro-labs/core/src/call.ts +81 -0
  33. package/runtime/node_modules/@metro-labs/core/src/claude-token.ts +3 -0
  34. package/runtime/node_modules/@metro-labs/core/src/effort.ts +21 -0
  35. package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
  36. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/events.ts +54 -6
  37. package/runtime/node_modules/@metro-labs/{mcp/src/db → core/src}/ids.ts +8 -1
  38. package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
  39. package/runtime/node_modules/@metro-labs/{mcp/src/stations → core/src}/lines.ts +22 -26
  40. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/protocol.ts +7 -4
  41. package/runtime/node_modules/@metro-labs/core/src/runner-activity.ts +270 -0
  42. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/secure-fs.ts +17 -0
  43. package/runtime/node_modules/@metro-labs/core/src/skill-source.ts +96 -0
  44. package/runtime/node_modules/@metro-labs/core/src/station-names.ts +14 -0
  45. package/runtime/node_modules/@metro-labs/core/src/stations/account-files.ts +41 -0
  46. package/runtime/node_modules/@metro-labs/core/src/stations/account-status.ts +26 -0
  47. package/runtime/node_modules/@metro-labs/core/src/stations/account-store.ts +83 -0
  48. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/attachments.ts +9 -3
  49. package/runtime/node_modules/@metro-labs/core/src/stations/channel-directory.ts +159 -0
  50. package/runtime/node_modules/@metro-labs/core/src/stations/channel-pages.ts +129 -0
  51. package/runtime/node_modules/@metro-labs/core/src/stations/mail-text.ts +72 -0
  52. package/runtime/node_modules/@metro-labs/core/src/stations/mail-trust.ts +29 -0
  53. package/runtime/node_modules/@metro-labs/core/src/stations/mail.ts +212 -0
  54. package/runtime/node_modules/@metro-labs/core/src/stations/messaging-normalize.ts +16 -0
  55. package/runtime/node_modules/@metro-labs/core/src/stations/oauth.ts +126 -0
  56. package/runtime/node_modules/@metro-labs/core/src/stations/profile.ts +58 -0
  57. package/runtime/node_modules/@metro-labs/core/src/stations/sender-profile.ts +64 -0
  58. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/station-runtime.ts +6 -11
  59. package/runtime/node_modules/@metro-labs/core/src/stations/train-boot.ts +63 -0
  60. package/runtime/node_modules/@metro-labs/core/src/stations/train-events.ts +84 -0
  61. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/types.ts +22 -1
  62. package/runtime/node_modules/@metro-labs/core/src/tickets.ts +44 -0
  63. package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
  64. package/runtime/node_modules/@metro-labs/daemon/package.json +51 -0
  65. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/agent-fs.ts +246 -0
  66. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/crontab.ts +38 -0
  67. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files-api.ts +12 -0
  68. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files.ts +89 -0
  69. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/home-fs.ts +86 -0
  70. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/metro-home.ts +42 -0
  71. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/provision.ts +57 -0
  72. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedule-detail.ts +93 -0
  73. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules-api.ts +27 -0
  74. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules.ts +144 -0
  75. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/unit-files.ts +29 -0
  76. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/user.ts +101 -0
  77. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/view.ts +90 -0
  78. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-attach.ts +19 -0
  79. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-lookups.ts +55 -0
  80. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-routes.ts +78 -0
  81. package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +383 -0
  82. package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +30 -0
  83. package/runtime/node_modules/@metro-labs/daemon/src/agents/allowlist.ts +59 -0
  84. package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +134 -0
  85. package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +124 -0
  86. package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +334 -0
  87. package/runtime/node_modules/@metro-labs/{mcp/src/db/file-source.ts → daemon/src/agents/files.ts} +40 -50
  88. package/runtime/node_modules/@metro-labs/{mcp/src/db/key-map.ts → daemon/src/agents/keys.ts} +1 -11
  89. package/runtime/node_modules/@metro-labs/daemon/src/agents/map.ts +135 -0
  90. package/runtime/node_modules/@metro-labs/daemon/src/agents/policy-route.ts +27 -0
  91. package/runtime/node_modules/@metro-labs/{mcp/src/db/agent-scope.ts → daemon/src/agents/scope.ts} +2 -2
  92. package/runtime/node_modules/@metro-labs/daemon/src/agents/sender-cards.ts +94 -0
  93. package/runtime/node_modules/@metro-labs/daemon/src/agents/senders.ts +38 -0
  94. package/runtime/node_modules/@metro-labs/daemon/src/approvals/api.ts +55 -0
  95. package/runtime/node_modules/@metro-labs/daemon/src/approvals/owner-line.ts +45 -0
  96. package/runtime/node_modules/@metro-labs/daemon/src/approvals/pending.ts +190 -0
  97. package/runtime/node_modules/@metro-labs/daemon/src/approvals/preview.ts +66 -0
  98. package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +259 -0
  99. package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +36 -0
  100. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/crash-guard.ts +1 -1
  101. package/runtime/node_modules/@metro-labs/daemon/src/boot/local-owner.ts +21 -0
  102. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/paths.ts +3 -41
  103. package/runtime/node_modules/@metro-labs/daemon/src/channels/addressed.ts +26 -0
  104. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/inbound.ts +99 -73
  105. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/media-note.ts +11 -7
  106. package/runtime/node_modules/@metro-labs/daemon/src/channels/notice.ts +22 -0
  107. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/pending.ts +13 -1
  108. package/runtime/node_modules/@metro-labs/daemon/src/channels/react-note.ts +13 -0
  109. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/relay.ts +6 -2
  110. package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +269 -0
  111. package/runtime/node_modules/@metro-labs/daemon/src/claude/cli-files.ts +28 -0
  112. package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +359 -0
  113. package/runtime/node_modules/@metro-labs/daemon/src/claude/github-api.ts +12 -0
  114. package/runtime/node_modules/@metro-labs/daemon/src/claude/github-fetch.ts +160 -0
  115. package/runtime/node_modules/@metro-labs/daemon/src/claude/github-skills.ts +255 -0
  116. package/runtime/node_modules/@metro-labs/daemon/src/claude/github-validate.ts +53 -0
  117. package/runtime/node_modules/@metro-labs/daemon/src/claude/hooks.ts +60 -0
  118. package/runtime/node_modules/@metro-labs/daemon/src/claude/memory-routine.ts +123 -0
  119. package/runtime/node_modules/@metro-labs/daemon/src/claude/memory.ts +32 -0
  120. package/runtime/node_modules/@metro-labs/daemon/src/claude/runner-activity.ts +17 -0
  121. package/runtime/node_modules/@metro-labs/daemon/src/claude/runner-process.ts +52 -0
  122. package/runtime/node_modules/@metro-labs/daemon/src/claude/session-files.ts +75 -0
  123. package/runtime/node_modules/@metro-labs/daemon/src/claude/session.ts +294 -0
  124. package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +109 -0
  125. package/runtime/node_modules/@metro-labs/daemon/src/claude/setup-api.ts +114 -0
  126. package/runtime/node_modules/@metro-labs/daemon/src/claude/setup-state.ts +18 -0
  127. package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +325 -0
  128. package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +123 -0
  129. package/runtime/node_modules/@metro-labs/daemon/src/connectors/agent-key.ts +145 -0
  130. package/runtime/node_modules/@metro-labs/daemon/src/connectors/enroll-api.ts +99 -0
  131. package/runtime/node_modules/@metro-labs/daemon/src/connectors/leftovers.ts +59 -0
  132. package/runtime/node_modules/@metro-labs/daemon/src/connectors/metro-api.ts +93 -0
  133. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-grant.ts +4 -4
  134. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-owner.ts +3 -3
  135. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-reaper.ts +174 -0
  136. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-serve.ts +11 -19
  137. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-api.ts +10 -27
  138. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-store.ts +4 -4
  139. package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +253 -0
  140. package/runtime/node_modules/@metro-labs/daemon/src/gateway/cache-ttl.ts +43 -0
  141. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +186 -0
  142. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +209 -0
  143. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-version.ts +44 -0
  144. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +137 -0
  145. package/runtime/node_modules/@metro-labs/daemon/src/gateway/delivered.ts +102 -0
  146. package/runtime/node_modules/@metro-labs/daemon/src/gateway/effective.ts +32 -0
  147. package/runtime/node_modules/@metro-labs/daemon/src/gateway/effort.ts +130 -0
  148. package/runtime/node_modules/@metro-labs/daemon/src/gateway/eventstream.ts +123 -0
  149. package/runtime/node_modules/@metro-labs/daemon/src/gateway/failures.ts +40 -0
  150. package/runtime/node_modules/@metro-labs/daemon/src/gateway/fallback.ts +149 -0
  151. package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +305 -0
  152. package/runtime/node_modules/@metro-labs/daemon/src/gateway/frames.ts +118 -0
  153. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +372 -0
  154. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +121 -0
  155. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +150 -0
  156. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-leftovers.ts +63 -0
  157. package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +25 -0
  158. package/runtime/node_modules/@metro-labs/daemon/src/gateway/org-models.ts +203 -0
  159. package/runtime/node_modules/@metro-labs/daemon/src/gateway/routeway.ts +88 -0
  160. package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +18 -0
  161. package/runtime/node_modules/@metro-labs/daemon/src/gateway/subscription.ts +60 -0
  162. package/runtime/node_modules/@metro-labs/daemon/src/gateway/text.ts +33 -0
  163. package/runtime/node_modules/@metro-labs/daemon/src/gateway/tool-search.ts +126 -0
  164. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage-refresh.ts +51 -0
  165. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +265 -0
  166. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/accounts.ts +66 -19
  167. package/runtime/node_modules/@metro-labs/daemon/src/mcp/attachment-schema.ts +91 -0
  168. package/runtime/node_modules/@metro-labs/daemon/src/mcp/call-bridge.ts +45 -0
  169. package/runtime/node_modules/@metro-labs/daemon/src/mcp/call-permission.ts +25 -0
  170. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/call-tools.ts +88 -38
  171. package/runtime/node_modules/@metro-labs/daemon/src/mcp/channel-tool.ts +80 -0
  172. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/ctx.ts +4 -4
  173. package/runtime/node_modules/@metro-labs/daemon/src/mcp/diagnostics.ts +102 -0
  174. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/event-store.ts +24 -18
  175. package/runtime/node_modules/@metro-labs/daemon/src/mcp/frame-schema.ts +44 -0
  176. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/group-tools.ts +2 -2
  177. package/runtime/node_modules/@metro-labs/daemon/src/mcp/index.ts +167 -0
  178. package/runtime/node_modules/@metro-labs/daemon/src/mcp/instructions.ts +21 -0
  179. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/member-tools.ts +2 -2
  180. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-prompt.ts +115 -0
  181. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +111 -0
  182. package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-gate.ts +88 -0
  183. package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-snapshot.ts +65 -0
  184. package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-lookup.ts +60 -0
  185. package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-tool.ts +96 -0
  186. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/raw-get-stream.ts +55 -17
  187. package/runtime/node_modules/@metro-labs/daemon/src/mcp/read-tool.ts +87 -0
  188. package/runtime/node_modules/@metro-labs/daemon/src/mcp/request-identity.ts +48 -0
  189. package/runtime/node_modules/@metro-labs/daemon/src/mcp/server-approvals.ts +118 -0
  190. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-slot.ts +137 -0
  191. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/session.ts +103 -52
  192. package/runtime/node_modules/@metro-labs/daemon/src/mcp/speech-schema.ts +11 -0
  193. package/runtime/node_modules/@metro-labs/daemon/src/mcp/speech-send.ts +15 -0
  194. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-catalog.ts +108 -0
  195. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-def.ts +9 -0
  196. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-dispatch.ts +74 -48
  197. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-schemas.ts +87 -114
  198. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/upload-tool.ts +6 -11
  199. package/runtime/node_modules/@metro-labs/daemon/src/mcp-server/announced.ts +68 -0
  200. package/runtime/node_modules/@metro-labs/daemon/src/mcp-server/config.ts +29 -0
  201. package/runtime/node_modules/@metro-labs/daemon/src/mcp-server/connector-tools.ts +114 -0
  202. package/runtime/node_modules/@metro-labs/daemon/src/mcp-server/link.ts +197 -0
  203. package/runtime/node_modules/@metro-labs/daemon/src/mcp-server/rpc.ts +67 -0
  204. package/runtime/node_modules/@metro-labs/daemon/src/mcp-server/token.ts +50 -0
  205. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/helper-script.ts +183 -0
  206. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/imds.ts +16 -0
  207. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/install.ts +78 -0
  208. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/privilege.ts +50 -0
  209. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/root-follow.ts +16 -0
  210. package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +132 -0
  211. package/runtime/node_modules/@metro-labs/daemon/src/monitor/run-event.ts +139 -0
  212. package/runtime/node_modules/@metro-labs/daemon/src/monitor/run-events.ts +101 -0
  213. package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +323 -0
  214. package/runtime/node_modules/@metro-labs/daemon/src/policy/policy.ts +120 -0
  215. package/runtime/node_modules/@metro-labs/daemon/src/routes/bearer.ts +35 -0
  216. package/runtime/node_modules/@metro-labs/daemon/src/routes/body.ts +24 -0
  217. package/runtime/node_modules/@metro-labs/daemon/src/routes/gmail-attach.ts +67 -0
  218. package/runtime/node_modules/@metro-labs/daemon/src/routes/gmail-detach.ts +37 -0
  219. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/routes}/http.ts +55 -56
  220. package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +155 -0
  221. package/runtime/node_modules/@metro-labs/daemon/src/routes/pair-again.ts +23 -0
  222. package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +63 -0
  223. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/session-api.ts → daemon/src/routes/session.ts} +9 -7
  224. package/runtime/node_modules/@metro-labs/daemon/src/routes/threema-callback.ts +103 -0
  225. package/runtime/node_modules/@metro-labs/daemon/src/server/cloudwatch.ts +178 -0
  226. package/runtime/node_modules/@metro-labs/daemon/src/server/control.ts +39 -0
  227. package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +58 -0
  228. package/runtime/node_modules/@metro-labs/daemon/src/server/owner.ts +26 -0
  229. package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +90 -0
  230. package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
  231. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-browser.ts +107 -0
  232. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-driver.ts +42 -0
  233. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-gmail.ts +78 -0
  234. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-inline.ts +29 -1
  235. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-interactive.ts +6 -32
  236. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-resolve.ts +84 -13
  237. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/attach-session.ts +70 -27
  238. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-xmtp.ts +8 -9
  239. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach.ts +69 -3
  240. package/runtime/node_modules/@metro-labs/{mcp/src/db → daemon/src/stations}/materialize.ts +50 -181
  241. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/registry.ts +26 -2
  242. package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +135 -0
  243. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor-io.ts +3 -3
  244. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor.ts +5 -5
  245. package/runtime/node_modules/@metro-labs/daemon/src/stations/threema-callbacks.ts +32 -0
  246. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/train-call.ts +1 -1
  247. package/runtime/node_modules/@metro-labs/daemon/src/stations/webhook-endpoints.ts +51 -0
  248. package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +84 -0
  249. package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +124 -0
  250. package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +15 -0
  251. package/runtime/node_modules/@metro-labs/daemon/src/voice/api.ts +14 -0
  252. package/runtime/node_modules/@metro-labs/daemon/src/voice/audio.ts +193 -0
  253. package/runtime/node_modules/@metro-labs/daemon/src/voice/call.ts +191 -0
  254. package/runtime/node_modules/@metro-labs/daemon/src/voice/calls.ts +153 -0
  255. package/runtime/node_modules/@metro-labs/daemon/src/voice/peer.ts +85 -0
  256. package/runtime/node_modules/@metro-labs/daemon/src/voice/scribe.ts +115 -0
  257. package/runtime/node_modules/@metro-labs/daemon/src/voice/shared-talk.ts +85 -0
  258. package/runtime/node_modules/@metro-labs/daemon/src/voice/shared.ts +198 -0
  259. package/runtime/node_modules/@metro-labs/daemon/src/voice/speech-queue.ts +200 -0
  260. package/runtime/node_modules/@metro-labs/daemon/src/voice/speech.ts +125 -0
  261. package/runtime/node_modules/@metro-labs/daemon/src/voice/store.ts +103 -0
  262. package/runtime/node_modules/@metro-labs/discord-bot/package.json +3 -5
  263. package/runtime/node_modules/@metro-labs/discord-bot/src/accounts.ts +3 -23
  264. package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +21 -187
  265. package/runtime/node_modules/@metro-labs/discord-bot/src/attachments.ts +2 -2
  266. package/runtime/node_modules/@metro-labs/discord-bot/src/channel-source.ts +79 -0
  267. package/runtime/node_modules/@metro-labs/discord-bot/src/channels.ts +186 -0
  268. package/runtime/node_modules/@metro-labs/discord-bot/src/format.ts +26 -67
  269. package/runtime/node_modules/@metro-labs/discord-bot/src/group-actions.ts +1 -1
  270. package/runtime/node_modules/@metro-labs/discord-bot/src/group.ts +2 -2
  271. package/runtime/node_modules/@metro-labs/discord-bot/src/index.ts +8 -14
  272. package/runtime/node_modules/@metro-labs/discord-bot/src/members.ts +2 -2
  273. package/runtime/node_modules/@metro-labs/discord-bot/src/profile.ts +68 -0
  274. package/runtime/node_modules/@metro-labs/discord-bot/src/send-files.ts +12 -13
  275. package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +6 -1
  276. package/runtime/node_modules/@metro-labs/gmail/package.json +27 -0
  277. package/runtime/node_modules/@metro-labs/gmail/src/accounts.ts +133 -0
  278. package/runtime/node_modules/@metro-labs/gmail/src/actions.ts +20 -0
  279. package/runtime/node_modules/@metro-labs/gmail/src/api.ts +34 -0
  280. package/runtime/node_modules/@metro-labs/gmail/src/attachments.ts +38 -0
  281. package/runtime/node_modules/@metro-labs/gmail/src/auth.ts +115 -0
  282. package/runtime/node_modules/@metro-labs/gmail/src/channels.ts +66 -0
  283. package/runtime/node_modules/@metro-labs/gmail/src/config.ts +15 -0
  284. package/runtime/node_modules/@metro-labs/gmail/src/inbound.ts +97 -0
  285. package/runtime/node_modules/@metro-labs/gmail/src/index.ts +12 -0
  286. package/runtime/node_modules/@metro-labs/gmail/src/login.ts +39 -0
  287. package/runtime/node_modules/@metro-labs/gmail/src/managed-binding.ts +33 -0
  288. package/runtime/node_modules/@metro-labs/gmail/src/managed.ts +45 -0
  289. package/runtime/node_modules/@metro-labs/gmail/src/message.ts +125 -0
  290. package/runtime/node_modules/@metro-labs/gmail/src/mime.ts +70 -0
  291. package/runtime/node_modules/@metro-labs/gmail/src/outbound.ts +125 -0
  292. package/runtime/node_modules/@metro-labs/gmail/src/query.ts +101 -0
  293. package/runtime/node_modules/@metro-labs/gmail/src/state.ts +30 -0
  294. package/runtime/node_modules/@metro-labs/gmail/src/station.ts +16 -0
  295. package/runtime/node_modules/@metro-labs/gmail/src/trust.ts +42 -0
  296. package/runtime/node_modules/@metro-labs/http/package.json +44 -0
  297. package/runtime/node_modules/@metro-labs/http/src/agent-signature.ts +95 -0
  298. package/runtime/node_modules/@metro-labs/http/src/api-http.ts +146 -0
  299. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/oauth-discovery.ts → http/src/connector-discovery.ts} +57 -27
  300. package/runtime/node_modules/@metro-labs/http/src/connector-grant.ts +8 -0
  301. package/runtime/node_modules/@metro-labs/http/src/connector-input.ts +73 -0
  302. package/runtime/node_modules/@metro-labs/http/src/connector-mcp.ts +108 -0
  303. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/oauth-client.ts → http/src/connector-oauth.ts} +60 -31
  304. package/runtime/node_modules/@metro-labs/http/src/connector-policy.ts +92 -0
  305. package/runtime/node_modules/@metro-labs/http/src/connector-public-url.ts +64 -0
  306. package/runtime/node_modules/@metro-labs/http/src/connector-reach.ts +27 -0
  307. package/runtime/node_modules/@metro-labs/http/src/connector-resource.ts +108 -0
  308. package/runtime/node_modules/@metro-labs/http/src/connector-tools.ts +101 -0
  309. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/connector-url.ts +8 -28
  310. package/runtime/node_modules/@metro-labs/http/src/ed25519.ts +56 -0
  311. package/runtime/node_modules/@metro-labs/http/src/mcp-server-protocol.ts +99 -0
  312. package/runtime/node_modules/@metro-labs/http/src/mcp-server-tools.ts +104 -0
  313. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/mode-api.ts +2 -2
  314. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/session-config.ts → http/src/return-to.ts} +4 -6
  315. package/runtime/node_modules/@metro-labs/http/src/sigv4.ts +90 -0
  316. package/runtime/node_modules/@metro-labs/http/src/workos-token.ts +149 -0
  317. package/runtime/node_modules/@metro-labs/outlook/package.json +25 -0
  318. package/runtime/node_modules/@metro-labs/outlook/src/accounts.ts +78 -0
  319. package/runtime/node_modules/@metro-labs/outlook/src/actions.ts +15 -0
  320. package/runtime/node_modules/@metro-labs/outlook/src/attachments.ts +81 -0
  321. package/runtime/node_modules/@metro-labs/outlook/src/auth.ts +120 -0
  322. package/runtime/node_modules/@metro-labs/outlook/src/browser.ts +42 -0
  323. package/runtime/node_modules/@metro-labs/outlook/src/channels.ts +60 -0
  324. package/runtime/node_modules/@metro-labs/outlook/src/config.ts +23 -0
  325. package/runtime/node_modules/@metro-labs/outlook/src/format.ts +59 -0
  326. package/runtime/node_modules/@metro-labs/outlook/src/graph.ts +55 -0
  327. package/runtime/node_modules/@metro-labs/outlook/src/inbound.ts +96 -0
  328. package/runtime/node_modules/@metro-labs/outlook/src/index.ts +12 -0
  329. package/runtime/node_modules/@metro-labs/outlook/src/login.ts +129 -0
  330. package/runtime/node_modules/@metro-labs/outlook/src/me.ts +31 -0
  331. package/runtime/node_modules/@metro-labs/outlook/src/outbound.ts +103 -0
  332. package/runtime/node_modules/@metro-labs/outlook/src/query.ts +84 -0
  333. package/runtime/node_modules/@metro-labs/outlook/src/state.ts +28 -0
  334. package/runtime/node_modules/@metro-labs/outlook/src/station.ts +16 -0
  335. package/runtime/node_modules/@metro-labs/outlook/src/trust.ts +41 -0
  336. package/runtime/node_modules/@metro-labs/telegram/package.json +2 -4
  337. package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +5 -24
  338. package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +27 -6
  339. package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +1 -1
  340. package/runtime/node_modules/@metro-labs/telegram/src/channels.ts +58 -0
  341. package/runtime/node_modules/@metro-labs/telegram/src/client.ts +4 -4
  342. package/runtime/node_modules/@metro-labs/telegram/src/format.ts +19 -34
  343. package/runtime/node_modules/@metro-labs/telegram/src/group.ts +3 -3
  344. package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +13 -34
  345. package/runtime/node_modules/@metro-labs/telegram/src/index.ts +4 -43
  346. package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +2 -3
  347. package/runtime/node_modules/@metro-labs/telegram/src/members.ts +1 -1
  348. package/runtime/node_modules/@metro-labs/telegram/src/profile.ts +70 -0
  349. package/runtime/node_modules/@metro-labs/telegram/src/reactions.ts +2 -2
  350. package/runtime/node_modules/@metro-labs/telegram/src/station.ts +5 -1
  351. package/runtime/node_modules/@metro-labs/telegram/src/types.ts +0 -1
  352. package/runtime/node_modules/@metro-labs/telegram-bot/package.json +2 -2
  353. package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +7 -41
  354. package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +24 -77
  355. package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +2 -2
  356. package/runtime/node_modules/@metro-labs/telegram-bot/src/channel-files.ts +3 -0
  357. package/runtime/node_modules/@metro-labs/telegram-bot/src/channels.ts +43 -0
  358. package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +46 -48
  359. package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +15 -44
  360. package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +6 -82
  361. package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +1 -1
  362. package/runtime/node_modules/@metro-labs/telegram-bot/src/observed-chats.ts +172 -0
  363. package/runtime/node_modules/@metro-labs/telegram-bot/src/profile.ts +85 -0
  364. package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +9 -1
  365. package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +50 -15
  366. package/runtime/node_modules/@metro-labs/telegram-bot/src/updates.ts +26 -0
  367. package/runtime/node_modules/@metro-labs/threema/package.json +26 -0
  368. package/runtime/node_modules/@metro-labs/threema/src/accounts.ts +108 -0
  369. package/runtime/node_modules/@metro-labs/threema/src/actions.ts +130 -0
  370. package/runtime/node_modules/@metro-labs/threema/src/api.ts +152 -0
  371. package/runtime/node_modules/@metro-labs/threema/src/channels.ts +37 -0
  372. package/runtime/node_modules/@metro-labs/threema/src/chats.ts +88 -0
  373. package/runtime/node_modules/@metro-labs/threema/src/crypto.ts +100 -0
  374. package/runtime/node_modules/@metro-labs/threema/src/files.ts +47 -0
  375. package/runtime/node_modules/@metro-labs/threema/src/format.ts +164 -0
  376. package/runtime/node_modules/@metro-labs/threema/src/groups.ts +96 -0
  377. package/runtime/node_modules/@metro-labs/threema/src/ids.ts +21 -0
  378. package/runtime/node_modules/@metro-labs/threema/src/inbound.ts +92 -0
  379. package/runtime/node_modules/@metro-labs/threema/src/index.ts +24 -0
  380. package/runtime/node_modules/@metro-labs/threema/src/messages.ts +264 -0
  381. package/runtime/node_modules/@metro-labs/threema/src/outbound.ts +161 -0
  382. package/runtime/node_modules/@metro-labs/threema/src/station.ts +21 -0
  383. package/runtime/node_modules/@metro-labs/threema/src/verify.ts +117 -0
  384. package/runtime/node_modules/@metro-labs/webhook/package.json +2 -2
  385. package/runtime/node_modules/@metro-labs/webhook/src/station.ts +5 -8
  386. package/runtime/node_modules/@metro-labs/whatsapp/package.json +3 -6
  387. package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +6 -28
  388. package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +1 -1
  389. package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +100 -14
  390. package/runtime/node_modules/@metro-labs/whatsapp/src/app-state.ts +49 -0
  391. package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +2 -2
  392. package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +1 -1
  393. package/runtime/node_modules/@metro-labs/whatsapp/src/channel-chats.ts +137 -0
  394. package/runtime/node_modules/@metro-labs/whatsapp/src/channels.ts +48 -0
  395. package/runtime/node_modules/@metro-labs/whatsapp/src/client-history.ts +31 -0
  396. package/runtime/node_modules/@metro-labs/whatsapp/src/client-types.ts +50 -0
  397. package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +161 -84
  398. package/runtime/node_modules/@metro-labs/whatsapp/src/connection.ts +139 -0
  399. package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +7 -58
  400. package/runtime/node_modules/@metro-labs/whatsapp/src/history-events.ts +127 -0
  401. package/runtime/node_modules/@metro-labs/whatsapp/src/history-files.ts +39 -0
  402. package/runtime/node_modules/@metro-labs/whatsapp/src/history-identity.ts +58 -0
  403. package/runtime/node_modules/@metro-labs/whatsapp/src/history-message.ts +161 -0
  404. package/runtime/node_modules/@metro-labs/whatsapp/src/history-state.ts +344 -0
  405. package/runtime/node_modules/@metro-labs/whatsapp/src/history-types.ts +91 -0
  406. package/runtime/node_modules/@metro-labs/whatsapp/src/history.ts +195 -0
  407. package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +11 -28
  408. package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +4 -37
  409. package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +1 -1
  410. package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +37 -4
  411. package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +1 -1
  412. package/runtime/node_modules/@metro-labs/whatsapp/src/members.ts +94 -0
  413. package/runtime/node_modules/@metro-labs/whatsapp/src/messages.ts +91 -0
  414. package/runtime/node_modules/@metro-labs/whatsapp/src/names.ts +106 -0
  415. package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +44 -0
  416. package/runtime/node_modules/@metro-labs/whatsapp/src/profile.ts +158 -0
  417. package/runtime/node_modules/@metro-labs/whatsapp/src/resolve.ts +52 -0
  418. package/runtime/node_modules/@metro-labs/whatsapp/src/send-expiry.ts +65 -0
  419. package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +26 -1
  420. package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +5 -9
  421. package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +0 -1
  422. package/runtime/node_modules/@metro-labs/xmtp/package.json +4 -3
  423. package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +10 -20
  424. package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +2 -2
  425. package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +55 -224
  426. package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +55 -54
  427. package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +114 -223
  428. package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +58 -15
  429. package/runtime/node_modules/@metro-labs/xmtp/src/call-leftovers.ts +48 -0
  430. package/runtime/node_modules/@metro-labs/xmtp/src/channels.ts +56 -0
  431. package/runtime/node_modules/@metro-labs/xmtp/src/codecs.ts +114 -3
  432. package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +36 -20
  433. package/runtime/node_modules/@metro-labs/xmtp/src/delete-requests.ts +34 -0
  434. package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +38 -25
  435. package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +8 -18
  436. package/runtime/node_modules/@metro-labs/xmtp/src/frames.ts +190 -0
  437. package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +1 -1
  438. package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +2 -2
  439. package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +30 -16
  440. package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +18 -70
  441. package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +102 -50
  442. package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +1 -1
  443. package/runtime/node_modules/@metro-labs/xmtp/src/names.ts +61 -0
  444. package/runtime/node_modules/@metro-labs/xmtp/src/network.ts +114 -0
  445. package/runtime/node_modules/@metro-labs/xmtp/src/profile.ts +160 -0
  446. package/runtime/node_modules/@metro-labs/xmtp/src/read-attachments.ts +37 -0
  447. package/runtime/node_modules/@metro-labs/xmtp/src/resolve.ts +44 -0
  448. package/runtime/node_modules/@metro-labs/xmtp/src/sender.ts +112 -0
  449. package/runtime/node_modules/@metro-labs/xmtp/src/smart.ts +79 -0
  450. package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +10 -2
  451. package/runtime/node_modules/@metro-labs/xmtp/src/stream.ts +66 -0
  452. package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +32 -60
  453. package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +78 -49
  454. package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +4 -6
  455. package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +19 -5
  456. package/runtime/node_modules/@metro-labs/xmtp/src/wallet.ts +28 -0
  457. package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +14 -4
  458. package/runtime/patches/5bca2c07d5852d3f58453cff0448dd85da13d3665b61e3d758905b298d432d7c.patch +31 -0
  459. package/runtime/runtime.json +1 -1
  460. package/runtime/sdk-runner/node_modules/@metro-labs/core/package.json +61 -0
  461. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/automation-files.ts +216 -0
  462. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/automation-store.ts +171 -0
  463. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/automation-types.ts +141 -0
  464. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/call.ts +81 -0
  465. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/claude-token.ts +3 -0
  466. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/effort.ts +21 -0
  467. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
  468. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/events.ts +165 -0
  469. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/ids.ts +28 -0
  470. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/is-record.ts +2 -0
  471. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/lines.ts +78 -0
  472. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/log.ts +42 -0
  473. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/protocol.ts +227 -0
  474. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/runner-activity.ts +270 -0
  475. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/secure-fs.ts +74 -0
  476. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/skill-source.ts +96 -0
  477. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/station-names.ts +14 -0
  478. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/stations/account-files.ts +41 -0
  479. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/stations/account-status.ts +26 -0
  480. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/stations/account-store.ts +83 -0
  481. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/stations/attachments.ts +202 -0
  482. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/stations/channel-directory.ts +159 -0
  483. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/stations/channel-pages.ts +129 -0
  484. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/stations/mail-text.ts +72 -0
  485. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/stations/mail-trust.ts +29 -0
  486. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/stations/mail.ts +212 -0
  487. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/stations/messaging-normalize.ts +16 -0
  488. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/stations/oauth.ts +126 -0
  489. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/stations/profile.ts +58 -0
  490. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/stations/sender-profile.ts +64 -0
  491. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/stations/station-runtime.ts +59 -0
  492. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/stations/train-boot.ts +63 -0
  493. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/stations/train-events.ts +84 -0
  494. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/stations/types.ts +128 -0
  495. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/str.ts +5 -0
  496. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/tickets.ts +44 -0
  497. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/train-error.ts +53 -0
  498. package/runtime/sdk-runner/node_modules/@metro-labs/core/src/version.ts +2 -0
  499. package/runtime/sdk-runner/runner.json +10 -0
  500. package/runtime/sdk-runner/src/activity-tasks.ts +194 -0
  501. package/runtime/sdk-runner/src/activity.ts +392 -0
  502. package/runtime/sdk-runner/src/app.ts +87 -0
  503. package/runtime/sdk-runner/src/approvals.ts +37 -0
  504. package/runtime/sdk-runner/src/automation-cli.ts +10 -0
  505. package/runtime/sdk-runner/src/automation-command.ts +151 -0
  506. package/runtime/sdk-runner/src/automation.ts +145 -0
  507. package/runtime/sdk-runner/src/calls.ts +133 -0
  508. package/runtime/sdk-runner/src/channel-text.ts +26 -0
  509. package/runtime/sdk-runner/src/config.ts +50 -0
  510. package/runtime/sdk-runner/src/errors.ts +142 -0
  511. package/runtime/sdk-runner/src/inbox.ts +168 -0
  512. package/runtime/sdk-runner/src/input-queue.ts +77 -0
  513. package/runtime/sdk-runner/src/input-timing.ts +68 -0
  514. package/runtime/sdk-runner/src/link.ts +154 -0
  515. package/runtime/sdk-runner/src/main.ts +57 -0
  516. package/runtime/sdk-runner/src/recovery.ts +46 -0
  517. package/runtime/sdk-runner/src/rules.ts +28 -0
  518. package/runtime/sdk-runner/src/runner.ts +358 -0
  519. package/runtime/sdk-runner/src/session-store.ts +129 -0
  520. package/runtime/sdk-runner/src/session-watch.ts +158 -0
  521. package/runtime/sdk-runner/src/singleton.ts +15 -0
  522. package/runtime/sdk-runner/src/skill-work.ts +76 -0
  523. package/runtime/sdk-runner/src/skills-files.ts +169 -0
  524. package/runtime/sdk-runner/src/skills.ts +150 -0
  525. package/runtime/sdk-runner/src/task-ledger.ts +244 -0
  526. package/runtime/sdk-runner/src/task-recovery.ts +203 -0
  527. package/runtime/sdk-runner/src/task-state.ts +77 -0
  528. package/runtime/sdk-runner/src/tool-proxy.ts +40 -0
  529. package/runtime/server.ts +1 -0
  530. package/runtime/stations.json +43 -0
  531. package/skills/MEMORY.md +78 -0
  532. package/skills/METRO.md +35 -0
  533. package/skills/STAGE.md +110 -0
  534. package/dist/bedrock-eventstream.js +0 -120
  535. package/dist/bedrock-proxy.js +0 -260
  536. package/dist/bedrock-upstream.js +0 -72
  537. package/dist/bedrock.js +0 -106
  538. package/dist/claude.js +0 -15
  539. package/dist/plugin.js +0 -82
  540. package/dist/prompt.js +0 -61
  541. package/dist/store.js +0 -93
  542. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-speak.ts +0 -195
  543. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-transcribe.ts +0 -292
  544. package/runtime/node_modules/@metro-labs/discord-bot/src/voice.ts +0 -197
  545. package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +0 -5
  546. package/runtime/node_modules/@metro-labs/mcp/package.json +0 -67
  547. package/runtime/node_modules/@metro-labs/mcp/src/channels/dedupe.ts +0 -24
  548. package/runtime/node_modules/@metro-labs/mcp/src/daemon/account-api.ts +0 -311
  549. package/runtime/node_modules/@metro-labs/mcp/src/daemon/agent-api.ts +0 -333
  550. package/runtime/node_modules/@metro-labs/mcp/src/daemon/agent-connector-api.ts +0 -150
  551. package/runtime/node_modules/@metro-labs/mcp/src/daemon/agent-pair.ts +0 -20
  552. package/runtime/node_modules/@metro-labs/mcp/src/daemon/api-http.ts +0 -153
  553. package/runtime/node_modules/@metro-labs/mcp/src/daemon/boot.ts +0 -368
  554. package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair-api.ts +0 -134
  555. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-api.ts +0 -313
  556. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-json.ts +0 -21
  557. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-oauth-routes.ts +0 -157
  558. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-oauth.ts +0 -127
  559. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-tools.ts +0 -100
  560. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-verify.ts +0 -333
  561. package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity.ts +0 -86
  562. package/runtime/node_modules/@metro-labs/mcp/src/daemon/local-mode.ts +0 -158
  563. package/runtime/node_modules/@metro-labs/mcp/src/daemon/local-secret.ts +0 -21
  564. package/runtime/node_modules/@metro-labs/mcp/src/daemon/oauth-pending.ts +0 -65
  565. package/runtime/node_modules/@metro-labs/mcp/src/daemon/pair-codes.ts +0 -58
  566. package/runtime/node_modules/@metro-labs/mcp/src/daemon/project-api.ts +0 -214
  567. package/runtime/node_modules/@metro-labs/mcp/src/daemon/relay.ts +0 -303
  568. package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-api.ts +0 -139
  569. package/runtime/node_modules/@metro-labs/mcp/src/daemon/runtime-source.ts +0 -105
  570. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session-apis.ts +0 -52
  571. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session.ts +0 -218
  572. package/runtime/node_modules/@metro-labs/mcp/src/daemon/siwe-auth.ts +0 -82
  573. package/runtime/node_modules/@metro-labs/mcp/src/daemon/siwe-nonces.ts +0 -43
  574. package/runtime/node_modules/@metro-labs/mcp/src/daemon/siwe-routes.ts +0 -89
  575. package/runtime/node_modules/@metro-labs/mcp/src/daemon/tunnel.ts +0 -169
  576. package/runtime/node_modules/@metro-labs/mcp/src/db/account-attach.ts +0 -91
  577. package/runtime/node_modules/@metro-labs/mcp/src/db/agent-admin.ts +0 -214
  578. package/runtime/node_modules/@metro-labs/mcp/src/db/agent-connectors.ts +0 -143
  579. package/runtime/node_modules/@metro-labs/mcp/src/db/agent-map.ts +0 -71
  580. package/runtime/node_modules/@metro-labs/mcp/src/db/client.ts +0 -37
  581. package/runtime/node_modules/@metro-labs/mcp/src/db/connector-config.ts +0 -147
  582. package/runtime/node_modules/@metro-labs/mcp/src/db/connector-relay.ts +0 -126
  583. package/runtime/node_modules/@metro-labs/mcp/src/db/connectors.ts +0 -308
  584. package/runtime/node_modules/@metro-labs/mcp/src/db/file-admin.ts +0 -250
  585. package/runtime/node_modules/@metro-labs/mcp/src/db/projects.ts +0 -309
  586. package/runtime/node_modules/@metro-labs/mcp/src/db/runtime-admin.ts +0 -24
  587. package/runtime/node_modules/@metro-labs/mcp/src/db/runtimes.ts +0 -105
  588. package/runtime/node_modules/@metro-labs/mcp/src/db/schema.ts +0 -118
  589. package/runtime/node_modules/@metro-labs/mcp/src/db/token-carry.ts +0 -45
  590. package/runtime/node_modules/@metro-labs/mcp/src/db/users.ts +0 -72
  591. package/runtime/node_modules/@metro-labs/mcp/src/db/whatsapp-login.ts +0 -18
  592. package/runtime/node_modules/@metro-labs/mcp/src/mcp/channel-owner.ts +0 -29
  593. package/runtime/node_modules/@metro-labs/mcp/src/mcp/frame-scope.ts +0 -21
  594. package/runtime/node_modules/@metro-labs/mcp/src/mcp/index.ts +0 -192
  595. package/runtime/node_modules/@metro-labs/mcp/src/mcp/permission-relay.ts +0 -66
  596. package/runtime/node_modules/@metro-labs/mcp/src/mcp/request-identity.ts +0 -73
  597. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-registry.ts +0 -172
  598. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-route.ts +0 -43
  599. package/runtime/node_modules/@metro-labs/mcp/src/monitor/api.ts +0 -240
  600. package/runtime/node_modules/@metro-labs/mcp/src/server.ts +0 -2
  601. package/runtime/node_modules/@metro-labs/mcp/src/stations/account-store.ts +0 -80
  602. package/runtime/node_modules/@metro-labs/mcp/src/stations/messaging-normalize.ts +0 -88
  603. package/runtime/node_modules/@metro-labs/telegram/src/normalize.ts +0 -22
  604. package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +0 -1
  605. package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +0 -3
  606. package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +0 -22
  607. package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +0 -5
  608. package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +0 -87
  609. package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +0 -55
  610. package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +0 -349
  611. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/log.ts +0 -0
  612. /package/runtime/node_modules/@metro-labs/{mcp/src/mcp → core/src}/str.ts +0 -0
  613. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/train-error.ts +0 -0
  614. /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/webhook-note.ts +0 -0
  615. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/api-error.ts +0 -0
  616. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/cors.ts +0 -0
@@ -0,0 +1,160 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { isRecord } from '@metro-labs/core/is-record';
3
+ import { SKILL_COMMIT, SKILL_FILE_MAX, SKILL_FILES_MAX, SKILL_TOTAL_MAX, skillPath, type SkillSource } from '@metro-labs/core/skill-source';
4
+
5
+ export class GitHubFailure extends Error {
6
+ constructor(message: string, readonly retryAt = Date.now() + 60_000, readonly rateLimited = false) { super(message); }
7
+ }
8
+
9
+ export interface GitHubSnapshot {
10
+ repositoryId: number;
11
+ commit: string;
12
+ etag: string | null;
13
+ files: Map<string, Buffer>;
14
+ executables?: string[];
15
+ }
16
+
17
+ interface Entry { path: string; mode: string; type: string; sha: string; size: number }
18
+ type Request = (url: string, init: RequestInit) => Promise<Response>;
19
+ const API = 'https://api.github.com/repos/';
20
+ const RESPONSE_MAX = 2 * 1024 * 1024;
21
+
22
+ async function boundedJson(response: Response, text: boolean): Promise<unknown> {
23
+ if (response.body === null) throw new GitHubFailure('GitHub returned an empty response.');
24
+ const reader = response.body.getReader();
25
+ const chunks: Uint8Array[] = [];
26
+ let bytes = 0;
27
+ try {
28
+ for (;;) {
29
+ const { done, value } = await reader.read();
30
+ if (done) break;
31
+ bytes += value.byteLength;
32
+ if (bytes > RESPONSE_MAX) throw new GitHubFailure('GitHub returned too much data. Choose a smaller skills folder.');
33
+ chunks.push(value);
34
+ }
35
+ const body = Buffer.concat(chunks).toString('utf8');
36
+ return text ? body.trim() : JSON.parse(body) as unknown;
37
+ } finally { await reader.cancel().catch(() => undefined); }
38
+ }
39
+
40
+ function refused(response: Response): GitHubFailure {
41
+ const retry = Number(response.headers.get('retry-after'));
42
+ const reset = Number(response.headers.get('x-ratelimit-reset')) * 1000;
43
+ if (response.status === 429 || (response.status === 403 && (response.headers.get('x-ratelimit-remaining') === '0' || retry > 0))) {
44
+ return new GitHubFailure('GitHub rate limit reached. Sync will retry later.', Math.max(Date.now() + 60_000, Date.now() + (Number.isFinite(retry) ? retry * 1000 : 0), Number.isFinite(reset) ? reset : 0), true);
45
+ }
46
+ if ([401, 403, 404].includes(response.status)) return new GitHubFailure('GitHub access was refused. Check the repository, ref, token expiry and organization approval. The loaded skills are kept.', Date.now() + 15 * 60_000);
47
+ return new GitHubFailure('GitHub could not provide the skills. The loaded skills are kept.');
48
+ }
49
+
50
+ function headers(token: string, etag: string | null | undefined, shaOnly: boolean): Record<string, string> {
51
+ return { Authorization: `Bearer ${token}`, Accept: shaOnly ? 'application/vnd.github.sha' : 'application/vnd.github+json', 'X-GitHub-Api-Version': '2022-11-28', ...(etag ? { 'If-None-Match': etag } : {}) };
52
+ }
53
+
54
+ export class GitHubReader {
55
+ private readonly base: string;
56
+ private count = 0;
57
+ private readonly signal = AbortSignal.timeout(120_000);
58
+ constructor(private readonly source: SkillSource, private readonly token: string, private readonly request: Request = fetch) {
59
+ this.base = `${API}${source.repository}`;
60
+ }
61
+
62
+ private async get(path: string, etag?: string | null, shaOnly = false): Promise<{ data: unknown; etag: string | null; unchanged: boolean }> {
63
+ if (++this.count > SKILL_FILES_MAX + 12) throw new GitHubFailure('The skills folder needs too many GitHub requests.');
64
+ let response: Response;
65
+ try {
66
+ response = await this.request(`${this.base}${path}`, {
67
+ headers: headers(this.token, etag, shaOnly),
68
+ redirect: 'manual', signal: AbortSignal.any([this.signal, AbortSignal.timeout(20_000)]),
69
+ });
70
+ } catch { throw new GitHubFailure('GitHub is unreachable. The loaded skills are kept.'); }
71
+ if (response.status === 304) return { data: null, etag: etag ?? null, unchanged: true };
72
+ if (!response.ok) { await response.body?.cancel(); throw refused(response); }
73
+ try { return { data: await boundedJson(response, shaOnly), etag: response.headers.get('etag'), unchanged: false }; }
74
+ catch (err) { if (err instanceof GitHubFailure) throw err; throw new GitHubFailure('GitHub returned invalid skills data.'); }
75
+ }
76
+
77
+ private async tree(sha: string, recursive: boolean): Promise<Entry[]> {
78
+ const { data } = await this.get(`/git/trees/${sha}${recursive ? '?recursive=1' : ''}`);
79
+ if (!isRecord(data) || data.truncated !== false || !Array.isArray(data.tree) || data.tree.length > 4096) throw new GitHubFailure('The GitHub tree is incomplete or too large. Choose a smaller skills folder.');
80
+ return data.tree.map((raw: unknown) => {
81
+ if (!isRecord(raw) || typeof raw.path !== 'string' || typeof raw.mode !== 'string' || typeof raw.type !== 'string' || typeof raw.sha !== 'string' || !SKILL_COMMIT.test(raw.sha)) throw new GitHubFailure('GitHub returned an invalid tree.');
82
+ return { path: raw.path, mode: raw.mode, type: raw.type, sha: raw.sha, size: typeof raw.size === 'number' ? raw.size : 0 };
83
+ });
84
+ }
85
+
86
+ private async folder(tree: string): Promise<string> {
87
+ let sha = tree;
88
+ for (const segment of this.source.folder.split('/').filter(Boolean)) {
89
+ const entry = (await this.tree(sha, false)).find((row) => row.path === segment);
90
+ if (entry?.mode !== '040000' || entry.type !== 'tree') throw new GitHubFailure('The selected skills folder is missing or is not a regular directory.');
91
+ sha = entry.sha;
92
+ }
93
+ return sha;
94
+ }
95
+
96
+ private async blob(entry: Entry): Promise<Buffer> {
97
+ const { data } = await this.get(`/git/blobs/${entry.sha}`);
98
+ if (!isRecord(data) || data.encoding !== 'base64' || typeof data.content !== 'string' || data.size !== entry.size) throw new GitHubFailure('GitHub returned an invalid skill file.');
99
+ const encoded = data.content.replace(/\n/g, '');
100
+ if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(encoded)) throw new GitHubFailure('GitHub returned an invalid skill file.');
101
+ const bytes = Buffer.from(encoded, 'base64');
102
+ const hash = createHash('sha1').update(`blob ${bytes.byteLength}\0`).update(bytes).digest('hex');
103
+ if (bytes.byteLength !== entry.size || hash !== entry.sha) throw new GitHubFailure('A skill file has an unexpected size or Git object hash.');
104
+ return bytes;
105
+ }
106
+
107
+ private async repository(expected: number | null): Promise<number> {
108
+ const repo = (await this.get('')).data;
109
+ if (!isRecord(repo) || typeof repo.id !== 'number' || typeof repo.full_name !== 'string' || repo.full_name.toLowerCase() !== this.source.repository.toLowerCase() || (expected !== null && repo.id !== expected)) throw new GitHubFailure('The GitHub repository identity changed. Reconnect it explicitly.');
110
+ return repo.id;
111
+ }
112
+
113
+ async snapshot(repositoryId: number | null, commit: string | null, etag: string | null): Promise<GitHubSnapshot | null> {
114
+ const id = await this.repository(repositoryId);
115
+ const resolved = await this.get(`/commits/${encodeURIComponent(this.source.ref)}`, etag, true);
116
+ if (resolved.unchanged) return null;
117
+ if (typeof resolved.data !== 'string' || !SKILL_COMMIT.test(resolved.data)) throw new GitHubFailure('GitHub did not resolve an immutable commit.');
118
+ if (resolved.data === commit) return null;
119
+ const data = immutableCommit((await this.get(`/git/commits/${resolved.data}`)).data);
120
+ if (data.sha !== resolved.data) throw new GitHubFailure('GitHub returned a different commit.');
121
+ const entries = checkedEntries(await this.tree(await this.folder(data.tree), true));
122
+ const files = await this.blobs(entries);
123
+ return { repositoryId: id, commit: data.sha, etag: resolved.etag, files, executables: entries.filter((entry) => entry.mode === '100755').map((entry) => entry.path) };
124
+ }
125
+
126
+ private async blobs(entries: Entry[]): Promise<Map<string, Buffer>> {
127
+ const queue = [...entries];
128
+ const files = new Map<string, Buffer>();
129
+ const worker = async (): Promise<void> => {
130
+ for (let entry = queue.shift(); entry !== undefined; entry = queue.shift()) files.set(entry.path, await this.blob(entry));
131
+ };
132
+ try { await Promise.all(Array.from({ length: Math.min(4, queue.length) }, worker)); }
133
+ catch (err) { queue.length = 0; throw err; }
134
+ return files;
135
+ }
136
+ }
137
+
138
+ function immutableCommit(data: unknown): { sha: string; tree: string } {
139
+ if (!isRecord(data) || typeof data.sha !== 'string' || !SKILL_COMMIT.test(data.sha) || !isRecord(data.tree) || typeof data.tree.sha !== 'string' || !SKILL_COMMIT.test(data.tree.sha)) throw new GitHubFailure('GitHub did not resolve an immutable commit.');
140
+ return { sha: data.sha, tree: data.tree.sha };
141
+ }
142
+
143
+ function regularFile(entry: Entry): void {
144
+ if (entry.type !== 'blob' || !['100644', '100755'].includes(entry.mode)) throw new GitHubFailure('Symlinks, submodules and special files are not supported in skills.');
145
+ if (!skillPath(entry.path) || entry.size < 0 || entry.size > SKILL_FILE_MAX || !Number.isInteger(entry.size)) throw new GitHubFailure('A skills path or file size is not supported. Use skill-name/SKILL.md and regular resources, up to 256 KiB each.');
146
+ }
147
+
148
+ function checkedEntries(entries: Entry[]): Entry[] {
149
+ const files: Entry[] = [];
150
+ let total = 0;
151
+ for (const entry of entries) {
152
+ if (entry.mode === '040000' && entry.type === 'tree') continue;
153
+ regularFile(entry);
154
+ total += entry.size;
155
+ files.push(entry);
156
+ }
157
+ if (files.length > SKILL_FILES_MAX || total > SKILL_TOTAL_MAX) throw new GitHubFailure('Skills exceed 256 files or 8 MiB.');
158
+ if (new Set(files.map((entry) => entry.path.toLowerCase())).size !== files.length) throw new GitHubFailure('Skills contain duplicate file paths.');
159
+ return files;
160
+ }
@@ -0,0 +1,255 @@
1
+ import { existsSync, readFileSync as readLocal, statSync as statLocal } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { Readable } from 'node:stream';
4
+ import { log } from '@metro-labs/core/log';
5
+ import { isRecord } from '@metro-labs/core/is-record';
6
+ import { writeSecure } from '@metro-labs/core/secure-fs';
7
+ import { SKILL_HASH, SKILL_MANIFEST_MAX, skillGeneration, skillRelease, skillSourceRoot, type SkillGeneration } from '@metro-labs/core/skill-source';
8
+ import { ApiError } from '@metro-labs/http/api-error';
9
+ import { readFileSync, statSync } from '../agent-user/agent-fs.js';
10
+ import { receiveHomeFile, writeHomeText } from '../agent-user/home-fs.js';
11
+ import { agentsDir } from '../agents/files.js';
12
+ import { claudeDir } from './files.js';
13
+ import { GitHubFailure, GitHubReader } from './github-fetch.js';
14
+ import { githubSource, validatedGeneration } from './github-validate.js';
15
+ import type { ClaudeSkill } from './skills.js';
16
+
17
+ type Configuration = ReturnType<typeof githubSource>;
18
+ interface Stored {
19
+ source: Configuration | null;
20
+ prepared: SkillGeneration | null;
21
+ etag: string | null;
22
+ checkedAt: string | null;
23
+ retryAt: number;
24
+ problem: string | null;
25
+ rateLimit: number;
26
+ repositoryId: number | null;
27
+ }
28
+ export interface GitHubSkillsDeps {
29
+ agents: string;
30
+ claude: string;
31
+ request?: (url: string, init: RequestInit) => Promise<Response>;
32
+ }
33
+ const EMPTY: Stored = { source: null, prepared: null, etag: null, checkedAt: null, retryAt: 0, problem: null, rateLimit: 0, repositoryId: null };
34
+ const savedString = (value: unknown): string | null => typeof value === 'string' ? value : null;
35
+ const savedNumber = (value: unknown): number => typeof value === 'number' && Number.isFinite(value) ? value : 0;
36
+
37
+ function readStored(path: string): Stored {
38
+ if (!existsSync(path)) return { ...EMPTY };
39
+ try {
40
+ if (statLocal(path).size > SKILL_MANIFEST_MAX * 2) throw new Error('size');
41
+ const raw: unknown = JSON.parse(readLocal(path, 'utf8'));
42
+ if (!isRecord(raw)) throw new Error('shape');
43
+ return {
44
+ source: raw.source === null ? null : githubSource(raw.source),
45
+ prepared: raw.prepared === null ? null : skillGeneration(raw.prepared),
46
+ etag: savedString(raw.etag), checkedAt: savedString(raw.checkedAt),
47
+ retryAt: savedNumber(raw.retryAt), rateLimit: savedNumber(raw.rateLimit), problem: savedString(raw.problem),
48
+ repositoryId: typeof raw.repositoryId === 'number' ? raw.repositoryId : null,
49
+ };
50
+ } catch { throw new Error('The saved GitHub skills source is unreadable. Restore it before changing the source.'); }
51
+ }
52
+
53
+ function agentJson(path: string): unknown {
54
+ try {
55
+ if (statSync(path).size > SKILL_MANIFEST_MAX) return null;
56
+ return JSON.parse(readFileSync(path, 'utf8')) as unknown;
57
+ } catch { return null; }
58
+ }
59
+
60
+ export class GitHubSkills {
61
+ private readonly path: string;
62
+ readonly root: string;
63
+ private stored: Stored = { ...EMPTY };
64
+ private unreadable = false;
65
+ private busy = false;
66
+ private epoch = 0;
67
+ private timer: ReturnType<typeof setTimeout> | null = null;
68
+
69
+ constructor(private readonly deps: GitHubSkillsDeps) {
70
+ this.path = join(deps.agents, 'github-skills.json');
71
+ this.root = skillSourceRoot(deps.claude);
72
+ try { this.stored = readStored(this.path); }
73
+ catch { this.unreadable = true; }
74
+ }
75
+
76
+ private readable(): void {
77
+ if (!this.unreadable) return;
78
+ this.stored = readStored(this.path);
79
+ this.unreadable = false;
80
+ }
81
+
82
+ private save(): void {
83
+ this.readable();
84
+ writeSecure(this.path, JSON.stringify(this.stored));
85
+ }
86
+
87
+ private activation(): { generation: string | null; appliedAt: string | null; problem: string | null; shadowed: string[] } {
88
+ const raw = agentJson(join(this.root, 'status.json'));
89
+ if (!isRecord(raw)) return { generation: null, appliedAt: null, problem: null, shadowed: [] };
90
+ return {
91
+ generation: typeof raw.generation === 'string' && SKILL_HASH.test(raw.generation) ? raw.generation : null,
92
+ appliedAt: typeof raw.appliedAt === 'string' ? raw.appliedAt : null,
93
+ problem: typeof raw.problem === 'string' ? raw.problem.slice(0, 300) : null,
94
+ shadowed: Array.isArray(raw.shadowed) ? raw.shadowed.filter((name): name is string => typeof name === 'string').slice(0, 64) : [],
95
+ };
96
+ }
97
+
98
+ private loaded(activation = this.activation()): SkillGeneration | null {
99
+ const id = activation.generation;
100
+ if (id === null) return null;
101
+ try { return skillGeneration(agentJson(join(skillRelease(this.root, id), 'manifest.json'))); }
102
+ catch { return null; }
103
+ }
104
+
105
+ view(activation = this.activation(), loaded = this.loaded(activation)): object {
106
+ const { source, prepared, checkedAt, problem } = this.stored;
107
+ return {
108
+ supported: true,
109
+ source: source === null ? null : { repository: source.repository, ref: source.ref, folder: source.folder, hasToken: true },
110
+ checking: this.busy, checkedAt, problem: this.unreadable ? 'The saved GitHub source is unreadable. Restore its configuration before changing it. Local skills are still available.' : problem,
111
+ prepared: prepared === null ? null : { generation: prepared.id, source: prepared.source, skillCount: prepared.skills.length },
112
+ loaded: loaded?.source ?? null, activation,
113
+ pending: prepared !== null && prepared.id !== activation.generation,
114
+ };
115
+ }
116
+
117
+ listing(): { rows: ClaudeSkill[]; skillSource: object } {
118
+ const activation = this.activation();
119
+ const loaded = this.loaded(activation);
120
+ return { rows: this.rows(activation, loaded), skillSource: this.view(activation, loaded) };
121
+ }
122
+
123
+ rows(activation = this.activation(), loaded = this.loaded(activation)): ClaudeSkill[] {
124
+ if (loaded === null) return [];
125
+ const origin = loaded.source;
126
+ const shadowed = activation.shadowed;
127
+ return loaded.skills.map((skill) => ({
128
+ id: `github:${skill.name}`, name: skill.name, title: skill.name, description: skill.description,
129
+ path: join(skillRelease(this.root, loaded.id), 'skills', skill.name, 'SKILL.md'), editable: false,
130
+ updatedAt: loaded.createdAt, managed: true, shadowed: shadowed.includes(skill.name),
131
+ ...(origin === null ? {} : { github: { repository: origin.repository, commit: origin.commit, folder: origin.folder } }),
132
+ }));
133
+ }
134
+
135
+ read(id: string): ClaudeSkill & { text: string } {
136
+ const row = this.rows().find((skill) => skill.id === id);
137
+ if (row === undefined) throw new ApiError('no such skill', 404);
138
+ if (statSync(row.path).size > 256 * 1024) throw new ApiError('The managed skill changed on disk. Sync it again.', 409);
139
+ return { ...row, text: readFileSync(row.path, 'utf8') };
140
+ }
141
+
142
+ async configure(raw: unknown): Promise<object> {
143
+ if (this.busy) throw new ApiError('A skills sync is already running. Try again when it finishes.', 409);
144
+ const source = githubSource(raw);
145
+ this.readable();
146
+ const loaded = this.loaded();
147
+ this.epoch += 1;
148
+ this.stored = { ...this.stored, source, prepared: loaded, etag: null, retryAt: 0, problem: null, repositoryId: null };
149
+ if (loaded === null) await this.publish(validatedGeneration(null, null), new Map(), this.epoch);
150
+ else { this.save(); this.offer(); }
151
+ await this.sync(true);
152
+ return this.view();
153
+ }
154
+
155
+ async remove(): Promise<object> {
156
+ this.readable();
157
+ this.epoch += 1;
158
+ this.stored = { ...EMPTY };
159
+ this.save();
160
+ await this.publish(validatedGeneration(null, null), new Map(), this.epoch);
161
+ return this.view();
162
+ }
163
+
164
+ private waiting(force: boolean): boolean {
165
+ if (Date.now() < this.stored.rateLimit) return true;
166
+ if (force) return false;
167
+ return Date.now() < this.stored.retryAt || (this.stored.prepared !== null && this.stored.prepared.id !== this.activation().generation);
168
+ }
169
+
170
+ private reader(source: Configuration, known: SkillGeneration['source'], force: boolean): ReturnType<GitHubReader['snapshot']> {
171
+ return new GitHubReader(source, source.token, this.deps.request).snapshot(this.stored.repositoryId, force ? null : known?.commit ?? null, force ? null : this.stored.etag);
172
+ }
173
+
174
+ private async fetch(source: Configuration, epoch: number, force: boolean): Promise<void> {
175
+ const previous = this.stored.prepared?.source;
176
+ const same = previous?.repository === source.repository && previous.ref === source.ref && previous.folder === source.folder;
177
+ const known = same ? previous : null;
178
+ const snapshot = await this.reader(source, known, force);
179
+ if (epoch !== this.epoch) return;
180
+ if (snapshot !== null) {
181
+ const generation = validatedGeneration(source, snapshot);
182
+ this.stored.etag = snapshot.etag;
183
+ this.stored.repositoryId = snapshot.repositoryId;
184
+ await this.publish(generation, snapshot.files, epoch);
185
+ if (epoch !== this.epoch) return;
186
+ }
187
+ this.stored.checkedAt = new Date().toISOString();
188
+ this.stored.problem = null;
189
+ this.stored.retryAt = Date.now() + 60_000;
190
+ }
191
+
192
+ async sync(force = false): Promise<void> {
193
+ this.readable();
194
+ this.offer();
195
+ const source = this.stored.source;
196
+ if (source === null || this.busy || this.waiting(force)) return;
197
+ const epoch = this.epoch;
198
+ this.busy = true;
199
+ try { await this.fetch(source, epoch, force); }
200
+ catch (err) {
201
+ if (epoch !== this.epoch) return;
202
+ this.failure(err);
203
+ } finally {
204
+ this.busy = false;
205
+ this.save();
206
+ }
207
+ }
208
+
209
+ private failure(err: unknown): void {
210
+ this.stored.problem = err instanceof GitHubFailure ? err.message : 'The repository failed skill validation or staging. Keep one folder per skill, safe metadata and regular files. The loaded skills are kept.';
211
+ this.stored.retryAt = err instanceof GitHubFailure ? err.retryAt : Date.now() + 5 * 60_000;
212
+ if (err instanceof GitHubFailure && err.rateLimited) this.stored.rateLimit = err.retryAt;
213
+ this.stored.checkedAt = new Date().toISOString();
214
+ }
215
+
216
+ private offer(): void {
217
+ const generation = this.stored.prepared;
218
+ if (generation === null) return;
219
+ const pending = agentJson(join(this.root, 'pending.json'));
220
+ if (isRecord(pending) && pending.id === generation.id) return;
221
+ writeHomeText(join(this.root, 'pending.json'), JSON.stringify(generation), 0o600);
222
+ }
223
+
224
+ private async publish(generation: SkillGeneration, files: Map<string, Buffer>, epoch: number): Promise<void> {
225
+ const release = skillRelease(this.root, generation.id);
226
+ const deadline = Date.now() + 120_000;
227
+ for (const [path, bytes] of files) {
228
+ if (epoch !== this.epoch) return;
229
+ if (Date.now() > deadline) throw new Error('Staging skills timed out.');
230
+ const mode = generation.files.find((file) => file.path === path)?.executable === true ? 0o700 : 0o600;
231
+ await receiveHomeFile(join(release, 'skills', path), Readable.from(bytes), mode);
232
+ }
233
+ if (epoch !== this.epoch) return;
234
+ writeHomeText(join(release, 'manifest.json'), JSON.stringify(generation), 0o600);
235
+ this.stored.prepared = generation;
236
+ this.save();
237
+ this.offer();
238
+ }
239
+
240
+ watch(): void {
241
+ if (this.timer !== null) return;
242
+ const tick = (): void => {
243
+ this.sync().catch(() => { log.warn('github-skills: could not save sync state'); });
244
+ this.timer = setTimeout(tick, 60_000 + Math.floor(Math.random() * 5_000));
245
+ this.timer.unref();
246
+ };
247
+ tick();
248
+ }
249
+ }
250
+
251
+ let current: GitHubSkills | null = null;
252
+ export function githubSkills(): GitHubSkills {
253
+ current ??= new GitHubSkills({ agents: agentsDir(), claude: claudeDir() });
254
+ return current;
255
+ }
@@ -0,0 +1,53 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+ import { isRecord } from '@metro-labs/core/is-record';
3
+ import { SKILL_NAME, skillGeneration, type SkillGeneration, type SkillSource } from '@metro-labs/core/skill-source';
4
+ import { ApiError } from '@metro-labs/http/api-error';
5
+ import type { GitHubSnapshot } from './github-fetch.js';
6
+
7
+ const FIELDS = new Set(['name', 'description', 'argument-hint', 'disable-model-invocation', 'user-invocable']);
8
+ export const skillDigest = (bytes: string | Uint8Array): string => createHash('sha256').update(bytes).digest('hex');
9
+
10
+ function validRef(value: unknown): value is string {
11
+ return typeof value === 'string' && value.length <= 200 && /^[A-Za-z0-9][A-Za-z0-9._/-]*$/.test(value) && !value.includes('..') && !value.includes('//');
12
+ }
13
+
14
+ function validFolder(value: unknown): value is string {
15
+ if (typeof value !== 'string' || value.length > 240) return false;
16
+ if (value === '') return true;
17
+ const parts = value.split('/');
18
+ return parts.length <= 6 && parts.every((part) => /^[A-Za-z0-9._-]{1,80}$/.test(part) && part !== '.' && part !== '..');
19
+ }
20
+
21
+ export function githubSource(raw: unknown): SkillSource & { token: string } {
22
+ if (!isRecord(raw) || typeof raw.repository !== 'string' || !/^[A-Za-z0-9][A-Za-z0-9-]{0,38}\/[A-Za-z0-9][A-Za-z0-9._-]{0,99}$/.test(raw.repository)) throw new ApiError('Use a GitHub repository in owner/repository form.', 400);
23
+ if (!validRef(raw.ref)) throw new ApiError('Use a branch, tag or full commit SHA.', 400);
24
+ if (!validFolder(raw.folder)) throw new ApiError('Use a relative skills folder, or leave it empty for the repository root.', 400);
25
+ if (typeof raw.token !== 'string' || !/^github_pat_[A-Za-z0-9_]{20,240}$/.test(raw.token)) throw new ApiError('Use a fine-grained GitHub token with Contents read access to this repository only.', 400);
26
+ return { repository: raw.repository, ref: raw.ref, folder: raw.folder, token: raw.token };
27
+ }
28
+
29
+ function passiveMetadata(meta: Record<string, unknown>): void {
30
+ if (Object.keys(meta).some((key) => !FIELDS.has(key))) throw new Error('Unsupported skill metadata. Only name, description, argument-hint, disable-model-invocation and user-invocable are allowed. Hooks, tool grants, model changes and agents are not imported.');
31
+ if (['disable-model-invocation', 'user-invocable'].some((key) => key in meta && typeof meta[key] !== 'boolean') || ('argument-hint' in meta && typeof meta['argument-hint'] !== 'string')) throw new Error('Invalid skill metadata types.');
32
+ }
33
+
34
+ function skillMetadata(name: string, bytes: Buffer): { name: string; description: string } {
35
+ const text = new TextDecoder('utf-8', { fatal: true }).decode(bytes);
36
+ const match = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(text);
37
+ if (match === null || /!`|\0/.test(text)) throw new Error('A skill needs YAML frontmatter. Shell substitutions are not supported.');
38
+ const meta: unknown = Bun.YAML.parse(match[1] ?? '');
39
+ if (!isRecord(meta) || meta.name !== name || !SKILL_NAME.test(name) || typeof meta.description !== 'string' || meta.description.trim() === '' || meta.description.length > 1024) throw new Error('A skill needs a name matching its folder and a description of up to 1024 characters.');
40
+ passiveMetadata(meta);
41
+ return { name, description: meta.description };
42
+ }
43
+
44
+ export function validatedGeneration(source: SkillSource | null, snapshot: GitHubSnapshot | null): SkillGeneration {
45
+ const files = snapshot?.files ?? new Map<string, Buffer>();
46
+ const skills = [...files].filter(([path]) => path.endsWith('/SKILL.md')).map(([path, bytes]) => skillMetadata(path.split('/')[0] ?? '', bytes));
47
+ const manifest = {
48
+ source: source === null || snapshot === null ? null : { repository: source.repository, ref: source.ref, folder: source.folder, repositoryId: snapshot.repositoryId, commit: snapshot.commit },
49
+ skills,
50
+ files: [...files].map(([path, bytes]) => ({ path, size: bytes.byteLength, sha256: skillDigest(bytes), ...(snapshot?.executables?.includes(path) === true ? { executable: true } : {}) })),
51
+ };
52
+ return skillGeneration({ ...manifest, id: skillDigest(randomUUID()), createdAt: new Date().toISOString() });
53
+ }
@@ -0,0 +1,60 @@
1
+ import { join } from 'node:path';
2
+ import { isRecord } from '@metro-labs/core/is-record';
3
+ import { GUARD_HOOK, SESSION_START_HOOK } from './cli-files.js';
4
+
5
+ interface HookCommand {
6
+ type: 'command';
7
+ command: string;
8
+ statusMessage?: string;
9
+ }
10
+
11
+ const METRO_COMMAND = /^node "[^"]*\/hooks\/(guard|session-start)\.mjs"$/;
12
+ const METRO_GUARD = /^node "[^"]*\/hooks\/guard\.mjs"$/;
13
+
14
+ const commandOf = (hook: unknown): string => (isRecord(hook) && typeof hook.command === 'string' ? hook.command : '');
15
+ const metroHook = (hook: unknown): boolean => METRO_COMMAND.test(commandOf(hook));
16
+ const run = (dir: string, file: string): string => `node "${join(dir, file)}"`;
17
+
18
+ function metroHooks(dir: string): Record<string, HookCommand> {
19
+ return {
20
+ PreToolUse: { type: 'command', command: run(dir, GUARD_HOOK), statusMessage: 'Checking the orchestrator boundary' },
21
+ SessionStart: { type: 'command', command: run(dir, SESSION_START_HOOK) },
22
+ };
23
+ }
24
+
25
+ function withHook(groups: unknown[], wanted: HookCommand): unknown[] {
26
+ let placed = false;
27
+ const out: unknown[] = [];
28
+ for (const group of groups) {
29
+ if (!isRecord(group) || !Array.isArray(group.hooks) || !group.hooks.some(metroHook)) {
30
+ out.push(group);
31
+ continue;
32
+ }
33
+ const kept = group.hooks.flatMap((hook: unknown) => {
34
+ if (!metroHook(hook)) return [hook];
35
+ if (placed) return [];
36
+ placed = true;
37
+ return [wanted];
38
+ });
39
+ if (kept.length > 0) out.push({ ...group, hooks: kept });
40
+ }
41
+ return placed ? out : [...out, { hooks: [wanted] }];
42
+ }
43
+
44
+ export function withMetroHooks(settings: Record<string, unknown>, dir: string): Record<string, unknown> | null {
45
+ const hooks = settings.hooks ?? {};
46
+ if (!isRecord(hooks)) return null;
47
+ const next: Record<string, unknown> = { ...hooks };
48
+ for (const [event, wanted] of Object.entries(metroHooks(dir))) {
49
+ const groups = hooks[event] ?? [];
50
+ if (!Array.isArray(groups)) return null;
51
+ next[event] = withHook(groups, wanted);
52
+ }
53
+ return { ...settings, hooks: next };
54
+ }
55
+
56
+ export function hasMetroGuard(settings: Record<string, unknown> | null): boolean {
57
+ const groups = settings !== null && isRecord(settings.hooks) ? settings.hooks.PreToolUse : undefined;
58
+ if (!Array.isArray(groups)) return false;
59
+ return groups.some((group) => isRecord(group) && Array.isArray(group.hooks) && group.hooks.some((hook) => METRO_GUARD.test(commandOf(hook))));
60
+ }
@@ -0,0 +1,123 @@
1
+ import { join } from 'node:path';
2
+ import { errMsg, log } from '@metro-labs/core/log';
3
+ import { existsSync, readFileSync } from '../agent-user/agent-fs.js';
4
+ import { readCrontab, withBlock, writeCrontab } from '../agent-user/crontab.js';
5
+ import { writeHomeText } from '../agent-user/home-fs.js';
6
+ import { listSchedules, parseCronLine, realRunner, type Runner } from '../agent-user/schedules.js';
7
+ import { agentPath, agentUser, type AgentUser } from '../agent-user/user.js';
8
+
9
+ const BEGIN = '# metro memory routine: begin';
10
+ const END = '# metro memory routine: end';
11
+ const REPLACED = '# replaced by memory-routine: ';
12
+ const OWN_JOB = /memory/i;
13
+ const SCHEDULE = '0 0,12 * * *';
14
+
15
+ export type MemoryJobState = 'scheduled' | 'own' | 'off' | 'unavailable';
16
+
17
+ export interface MemoryJob {
18
+ state: MemoryJobState;
19
+ job: string | null;
20
+ }
21
+
22
+ export interface MemoryJobDeps {
23
+ user?: AgentUser | null;
24
+ runner?: Runner;
25
+ cli?: string;
26
+ port?: string;
27
+ }
28
+
29
+ let last: MemoryJob = { state: 'unavailable', job: null };
30
+
31
+ export const memoryJobStatus = (): MemoryJob => ({ ...last });
32
+
33
+ export const launcherPath = (user: AgentUser): string => join(user.home, '.metro', 'bin', 'memory-routine');
34
+ export const skillPath = (user: AgentUser): string => join(user.home, '.claude', 'skills', 'memory', 'SKILL.md');
35
+ const logPath = (user: AgentUser): string => join(user.home, '.metro', 'memory-routine.log');
36
+ const quoted = (text: string): string => `'${text.replace(/'/g, '\'\\\'\'')}'`;
37
+
38
+ export function launcherText(user: AgentUser, cli: string, port: string): string {
39
+ return [
40
+ '#!/bin/sh',
41
+ `PATH=${quoted(agentPath(user))}`,
42
+ 'export PATH',
43
+ ...(port === '' ? [] : [`METRO_WEBHOOK_PORT=${quoted(port)}`, 'export METRO_WEBHOOK_PORT']),
44
+ 'cd "$HOME" || exit 1',
45
+ `exec node ${quoted(cli)} memory "$@"`,
46
+ '',
47
+ ].join('\n');
48
+ }
49
+
50
+ export const cronLine = (user: AgentUser): string => `${SCHEDULE} ${launcherPath(user)} ${skillPath(user)} >> ${logPath(user)} 2>&1`;
51
+
52
+ const commandName = (command: string): string => command.split(/\s+/)[0]?.split('/').pop() ?? 'cron';
53
+
54
+ const ownCommand = (user: AgentUser, line: string): string | null => {
55
+ const parsed = parseCronLine(line);
56
+ return parsed === null || parsed.command.includes(launcherPath(user)) || !OWN_JOB.test(parsed.command) ? null : parsed.command;
57
+ };
58
+
59
+ const replaces = (user: AgentUser, line: string): boolean => OWN_JOB.test(commandName(ownCommand(user, line) ?? ''));
60
+
61
+ function ownJob(user: AgentUser, runner: Runner, lines: string[]): string | null {
62
+ const cron = lines.flatMap((line) => {
63
+ const command = ownCommand(user, line);
64
+ return command === null || replaces(user, line) ? [] : [commandName(command)];
65
+ });
66
+ const timers = listSchedules(null, runner).filter((job) => job.runsAs === user.name && OWN_JOB.test(`${job.name} ${job.command}`));
67
+ return cron[0] ?? timers[0]?.name ?? null;
68
+ }
69
+
70
+ const restored = (line: string): string => (line.startsWith(REPLACED) ? line.slice(REPLACED.length) : line);
71
+
72
+ function marked(user: AgentUser, lines: string[], on: boolean, scheduled: boolean): string[] {
73
+ if (!on) return lines.map(restored);
74
+ return lines.map((l) => (scheduled && replaces(user, l) ? `${REPLACED}${l}` : l));
75
+ }
76
+
77
+ function placeLauncher(path: string, text: string): void {
78
+ if (existsSync(path) && readFileSync(path, 'utf8') === text) return;
79
+ writeHomeText(path, text, 0o755);
80
+ }
81
+
82
+ const envText = (name: string): string => process.env[name]?.trim() ?? '';
83
+
84
+ function resolved(deps: MemoryJobDeps): Required<MemoryJobDeps> {
85
+ return {
86
+ user: deps.user === undefined ? agentUser() : deps.user,
87
+ runner: deps.runner ?? realRunner,
88
+ cli: deps.cli ?? envText('METRO_CLI_BIN'),
89
+ port: deps.port ?? envText('METRO_WEBHOOK_PORT'),
90
+ };
91
+ }
92
+
93
+ const stateOf = (scheduled: boolean, own: string | null): MemoryJobState => {
94
+ if (scheduled) return 'scheduled';
95
+ return own === null ? 'off' : 'own';
96
+ };
97
+
98
+ export function ensureMemoryJob(on: boolean, deps: MemoryJobDeps = {}): MemoryJob {
99
+ const { user, runner, cli, port } = resolved(deps);
100
+ if (user === null || cli === '') {
101
+ last = { state: 'unavailable', job: null };
102
+ return memoryJobStatus();
103
+ }
104
+ const lines = readCrontab(user, runner);
105
+ const own = on ? ownJob(user, runner, lines) : null;
106
+ const scheduled = on && own === null;
107
+ const launcher = launcherPath(user);
108
+ if (scheduled) placeLauncher(launcher, launcherText(user, cli, port));
109
+ const kept = marked(user, lines, on, scheduled);
110
+ const next = withBlock(kept, BEGIN, END, scheduled ? [cronLine(user)] : [], (l) => l.includes(launcher));
111
+ const changed = writeCrontab(user, runner, lines, next);
112
+ last = { state: stateOf(scheduled, own), job: own };
113
+ if (changed) log.info({ ...last, rewritten: kept.filter((l, i) => l !== lines[i]) }, 'memory-routine: updated the memory job');
114
+ return memoryJobStatus();
115
+ }
116
+
117
+ export function tryMemoryJob(on: boolean): void {
118
+ try {
119
+ ensureMemoryJob(on);
120
+ } catch (err) {
121
+ log.warn({ err: errMsg(err) }, 'memory-routine: could not set up the daily memory job');
122
+ }
123
+ }