@stage-labs/metro 0.1.0-beta.23 → 0.1.0-beta.231

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 (457) hide show
  1. package/dist/api.js +9 -101
  2. package/dist/background.js +123 -0
  3. package/dist/claude-settings.js +40 -0
  4. package/dist/claude.js +197 -0
  5. package/dist/cli.js +52 -110
  6. package/dist/control.js +19 -103
  7. package/dist/hold.js +210 -0
  8. package/dist/local.js +43 -0
  9. package/dist/mcp-config.js +25 -0
  10. package/dist/memory.js +222 -0
  11. package/dist/node-name.js +71 -0
  12. package/dist/onboarding.js +44 -0
  13. package/dist/provider-flags.js +9 -0
  14. package/dist/route.js +58 -0
  15. package/dist/runtime-install.js +96 -0
  16. package/dist/runtime.js +29 -52
  17. package/dist/serve.js +157 -0
  18. package/dist/service.js +304 -0
  19. package/dist/tail.js +119 -0
  20. package/dist/update.js +13 -1
  21. package/package.json +2 -23
  22. package/runtime/marketplace/.claude-plugin/marketplace.json +12 -0
  23. package/runtime/marketplace/plugin/.claude-plugin/plugin.json +17 -0
  24. package/runtime/marketplace/plugin/.mcp.json +1 -0
  25. package/runtime/marketplace/plugin/MEMORY.md +78 -0
  26. package/runtime/marketplace/plugin/METRO.md +26 -0
  27. package/runtime/marketplace/plugin/STAGE.md +42 -0
  28. package/runtime/marketplace/plugin/bin/guard.mjs +71 -0
  29. package/runtime/marketplace/plugin/bin/metro-plugin.mjs +30 -0
  30. package/runtime/marketplace/plugin/bin/policy.mjs +97 -0
  31. package/runtime/marketplace/plugin/bin/session-start.mjs +31 -0
  32. package/runtime/marketplace/plugin/hooks/hooks.json +25 -0
  33. package/runtime/node_modules/@metro-labs/core/package.json +51 -0
  34. package/runtime/node_modules/@metro-labs/core/src/endpoints.ts +7 -0
  35. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/events.ts +11 -7
  36. package/runtime/node_modules/@metro-labs/{mcp/src/db → core/src}/ids.ts +5 -0
  37. package/runtime/node_modules/@metro-labs/core/src/is-record.ts +2 -0
  38. package/runtime/node_modules/@metro-labs/{mcp/src/stations → core/src}/lines.ts +22 -26
  39. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/protocol.ts +7 -4
  40. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/secure-fs.ts +17 -0
  41. package/runtime/node_modules/@metro-labs/core/src/station-names.ts +14 -0
  42. package/runtime/node_modules/@metro-labs/core/src/stations/account-files.ts +41 -0
  43. package/runtime/node_modules/@metro-labs/core/src/stations/account-store.ts +83 -0
  44. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/attachments.ts +0 -1
  45. package/runtime/node_modules/@metro-labs/core/src/stations/mail-text.ts +72 -0
  46. package/runtime/node_modules/@metro-labs/core/src/stations/mail-trust.ts +29 -0
  47. package/runtime/node_modules/@metro-labs/core/src/stations/mail.ts +212 -0
  48. package/runtime/node_modules/@metro-labs/core/src/stations/messaging-normalize.ts +16 -0
  49. package/runtime/node_modules/@metro-labs/core/src/stations/oauth.ts +126 -0
  50. package/runtime/node_modules/@metro-labs/core/src/stations/profile.ts +58 -0
  51. package/runtime/node_modules/@metro-labs/core/src/stations/sender-profile.ts +64 -0
  52. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/station-runtime.ts +6 -11
  53. package/runtime/node_modules/@metro-labs/core/src/stations/train-boot.ts +42 -0
  54. package/runtime/node_modules/@metro-labs/core/src/stations/train-events.ts +84 -0
  55. package/runtime/node_modules/@metro-labs/{mcp → core}/src/stations/types.ts +18 -1
  56. package/runtime/node_modules/@metro-labs/core/src/tickets.ts +37 -0
  57. package/runtime/node_modules/@metro-labs/core/src/version.ts +2 -0
  58. package/runtime/node_modules/@metro-labs/daemon/package.json +49 -0
  59. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/agent-fs.ts +134 -0
  60. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/crontab.ts +44 -0
  61. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files-api.ts +12 -0
  62. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/files.ts +89 -0
  63. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/home-fs.ts +113 -0
  64. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/job-env.ts +39 -0
  65. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/provision.ts +80 -0
  66. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedule-detail.ts +99 -0
  67. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules-api.ts +27 -0
  68. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/schedules.ts +144 -0
  69. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/unit-files.ts +43 -0
  70. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/user.ts +91 -0
  71. package/runtime/node_modules/@metro-labs/daemon/src/agent-user/view.ts +87 -0
  72. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-attach.ts +19 -0
  73. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-lookups.ts +55 -0
  74. package/runtime/node_modules/@metro-labs/daemon/src/agents/account-routes.ts +76 -0
  75. package/runtime/node_modules/@metro-labs/daemon/src/agents/accounts-api.ts +357 -0
  76. package/runtime/node_modules/@metro-labs/daemon/src/agents/admin.ts +30 -0
  77. package/runtime/node_modules/@metro-labs/daemon/src/agents/allowlist.ts +59 -0
  78. package/runtime/node_modules/@metro-labs/daemon/src/agents/api.ts +131 -0
  79. package/runtime/node_modules/@metro-labs/daemon/src/agents/bundle.ts +132 -0
  80. package/runtime/node_modules/@metro-labs/daemon/src/agents/file-admin.ts +305 -0
  81. package/runtime/node_modules/@metro-labs/daemon/src/agents/files.ts +142 -0
  82. package/runtime/node_modules/@metro-labs/{mcp/src/db/key-map.ts → daemon/src/agents/keys.ts} +1 -11
  83. package/runtime/node_modules/@metro-labs/daemon/src/agents/map.ts +133 -0
  84. package/runtime/node_modules/@metro-labs/daemon/src/agents/policy-route.ts +27 -0
  85. package/runtime/node_modules/@metro-labs/{mcp/src/db/agent-scope.ts → daemon/src/agents/scope.ts} +2 -2
  86. package/runtime/node_modules/@metro-labs/daemon/src/agents/sender-cards.ts +94 -0
  87. package/runtime/node_modules/@metro-labs/daemon/src/agents/senders.ts +38 -0
  88. package/runtime/node_modules/@metro-labs/daemon/src/approvals/api.ts +55 -0
  89. package/runtime/node_modules/@metro-labs/daemon/src/approvals/pending.ts +150 -0
  90. package/runtime/node_modules/@metro-labs/daemon/src/approvals/preview.ts +66 -0
  91. package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +223 -0
  92. package/runtime/node_modules/@metro-labs/daemon/src/boot/connect-hint.ts +36 -0
  93. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/crash-guard.ts +1 -1
  94. package/runtime/node_modules/@metro-labs/daemon/src/boot/local-owner.ts +21 -0
  95. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/boot}/paths.ts +6 -34
  96. package/runtime/node_modules/@metro-labs/daemon/src/channels/addressed.ts +26 -0
  97. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/inbound.ts +75 -45
  98. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/media-note.ts +11 -7
  99. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/pending.ts +4 -1
  100. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/relay.ts +2 -2
  101. package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +380 -0
  102. package/runtime/node_modules/@metro-labs/daemon/src/claude/files.ts +359 -0
  103. package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +208 -0
  104. package/runtime/node_modules/@metro-labs/daemon/src/claude/memory-routine.ts +114 -0
  105. package/runtime/node_modules/@metro-labs/daemon/src/claude/memory.ts +32 -0
  106. package/runtime/node_modules/@metro-labs/daemon/src/claude/onboarding.ts +60 -0
  107. package/runtime/node_modules/@metro-labs/daemon/src/claude/plugin-install.ts +149 -0
  108. package/runtime/node_modules/@metro-labs/daemon/src/claude/session-files.ts +75 -0
  109. package/runtime/node_modules/@metro-labs/daemon/src/claude/session.ts +295 -0
  110. package/runtime/node_modules/@metro-labs/daemon/src/claude/settings.ts +109 -0
  111. package/runtime/node_modules/@metro-labs/daemon/src/claude/setup.ts +346 -0
  112. package/runtime/node_modules/@metro-labs/daemon/src/claude/skills.ts +120 -0
  113. package/runtime/node_modules/@metro-labs/daemon/src/claude/usage-probe.ts +127 -0
  114. package/runtime/node_modules/@metro-labs/daemon/src/claude/version.ts +113 -0
  115. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-api.ts → daemon/src/connectors/api.ts} +79 -113
  116. package/runtime/node_modules/@metro-labs/{mcp/src/db/connector-config.ts → daemon/src/connectors/config.ts} +67 -41
  117. package/runtime/node_modules/@metro-labs/daemon/src/connectors/gates.ts +72 -0
  118. package/runtime/node_modules/@metro-labs/daemon/src/connectors/health.ts +18 -0
  119. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-client.ts +14 -17
  120. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/connectors}/oauth-discovery.ts +33 -20
  121. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth-routes.ts → daemon/src/connectors/oauth-routes.ts} +30 -32
  122. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/connector-oauth.ts → daemon/src/connectors/oauth.ts} +61 -22
  123. package/runtime/node_modules/@metro-labs/daemon/src/connectors/plugin-sync.ts +131 -0
  124. package/runtime/node_modules/@metro-labs/daemon/src/connectors/reach.ts +27 -0
  125. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay-policy.ts +90 -0
  126. package/runtime/node_modules/@metro-labs/daemon/src/connectors/relay.ts +347 -0
  127. package/runtime/node_modules/@metro-labs/daemon/src/connectors/store.ts +385 -0
  128. package/runtime/node_modules/@metro-labs/daemon/src/connectors/tools.ts +81 -0
  129. package/runtime/node_modules/@metro-labs/daemon/src/connectors/transfer-api.ts +116 -0
  130. package/runtime/node_modules/@metro-labs/daemon/src/connectors/transfer-crypto.ts +44 -0
  131. package/runtime/node_modules/@metro-labs/daemon/src/connectors/transfer-store.ts +48 -0
  132. package/runtime/node_modules/@metro-labs/daemon/src/connectors/url.ts +37 -0
  133. package/runtime/node_modules/@metro-labs/daemon/src/connectors/verify.ts +106 -0
  134. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-grant.ts +4 -4
  135. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-owner.ts +3 -3
  136. package/runtime/node_modules/@metro-labs/daemon/src/files/attach-reaper.ts +174 -0
  137. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/attach-serve.ts +12 -13
  138. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-api.ts +10 -27
  139. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/files}/upload-store.ts +4 -4
  140. package/runtime/node_modules/@metro-labs/daemon/src/gateway/bedrock.ts +233 -0
  141. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-auth.ts +214 -0
  142. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-device.ts +91 -0
  143. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-stream.ts +173 -0
  144. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-translate.ts +209 -0
  145. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex-version.ts +44 -0
  146. package/runtime/node_modules/@metro-labs/daemon/src/gateway/codex.ts +155 -0
  147. package/runtime/node_modules/@metro-labs/daemon/src/gateway/effort.ts +93 -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/forward.ts +237 -0
  150. package/runtime/node_modules/@metro-labs/daemon/src/gateway/frames.ts +118 -0
  151. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +307 -0
  152. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-auth.ts +160 -0
  153. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-client.ts +46 -0
  154. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-setup.ts +150 -0
  155. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-stream.ts +139 -0
  156. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini-translate.ts +235 -0
  157. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gemini.ts +208 -0
  158. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +203 -0
  159. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +285 -0
  160. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-lists.ts +57 -0
  161. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-signin.ts +161 -0
  162. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-store.ts +72 -0
  163. package/runtime/node_modules/@metro-labs/daemon/src/gateway/openrouter.ts +104 -0
  164. package/runtime/node_modules/@metro-labs/daemon/src/gateway/pkce.ts +36 -0
  165. package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +118 -0
  166. package/runtime/node_modules/@metro-labs/daemon/src/gateway/served.ts +18 -0
  167. package/runtime/node_modules/@metro-labs/daemon/src/gateway/subscription.ts +120 -0
  168. package/runtime/node_modules/@metro-labs/daemon/src/gateway/text.ts +35 -0
  169. package/runtime/node_modules/@metro-labs/daemon/src/gateway/tool-search.ts +126 -0
  170. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage-refresh.ts +102 -0
  171. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +348 -0
  172. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/accounts.ts +28 -17
  173. package/runtime/node_modules/@metro-labs/daemon/src/mcp/attachment-schema.ts +91 -0
  174. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/call-tools.ts +49 -20
  175. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/ctx.ts +4 -4
  176. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/event-store.ts +15 -16
  177. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/group-tools.ts +2 -2
  178. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/index.ts +34 -80
  179. package/runtime/node_modules/@metro-labs/daemon/src/mcp/instructions.ts +19 -0
  180. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/member-tools.ts +2 -2
  181. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-prompt.ts +87 -0
  182. package/runtime/node_modules/@metro-labs/daemon/src/mcp/permission-relay.ts +88 -0
  183. package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-gate.ts +82 -0
  184. package/runtime/node_modules/@metro-labs/daemon/src/mcp/policy-snapshot.ts +79 -0
  185. package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-lookup.ts +60 -0
  186. package/runtime/node_modules/@metro-labs/daemon/src/mcp/profile-tool.ts +96 -0
  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 +46 -0
  189. package/runtime/node_modules/@metro-labs/daemon/src/mcp/session-slot.ts +71 -0
  190. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/session.ts +47 -44
  191. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-catalog.ts +93 -0
  192. package/runtime/node_modules/@metro-labs/daemon/src/mcp/tool-def.ts +9 -0
  193. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-dispatch.ts +53 -40
  194. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/tool-schemas.ts +64 -113
  195. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/upload-tool.ts +6 -11
  196. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/helper-script.ts +126 -0
  197. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/install.ts +37 -0
  198. package/runtime/node_modules/@metro-labs/daemon/src/metro-user/privilege.ts +48 -0
  199. package/runtime/node_modules/@metro-labs/daemon/src/monitor/api.ts +132 -0
  200. package/runtime/node_modules/@metro-labs/daemon/src/net/tunnel.ts +316 -0
  201. package/runtime/node_modules/@metro-labs/daemon/src/policy/policy.ts +118 -0
  202. package/runtime/node_modules/@metro-labs/daemon/src/routes/bearer.ts +35 -0
  203. package/runtime/node_modules/@metro-labs/daemon/src/routes/body.ts +24 -0
  204. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/routes}/http.ts +63 -51
  205. package/runtime/node_modules/@metro-labs/daemon/src/routes/local-mode.ts +209 -0
  206. package/runtime/node_modules/@metro-labs/daemon/src/routes/session-apis.ts +69 -0
  207. package/runtime/node_modules/@metro-labs/daemon/src/routes/session.ts +29 -0
  208. package/runtime/node_modules/@metro-labs/daemon/src/routes/threema-callback.ts +103 -0
  209. package/runtime/node_modules/@metro-labs/daemon/src/server/cloudwatch.ts +178 -0
  210. package/runtime/node_modules/@metro-labs/daemon/src/server/control.ts +39 -0
  211. package/runtime/node_modules/@metro-labs/daemon/src/server/machine.ts +58 -0
  212. package/runtime/node_modules/@metro-labs/daemon/src/server/owner.ts +26 -0
  213. package/runtime/node_modules/@metro-labs/daemon/src/server/update.ts +90 -0
  214. package/runtime/node_modules/@metro-labs/daemon/src/server.ts +2 -0
  215. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-browser.ts +102 -0
  216. package/runtime/node_modules/@metro-labs/daemon/src/stations/attach-driver.ts +42 -0
  217. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-inline.ts +29 -1
  218. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-interactive.ts +5 -31
  219. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-resolve.ts +38 -13
  220. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/attach-session.ts +32 -22
  221. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach-xmtp.ts +8 -9
  222. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/attach.ts +69 -3
  223. package/runtime/node_modules/@metro-labs/{mcp/src/db → daemon/src/stations}/materialize.ts +60 -179
  224. package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/stations/registry.ts +20 -2
  225. package/runtime/node_modules/@metro-labs/daemon/src/stations/runtime-deps.ts +82 -0
  226. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor-io.ts +3 -3
  227. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/supervisor.ts +6 -9
  228. package/runtime/node_modules/@metro-labs/daemon/src/stations/threema-callbacks.ts +32 -0
  229. package/runtime/node_modules/@metro-labs/{mcp/src/daemon → daemon/src/stations}/train-call.ts +1 -1
  230. package/runtime/node_modules/@metro-labs/daemon/src/stations/webhook-endpoints.ts +51 -0
  231. package/runtime/node_modules/@metro-labs/daemon/src/terminal/api.ts +84 -0
  232. package/runtime/node_modules/@metro-labs/daemon/src/terminal/socket.ts +124 -0
  233. package/runtime/node_modules/@metro-labs/daemon/src/terminal/tickets.ts +15 -0
  234. package/runtime/node_modules/@metro-labs/daemon/src/vault/api.ts +45 -0
  235. package/runtime/node_modules/@metro-labs/daemon/src/vault/config.ts +51 -0
  236. package/runtime/node_modules/@metro-labs/daemon/src/vault/firewall.ts +9 -0
  237. package/runtime/node_modules/@metro-labs/daemon/src/vault/index.ts +96 -0
  238. package/runtime/node_modules/@metro-labs/daemon/src/vault/install.ts +56 -0
  239. package/runtime/node_modules/@metro-labs/daemon/src/vault/paths.ts +26 -0
  240. package/runtime/node_modules/@metro-labs/daemon/src/vault/proxy.ts +147 -0
  241. package/runtime/node_modules/@metro-labs/daemon/src/vault/store.ts +129 -0
  242. package/runtime/node_modules/@metro-labs/daemon/src/vault/trust.ts +44 -0
  243. package/runtime/node_modules/@metro-labs/discord-bot/package.json +2 -4
  244. package/runtime/node_modules/@metro-labs/discord-bot/src/accounts.ts +3 -23
  245. package/runtime/node_modules/@metro-labs/discord-bot/src/actions.ts +19 -187
  246. package/runtime/node_modules/@metro-labs/discord-bot/src/attachments.ts +2 -2
  247. package/runtime/node_modules/@metro-labs/discord-bot/src/format.ts +26 -67
  248. package/runtime/node_modules/@metro-labs/discord-bot/src/group-actions.ts +1 -1
  249. package/runtime/node_modules/@metro-labs/discord-bot/src/group.ts +2 -2
  250. package/runtime/node_modules/@metro-labs/discord-bot/src/index.ts +8 -14
  251. package/runtime/node_modules/@metro-labs/discord-bot/src/members.ts +2 -2
  252. package/runtime/node_modules/@metro-labs/discord-bot/src/profile.ts +68 -0
  253. package/runtime/node_modules/@metro-labs/discord-bot/src/send-files.ts +12 -13
  254. package/runtime/node_modules/@metro-labs/discord-bot/src/station.ts +5 -1
  255. package/runtime/node_modules/@metro-labs/gmail/package.json +25 -0
  256. package/runtime/node_modules/@metro-labs/gmail/src/accounts.ts +81 -0
  257. package/runtime/node_modules/@metro-labs/gmail/src/actions.ts +14 -0
  258. package/runtime/node_modules/@metro-labs/gmail/src/api.ts +31 -0
  259. package/runtime/node_modules/@metro-labs/gmail/src/attachments.ts +35 -0
  260. package/runtime/node_modules/@metro-labs/gmail/src/auth.ts +105 -0
  261. package/runtime/node_modules/@metro-labs/gmail/src/config.ts +13 -0
  262. package/runtime/node_modules/@metro-labs/gmail/src/inbound.ts +96 -0
  263. package/runtime/node_modules/@metro-labs/gmail/src/index.ts +12 -0
  264. package/runtime/node_modules/@metro-labs/gmail/src/login.ts +37 -0
  265. package/runtime/node_modules/@metro-labs/gmail/src/message.ts +125 -0
  266. package/runtime/node_modules/@metro-labs/gmail/src/mime.ts +70 -0
  267. package/runtime/node_modules/@metro-labs/gmail/src/outbound.ts +124 -0
  268. package/runtime/node_modules/@metro-labs/gmail/src/query.ts +99 -0
  269. package/runtime/node_modules/@metro-labs/gmail/src/state.ts +24 -0
  270. package/runtime/node_modules/@metro-labs/gmail/src/station.ts +15 -0
  271. package/runtime/node_modules/@metro-labs/gmail/src/trust.ts +42 -0
  272. package/runtime/node_modules/@metro-labs/http/package.json +30 -0
  273. package/runtime/node_modules/@metro-labs/http/src/api-http.ts +135 -0
  274. package/runtime/node_modules/@metro-labs/{mcp/src/daemon/session-api.ts → http/src/mode-api.ts} +13 -9
  275. package/runtime/node_modules/@metro-labs/http/src/return-to.ts +21 -0
  276. package/runtime/node_modules/@metro-labs/http/src/sigv4.ts +90 -0
  277. package/runtime/node_modules/@metro-labs/http/src/workos-token.ts +149 -0
  278. package/runtime/node_modules/@metro-labs/outlook/package.json +25 -0
  279. package/runtime/node_modules/@metro-labs/outlook/src/accounts.ts +78 -0
  280. package/runtime/node_modules/@metro-labs/outlook/src/actions.ts +14 -0
  281. package/runtime/node_modules/@metro-labs/outlook/src/attachments.ts +81 -0
  282. package/runtime/node_modules/@metro-labs/outlook/src/auth.ts +120 -0
  283. package/runtime/node_modules/@metro-labs/outlook/src/browser.ts +42 -0
  284. package/runtime/node_modules/@metro-labs/outlook/src/config.ts +23 -0
  285. package/runtime/node_modules/@metro-labs/outlook/src/format.ts +59 -0
  286. package/runtime/node_modules/@metro-labs/outlook/src/graph.ts +55 -0
  287. package/runtime/node_modules/@metro-labs/outlook/src/inbound.ts +96 -0
  288. package/runtime/node_modules/@metro-labs/outlook/src/index.ts +12 -0
  289. package/runtime/node_modules/@metro-labs/outlook/src/login.ts +129 -0
  290. package/runtime/node_modules/@metro-labs/outlook/src/me.ts +31 -0
  291. package/runtime/node_modules/@metro-labs/outlook/src/outbound.ts +103 -0
  292. package/runtime/node_modules/@metro-labs/outlook/src/query.ts +84 -0
  293. package/runtime/node_modules/@metro-labs/outlook/src/state.ts +28 -0
  294. package/runtime/node_modules/@metro-labs/outlook/src/station.ts +15 -0
  295. package/runtime/node_modules/@metro-labs/outlook/src/trust.ts +41 -0
  296. package/runtime/node_modules/@metro-labs/telegram/package.json +1 -3
  297. package/runtime/node_modules/@metro-labs/telegram/src/accounts.ts +5 -24
  298. package/runtime/node_modules/@metro-labs/telegram/src/actions.ts +8 -6
  299. package/runtime/node_modules/@metro-labs/telegram/src/attachments.ts +1 -1
  300. package/runtime/node_modules/@metro-labs/telegram/src/client.ts +2 -2
  301. package/runtime/node_modules/@metro-labs/telegram/src/format.ts +19 -34
  302. package/runtime/node_modules/@metro-labs/telegram/src/group.ts +3 -3
  303. package/runtime/node_modules/@metro-labs/telegram/src/inbound.ts +13 -34
  304. package/runtime/node_modules/@metro-labs/telegram/src/index.ts +4 -43
  305. package/runtime/node_modules/@metro-labs/telegram/src/media-actions.ts +2 -3
  306. package/runtime/node_modules/@metro-labs/telegram/src/members.ts +1 -1
  307. package/runtime/node_modules/@metro-labs/telegram/src/profile.ts +70 -0
  308. package/runtime/node_modules/@metro-labs/telegram/src/reactions.ts +2 -2
  309. package/runtime/node_modules/@metro-labs/telegram/src/station.ts +4 -1
  310. package/runtime/node_modules/@metro-labs/telegram/src/types.ts +0 -1
  311. package/runtime/node_modules/@metro-labs/telegram-bot/package.json +1 -1
  312. package/runtime/node_modules/@metro-labs/telegram-bot/src/accounts.ts +7 -41
  313. package/runtime/node_modules/@metro-labs/telegram-bot/src/actions.ts +22 -77
  314. package/runtime/node_modules/@metro-labs/telegram-bot/src/attachments.ts +2 -2
  315. package/runtime/node_modules/@metro-labs/telegram-bot/src/format.ts +46 -48
  316. package/runtime/node_modules/@metro-labs/telegram-bot/src/index.ts +15 -15
  317. package/runtime/node_modules/@metro-labs/telegram-bot/src/media-actions.ts +6 -82
  318. package/runtime/node_modules/@metro-labs/telegram-bot/src/members.ts +1 -1
  319. package/runtime/node_modules/@metro-labs/telegram-bot/src/profile.ts +85 -0
  320. package/runtime/node_modules/@metro-labs/telegram-bot/src/station.ts +5 -1
  321. package/runtime/node_modules/@metro-labs/telegram-bot/src/types.ts +20 -12
  322. package/runtime/node_modules/@metro-labs/threema/package.json +26 -0
  323. package/runtime/node_modules/@metro-labs/threema/src/accounts.ts +96 -0
  324. package/runtime/node_modules/@metro-labs/threema/src/actions.ts +124 -0
  325. package/runtime/node_modules/@metro-labs/threema/src/api.ts +152 -0
  326. package/runtime/node_modules/@metro-labs/threema/src/crypto.ts +100 -0
  327. package/runtime/node_modules/@metro-labs/threema/src/files.ts +47 -0
  328. package/runtime/node_modules/@metro-labs/threema/src/format.ts +164 -0
  329. package/runtime/node_modules/@metro-labs/threema/src/groups.ts +96 -0
  330. package/runtime/node_modules/@metro-labs/threema/src/ids.ts +21 -0
  331. package/runtime/node_modules/@metro-labs/threema/src/inbound.ts +87 -0
  332. package/runtime/node_modules/@metro-labs/threema/src/index.ts +24 -0
  333. package/runtime/node_modules/@metro-labs/threema/src/messages.ts +264 -0
  334. package/runtime/node_modules/@metro-labs/threema/src/outbound.ts +160 -0
  335. package/runtime/node_modules/@metro-labs/threema/src/station.ts +13 -0
  336. package/runtime/node_modules/@metro-labs/threema/src/verify.ts +117 -0
  337. package/runtime/node_modules/@metro-labs/webhook/package.json +1 -1
  338. package/runtime/node_modules/@metro-labs/webhook/src/station.ts +5 -8
  339. package/runtime/node_modules/@metro-labs/whatsapp/package.json +2 -5
  340. package/runtime/node_modules/@metro-labs/whatsapp/src/accounts.ts +6 -28
  341. package/runtime/node_modules/@metro-labs/whatsapp/src/ack.ts +1 -1
  342. package/runtime/node_modules/@metro-labs/whatsapp/src/actions.ts +54 -11
  343. package/runtime/node_modules/@metro-labs/whatsapp/src/attachments.ts +2 -2
  344. package/runtime/node_modules/@metro-labs/whatsapp/src/auth-state.ts +1 -1
  345. package/runtime/node_modules/@metro-labs/whatsapp/src/client.ts +86 -4
  346. package/runtime/node_modules/@metro-labs/whatsapp/src/format.ts +7 -58
  347. package/runtime/node_modules/@metro-labs/whatsapp/src/inbound.ts +11 -28
  348. package/runtime/node_modules/@metro-labs/whatsapp/src/index.ts +4 -37
  349. package/runtime/node_modules/@metro-labs/whatsapp/src/keys.ts +1 -1
  350. package/runtime/node_modules/@metro-labs/whatsapp/src/login.ts +1 -1
  351. package/runtime/node_modules/@metro-labs/whatsapp/src/media.ts +1 -1
  352. package/runtime/node_modules/@metro-labs/whatsapp/src/names.ts +75 -0
  353. package/runtime/node_modules/@metro-labs/whatsapp/src/parse.ts +44 -0
  354. package/runtime/node_modules/@metro-labs/whatsapp/src/resolve.ts +52 -0
  355. package/runtime/node_modules/@metro-labs/whatsapp/src/station.ts +16 -1
  356. package/runtime/node_modules/@metro-labs/whatsapp/src/token-store.ts +5 -9
  357. package/runtime/node_modules/@metro-labs/whatsapp/src/types.ts +0 -1
  358. package/runtime/node_modules/@metro-labs/xmtp/package.json +3 -2
  359. package/runtime/node_modules/@metro-labs/xmtp/src/accounts.ts +10 -20
  360. package/runtime/node_modules/@metro-labs/xmtp/src/actions-close.ts +2 -2
  361. package/runtime/node_modules/@metro-labs/xmtp/src/actions-conv.ts +15 -204
  362. package/runtime/node_modules/@metro-labs/xmtp/src/actions-meta.ts +40 -53
  363. package/runtime/node_modules/@metro-labs/xmtp/src/actions.ts +72 -220
  364. package/runtime/node_modules/@metro-labs/xmtp/src/attachments.ts +3 -3
  365. package/runtime/node_modules/@metro-labs/xmtp/src/codecs.ts +27 -0
  366. package/runtime/node_modules/@metro-labs/xmtp/src/conv-helpers.ts +11 -7
  367. package/runtime/node_modules/@metro-labs/xmtp/src/emit-payloads.ts +7 -24
  368. package/runtime/node_modules/@metro-labs/xmtp/src/emit.ts +8 -18
  369. package/runtime/node_modules/@metro-labs/xmtp/src/group-members.ts +1 -1
  370. package/runtime/node_modules/@metro-labs/xmtp/src/group.ts +2 -2
  371. package/runtime/node_modules/@metro-labs/xmtp/src/identity.ts +30 -16
  372. package/runtime/node_modules/@metro-labs/xmtp/src/index.ts +12 -20
  373. package/runtime/node_modules/@metro-labs/xmtp/src/labels.ts +57 -33
  374. package/runtime/node_modules/@metro-labs/xmtp/src/member-args.ts +1 -1
  375. package/runtime/node_modules/@metro-labs/xmtp/src/names.ts +61 -0
  376. package/runtime/node_modules/@metro-labs/xmtp/src/profile.ts +153 -0
  377. package/runtime/node_modules/@metro-labs/xmtp/src/resolve.ts +44 -0
  378. package/runtime/node_modules/@metro-labs/xmtp/src/sender.ts +112 -0
  379. package/runtime/node_modules/@metro-labs/xmtp/src/smart.ts +72 -0
  380. package/runtime/node_modules/@metro-labs/xmtp/src/station.ts +7 -2
  381. package/runtime/node_modules/@metro-labs/xmtp/src/tools-handlers.ts +22 -58
  382. package/runtime/node_modules/@metro-labs/xmtp/src/tools.ts +55 -48
  383. package/runtime/node_modules/@metro-labs/xmtp/src/transcribe.ts +4 -6
  384. package/runtime/node_modules/@metro-labs/xmtp/src/verify.ts +19 -5
  385. package/runtime/node_modules/@metro-labs/xmtp/src/wire.ts +14 -4
  386. package/runtime/runtime.json +1 -1
  387. package/runtime/server.ts +1 -0
  388. package/runtime/stations.json +38 -0
  389. package/dist/prompt.js +0 -61
  390. package/dist/store.js +0 -70
  391. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-speak.ts +0 -195
  392. package/runtime/node_modules/@metro-labs/discord-bot/src/voice-transcribe.ts +0 -292
  393. package/runtime/node_modules/@metro-labs/discord-bot/src/voice.ts +0 -197
  394. package/runtime/node_modules/@metro-labs/discord-bot/src/wire.ts +0 -5
  395. package/runtime/node_modules/@metro-labs/mcp/package.json +0 -66
  396. package/runtime/node_modules/@metro-labs/mcp/src/channels/dedupe.ts +0 -24
  397. package/runtime/node_modules/@metro-labs/mcp/src/daemon/account-api.ts +0 -311
  398. package/runtime/node_modules/@metro-labs/mcp/src/daemon/agent-api.ts +0 -341
  399. package/runtime/node_modules/@metro-labs/mcp/src/daemon/api-http.ts +0 -129
  400. package/runtime/node_modules/@metro-labs/mcp/src/daemon/boot.ts +0 -320
  401. package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair-api.ts +0 -111
  402. package/runtime/node_modules/@metro-labs/mcp/src/daemon/cli-pair.ts +0 -20
  403. package/runtime/node_modules/@metro-labs/mcp/src/daemon/collection-api.ts +0 -202
  404. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-json.ts +0 -31
  405. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-tools.ts +0 -100
  406. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-url.ts +0 -57
  407. package/runtime/node_modules/@metro-labs/mcp/src/daemon/connector-verify.ts +0 -333
  408. package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-auth.ts +0 -164
  409. package/runtime/node_modules/@metro-labs/mcp/src/daemon/google-oauth.ts +0 -208
  410. package/runtime/node_modules/@metro-labs/mcp/src/daemon/identity.ts +0 -79
  411. package/runtime/node_modules/@metro-labs/mcp/src/daemon/oauth-pending.ts +0 -65
  412. package/runtime/node_modules/@metro-labs/mcp/src/daemon/pair-codes.ts +0 -58
  413. package/runtime/node_modules/@metro-labs/mcp/src/daemon/project-api.ts +0 -214
  414. package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-api.ts +0 -125
  415. package/runtime/node_modules/@metro-labs/mcp/src/daemon/run-pair.ts +0 -18
  416. package/runtime/node_modules/@metro-labs/mcp/src/daemon/runtime-source.ts +0 -105
  417. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session-apis.ts +0 -41
  418. package/runtime/node_modules/@metro-labs/mcp/src/daemon/session.ts +0 -218
  419. package/runtime/node_modules/@metro-labs/mcp/src/daemon/tunnel.ts +0 -169
  420. package/runtime/node_modules/@metro-labs/mcp/src/db/account-attach.ts +0 -91
  421. package/runtime/node_modules/@metro-labs/mcp/src/db/agent-admin.ts +0 -215
  422. package/runtime/node_modules/@metro-labs/mcp/src/db/agent-map.ts +0 -71
  423. package/runtime/node_modules/@metro-labs/mcp/src/db/client.ts +0 -37
  424. package/runtime/node_modules/@metro-labs/mcp/src/db/connector-collections.ts +0 -218
  425. package/runtime/node_modules/@metro-labs/mcp/src/db/connectors.ts +0 -329
  426. package/runtime/node_modules/@metro-labs/mcp/src/db/projects.ts +0 -300
  427. package/runtime/node_modules/@metro-labs/mcp/src/db/runtime-admin.ts +0 -31
  428. package/runtime/node_modules/@metro-labs/mcp/src/db/runtimes.ts +0 -105
  429. package/runtime/node_modules/@metro-labs/mcp/src/db/schema.ts +0 -131
  430. package/runtime/node_modules/@metro-labs/mcp/src/db/token-carry.ts +0 -45
  431. package/runtime/node_modules/@metro-labs/mcp/src/db/users.ts +0 -57
  432. package/runtime/node_modules/@metro-labs/mcp/src/db/whatsapp-login.ts +0 -18
  433. package/runtime/node_modules/@metro-labs/mcp/src/mcp/channel-owner.ts +0 -29
  434. package/runtime/node_modules/@metro-labs/mcp/src/mcp/frame-scope.ts +0 -21
  435. package/runtime/node_modules/@metro-labs/mcp/src/mcp/permission-relay.ts +0 -66
  436. package/runtime/node_modules/@metro-labs/mcp/src/mcp/request-identity.ts +0 -73
  437. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-registry.ts +0 -172
  438. package/runtime/node_modules/@metro-labs/mcp/src/mcp/session-route.ts +0 -43
  439. package/runtime/node_modules/@metro-labs/mcp/src/monitor/api.ts +0 -240
  440. package/runtime/node_modules/@metro-labs/mcp/src/server.ts +0 -2
  441. package/runtime/node_modules/@metro-labs/mcp/src/stations/account-store.ts +0 -80
  442. package/runtime/node_modules/@metro-labs/mcp/src/stations/messaging-normalize.ts +0 -88
  443. package/runtime/node_modules/@metro-labs/telegram/src/normalize.ts +0 -22
  444. package/runtime/node_modules/@metro-labs/telegram/src/wire.ts +0 -1
  445. package/runtime/node_modules/@metro-labs/telegram-bot/src/wire.ts +0 -3
  446. package/runtime/node_modules/@metro-labs/whatsapp/src/normalize.ts +0 -22
  447. package/runtime/node_modules/@metro-labs/whatsapp/src/wire.ts +0 -5
  448. package/runtime/node_modules/@metro-labs/xmtp/src/actions-push.ts +0 -87
  449. package/runtime/node_modules/@metro-labs/xmtp/src/emit-core.ts +0 -55
  450. package/runtime/node_modules/@metro-labs/xmtp/src/push.ts +0 -349
  451. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/log.ts +0 -0
  452. /package/runtime/node_modules/@metro-labs/{mcp/src/mcp → core/src}/str.ts +0 -0
  453. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → core/src}/train-error.ts +0 -0
  454. /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/channels/webhook-note.ts +0 -0
  455. /package/runtime/node_modules/@metro-labs/{mcp → daemon}/src/mcp/raw-get-stream.ts +0 -0
  456. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/api-error.ts +0 -0
  457. /package/runtime/node_modules/@metro-labs/{mcp/src/daemon → http/src}/cors.ts +0 -0
@@ -0,0 +1,127 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { isRecord } from '@metro-labs/core/is-record';
3
+ import { errMsg, log } from '@metro-labs/core/log';
4
+ import { agentCommand, agentUser, agentUserExpected, claudeBin } from '../agent-user/user.js';
5
+ import { runningAsRoot } from '../metro-user/privilege.js';
6
+ import { PRIVACY_ENV } from './setup.js';
7
+
8
+ const REQUEST_ID = 'metro-usage';
9
+ const REQUEST = `${JSON.stringify({ type: 'control_request', request_id: REQUEST_ID, request: { subtype: 'get_usage', skip_behaviors: true } })}\n`;
10
+ const ARGS = [
11
+ '-p',
12
+ '--setting-sources',
13
+ 'project',
14
+ '--strict-mcp-config',
15
+ '--mcp-config',
16
+ '{"mcpServers":{}}',
17
+ '--no-session-persistence',
18
+ '--input-format',
19
+ 'stream-json',
20
+ '--output-format',
21
+ 'stream-json',
22
+ '--verbose',
23
+ ];
24
+ const BLOCKS_USAGE = 'CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC';
25
+ const PROBE_ENV: Record<string, string> = {
26
+ ...Object.fromEntries(Object.entries(PRIVACY_ENV).filter(([name]) => name !== BLOCKS_USAGE)),
27
+ DISABLE_AUTOUPDATER: '1',
28
+ DISABLE_BUG_COMMAND: '1',
29
+ ENABLE_CLAUDEAI_MCP_SERVERS: 'false',
30
+ };
31
+ const TIMEOUT_MS = 20_000;
32
+ const KILL_GRACE_MS = 2_000;
33
+ const LINE_MAX = 1024 * 1024;
34
+
35
+ export interface UsageProbeDeps {
36
+ command?: string[];
37
+ timeoutMs?: number;
38
+ }
39
+
40
+ export function usageProbeCommand(): string[] | null {
41
+ if (runningAsRoot() || (agentUserExpected() && agentUser() === null)) return null;
42
+ return agentCommand([claudeBin(), ...ARGS], PROBE_ENV);
43
+ }
44
+
45
+ function answerOf(line: string): Record<string, unknown> | null {
46
+ try {
47
+ const parsed: unknown = JSON.parse(line);
48
+ if (!isRecord(parsed) || parsed.type !== 'control_response' || !isRecord(parsed.response)) return null;
49
+ return parsed.response.request_id === REQUEST_ID ? parsed.response : null;
50
+ } catch {
51
+ return null;
52
+ }
53
+ }
54
+
55
+ function limitsOf(answer: Record<string, unknown>): unknown {
56
+ if (answer.subtype !== 'success') throw new Error(`Claude Code refused the usage request: ${typeof answer.error === 'string' ? answer.error : 'no reason given'}`);
57
+ return isRecord(answer.response) ? (answer.response.rate_limits ?? null) : null;
58
+ }
59
+
60
+ export function usageIn(output: string): unknown {
61
+ const answer = output
62
+ .split('\n')
63
+ .map(answerOf)
64
+ .find((found) => found !== null);
65
+ if (answer === undefined || answer === null) throw new Error('Claude Code gave no usage answer');
66
+ return limitsOf(answer);
67
+ }
68
+
69
+ export function readClaudeUsage(deps: UsageProbeDeps = {}): Promise<unknown> {
70
+ const command = deps.command ?? usageProbeCommand();
71
+ if (command === null) return Promise.reject(new Error('Claude Code runs only as the agent user, and this box has none'));
72
+ const [file = '', ...args] = command;
73
+ return new Promise((resolve, reject) => {
74
+ const child = spawn(file, args, { cwd: '/', stdio: ['pipe', 'pipe', 'ignore'], env: { ...process.env, ...PROBE_ENV } });
75
+ let carry = '';
76
+ let settled = false;
77
+ let hardKill: ReturnType<typeof setTimeout> | undefined;
78
+ const settle = (run: () => void): void => {
79
+ if (settled) return;
80
+ settled = true;
81
+ run();
82
+ };
83
+ const overdue = setTimeout(() => {
84
+ settle(() => {
85
+ reject(new Error('Claude Code did not report the usage in time'));
86
+ });
87
+ child.stdout.destroy();
88
+ child.kill('SIGTERM');
89
+ hardKill = setTimeout(() => child.kill('SIGKILL'), KILL_GRACE_MS);
90
+ }, deps.timeoutMs ?? TIMEOUT_MS);
91
+ const take = (line: string): void => {
92
+ const answer = answerOf(line);
93
+ if (answer === null) return;
94
+ settle(() => {
95
+ try {
96
+ resolve(limitsOf(answer));
97
+ } catch (err) {
98
+ reject(err instanceof Error ? err : new Error(errMsg(err)));
99
+ }
100
+ });
101
+ };
102
+ child.stdout.on('data', (chunk: Buffer) => {
103
+ const lines = (carry + chunk.toString('utf8')).split('\n');
104
+ carry = lines.pop() ?? '';
105
+ if (carry.length > LINE_MAX) carry = '';
106
+ lines.forEach(take);
107
+ });
108
+ child.stdin.on('error', (err) => {
109
+ log.debug({ err: errMsg(err) }, 'claude-usage: Claude Code closed its input early');
110
+ });
111
+ child.on('error', (err) => {
112
+ clearTimeout(overdue);
113
+ settle(() => {
114
+ reject(err);
115
+ });
116
+ });
117
+ child.on('close', () => {
118
+ clearTimeout(overdue);
119
+ clearTimeout(hardKill);
120
+ take(carry);
121
+ settle(() => {
122
+ reject(new Error('Claude Code gave no usage answer'));
123
+ });
124
+ });
125
+ child.stdin.end(REQUEST);
126
+ });
127
+ }
@@ -0,0 +1,113 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { ApiError } from '@metro-labs/http/api-error';
5
+ import { errMsg, log } from '@metro-labs/core/log';
6
+ import { isRecord } from '@metro-labs/core/is-record';
7
+ import { sessionRunning, stopSession, type SessionDeps } from './session.js';
8
+ import { agentUser, asAgent, claudeBin } from '../agent-user/user.js';
9
+
10
+ const LATEST_URL = 'https://registry.npmjs.org/@anthropic-ai/claude-code/latest';
11
+ const VERSION_RE = /(\d+)\.(\d+)\.(\d+)/;
12
+ const CACHE_MS = 10 * 60_000;
13
+ const INSTALL_TIMEOUT_MS = 5 * 60_000;
14
+ const TAIL = 400;
15
+
16
+ export interface VersionDeps {
17
+ claude?: string;
18
+ fetchImpl?: typeof fetch;
19
+ session?: SessionDeps;
20
+ now?: () => number;
21
+ }
22
+
23
+ export interface ClaudeVersion {
24
+ installed: string | null;
25
+ latest: string | null;
26
+ newer: boolean;
27
+ }
28
+
29
+ let cached: { latest: string | null; at: number } | null = null;
30
+
31
+ function candidates(deps: VersionDeps): string[] {
32
+ if (deps.claude !== undefined) return [deps.claude];
33
+ return agentUser() === null ? ['claude', join(homedir(), '.local', 'bin', 'claude')] : [claudeBin()];
34
+ }
35
+
36
+ const parse = (text: string): string | null => {
37
+ const m = VERSION_RE.exec(text);
38
+ return m === null ? null : `${m[1] ?? ''}.${m[2] ?? ''}.${m[3] ?? ''}`;
39
+ };
40
+
41
+ function probe(bin: string): string | null {
42
+ const run = spawnSync(...asAgent(bin, ['--version']), { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
43
+ return run.error === undefined && run.status === 0 && typeof run.stdout === 'string' ? parse(run.stdout) : null;
44
+ }
45
+
46
+ function located(deps: VersionDeps): { bin: string; installed: string } | null {
47
+ for (const bin of candidates(deps)) {
48
+ const installed = probe(bin);
49
+ if (installed !== null) return { bin, installed };
50
+ }
51
+ return null;
52
+ }
53
+
54
+ export function newerThan(a: string, b: string): boolean {
55
+ const left = a.split('.').map(Number);
56
+ const right = b.split('.').map(Number);
57
+ for (let i = 0; i < 3; i += 1) {
58
+ const d = (left[i] ?? 0) - (right[i] ?? 0);
59
+ if (d !== 0) return d > 0;
60
+ }
61
+ return false;
62
+ }
63
+
64
+ async function latestClaudeVersion(deps: VersionDeps = {}): Promise<string | null> {
65
+ const now = (deps.now ?? Date.now)();
66
+ if (cached !== null && now - cached.at < CACHE_MS) return cached.latest;
67
+ const fetchImpl = deps.fetchImpl ?? fetch;
68
+ let latest: string | null = null;
69
+ try {
70
+ const res = await fetchImpl(LATEST_URL, { headers: { accept: 'application/json' }, redirect: 'manual' });
71
+ const body: unknown = res.ok ? await res.json() : null;
72
+ latest = isRecord(body) && typeof body.version === 'string' ? parse(body.version) : null;
73
+ } catch (err) {
74
+ log.warn({ err: errMsg(err) }, 'claude-version: could not read the latest version from npm');
75
+ }
76
+ cached = { latest, at: now };
77
+ return latest;
78
+ }
79
+
80
+ export function forgetClaudeVersion(): void {
81
+ cached = null;
82
+ }
83
+
84
+ export async function claudeVersion(deps: VersionDeps = {}): Promise<ClaudeVersion> {
85
+ const installed = located(deps)?.installed ?? null;
86
+ const latest = await latestClaudeVersion(deps);
87
+ return { installed, latest, newer: installed !== null && latest !== null && newerThan(latest, installed) };
88
+ }
89
+
90
+ function install(bin: string): void {
91
+ const run = spawnSync(...asAgent(bin, ['install', 'latest']), { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout: INSTALL_TIMEOUT_MS });
92
+ if (run.error !== undefined) throw new ApiError(`claude install latest failed: ${errMsg(run.error)}`, 502);
93
+ if (run.status === 0) return;
94
+ const said = `${run.stderr ?? ''}${run.stdout ?? ''}`.trim().slice(-TAIL);
95
+ throw new ApiError(`claude install latest failed: ${said}`, 502);
96
+ }
97
+
98
+ function restartIfChanged(changed: boolean, session: SessionDeps): boolean {
99
+ if (!changed || !sessionRunning(session.tmux ?? 'tmux')) return false;
100
+ stopSession(session);
101
+ return true;
102
+ }
103
+
104
+ export async function updateClaude(deps: VersionDeps = {}): Promise<ClaudeVersion & { restarted: boolean }> {
105
+ const found = located(deps);
106
+ if (found === null) throw new ApiError('Claude Code is not installed on this machine', 404);
107
+ install(found.bin);
108
+ forgetClaudeVersion();
109
+ const after = await claudeVersion(deps);
110
+ const restarted = restartIfChanged(after.installed !== null && after.installed !== found.installed, deps.session ?? {});
111
+ log.info({ from: found.installed, to: after.installed, restarted }, 'claude-version: Claude Code updated');
112
+ return { ...after, restarted };
113
+ }
@@ -1,82 +1,44 @@
1
1
  import type { IncomingMessage, ServerResponse } from 'node:http';
2
- import { errMsg, log } from './log.js';
2
+ import { log } from '@metro-labs/core/log';
3
+ import { healthOf } from './health.js';
4
+ import type { RemoteTool } from './tools.js';
5
+ import { normalizePolicy, type ToolPolicy } from '../policy/policy.js';
3
6
  import {
4
7
  apiFailure,
5
8
  apiSession,
6
- projectParam,
7
9
  bodyField,
8
10
  cors,
9
11
  readJsonBody,
10
12
  sendJson,
11
- type ApiSession,
12
- } from './api-http.js';
13
- import { parseId } from '../db/ids.js';
14
- import type { ConnectorCollectionRow } from '../db/connector-collections.js';
13
+ stringOf,
14
+ } from '@metro-labs/http/api-http';
15
+ import { parseId } from '@metro-labs/core/ids';
15
16
  import {
16
17
  handleCallback,
17
18
  handleConnect,
18
19
  hostOf,
19
20
  startOAuth,
20
21
  type OAuthRouteDeps,
21
- } from './connector-oauth-routes.js';
22
- import { ConnectorUnauthorized } from './connector-verify.js';
22
+ } from './oauth-routes.js';
23
+ import { ConnectorUnauthorized } from './verify.js';
23
24
  import type {
24
25
  Connector,
25
26
  ConnectorCheck,
26
27
  ConnectorInput,
27
28
  DeletedConnector,
28
- } from '../db/connectors.js';
29
+ } from './store.js';
29
30
 
30
31
  const PREFIX = '/api/connectors';
31
32
 
32
- const asText = (value: unknown): string =>
33
- typeof value === 'string' ? value : '';
34
-
35
33
  export interface ConnectorApiDeps extends OAuthRouteDeps {
36
- listConnectors: (email: string, project: string) => Promise<Connector[]>;
37
- freshConnectorsByIds: (ids: string[]) => Promise<Connector[]>;
38
- listCollections: (
39
- email: string,
40
- project: string,
41
- ) => Promise<ConnectorCollectionRow[]>;
42
- getCollection: (email: string, id: string) => Promise<ConnectorCollectionRow>;
43
- createCollection: (
44
- email: string,
45
- project: string,
46
- name: string,
47
- ) => Promise<ConnectorCollectionRow>;
48
- renameCollection: (
49
- email: string,
50
- id: string,
51
- name: string,
52
- ) => Promise<ConnectorCollectionRow>;
53
- deleteCollection: (
54
- email: string,
55
- id: string,
56
- ) => Promise<{ id: string; name: string }>;
57
- addToCollection: (
58
- email: string,
59
- id: string,
60
- connectorId: string,
61
- ) => Promise<ConnectorCollectionRow>;
62
- removeFromCollection: (
63
- email: string,
64
- id: string,
65
- connectorId: string,
66
- ) => Promise<ConnectorCollectionRow>;
67
- createConnector: (
68
- email: string,
69
- project: string,
70
- input: ConnectorInput,
71
- ) => Promise<Connector>;
72
- verifyConnector: (email: string, id: string) => Promise<ConnectorCheck>;
73
- disconnectConnector: (email: string, id: string) => Promise<Connector>;
74
- renameConnector: (
75
- email: string,
76
- id: string,
77
- name: string,
78
- ) => Promise<Connector>;
79
- deleteConnector: (email: string, id: string) => Promise<DeletedConnector>;
34
+ listConnectors: () => Promise<Connector[]>;
35
+ createConnector: (input: ConnectorInput) => Promise<Connector>;
36
+ verifyConnector: (id: string) => Promise<ConnectorCheck>;
37
+ connectorTools: (id: string) => Promise<RemoteTool[]>;
38
+ disconnectConnector: (id: string) => Promise<Connector>;
39
+ renameConnector: (id: string, name: string) => Promise<Connector>;
40
+ deleteConnector: (id: string) => Promise<DeletedConnector>;
41
+ setConnectorPolicy: (id: string, policy: ToolPolicy) => Promise<Connector>;
80
42
  }
81
43
 
82
44
  type Routable =
@@ -84,9 +46,11 @@ type Routable =
84
46
  | { kind: 'callback' }
85
47
  | { kind: 'connector'; id: string }
86
48
  | { kind: 'verify'; id: string }
49
+ | { kind: 'tools'; id: string }
87
50
  | { kind: 'connect'; id: string }
88
51
  | { kind: 'disconnect'; id: string }
89
- | { kind: 'rename'; id: string };
52
+ | { kind: 'rename'; id: string }
53
+ | { kind: 'policy'; id: string };
90
54
 
91
55
  type Target = Routable | { kind: 'unknown' } | null;
92
56
 
@@ -95,9 +59,11 @@ function subTarget(id: string, rest: string[]): Target {
95
59
  if (rest.length > 1) return { kind: 'unknown' };
96
60
  const head = rest[0];
97
61
  if (head === 'verify') return { kind: 'verify', id };
62
+ if (head === 'tools') return { kind: 'tools', id };
98
63
  if (head === 'connect') return { kind: 'connect', id };
99
64
  if (head === 'disconnect') return { kind: 'disconnect', id };
100
65
  if (head === 'rename') return { kind: 'rename', id };
66
+ if (head === 'policy') return { kind: 'policy', id };
101
67
  return { kind: 'unknown' };
102
68
  }
103
69
 
@@ -112,20 +78,18 @@ function target(path: string): Target {
112
78
  return id === null ? { kind: 'unknown' } : subTarget(id, segments.slice(1));
113
79
  }
114
80
 
115
- function connectorPayload(
116
- row: Connector,
117
- detail = false,
118
- ): Record<string, unknown> {
119
- const { catalog, ...summary } = row.verified;
81
+ function connectorPayload(row: Connector): Record<string, unknown> {
120
82
  return {
121
83
  id: row.id,
122
84
  name: row.name,
123
85
  url: row.url,
124
- transport: row.transport,
125
86
  auth: row.auth,
126
87
  header: row.header,
88
+ clientId: row.client?.clientId ?? null,
127
89
  signIn: row.signIn,
128
- verified: detail ? { ...summary, catalog } : summary,
90
+ verified: row.verified,
91
+ policy: row.policy,
92
+ health: healthOf(row.id),
129
93
  };
130
94
  }
131
95
 
@@ -133,14 +97,8 @@ async function handleList(
133
97
  req: IncomingMessage,
134
98
  res: ServerResponse,
135
99
  deps: ConnectorApiDeps,
136
- session: ApiSession,
137
100
  ): Promise<void> {
138
- const project = projectParam(req);
139
- if (project === null) {
140
- sendJson(req, res, 400, { error: 'a project is required' });
141
- return;
142
- }
143
- const rows = await deps.listConnectors(session.email, project);
101
+ const rows = await deps.listConnectors();
144
102
  sendJson(req, res, 200, {
145
103
  connectors: rows.map((row) => connectorPayload(row)),
146
104
  });
@@ -150,21 +108,17 @@ async function handleCreate(
150
108
  req: IncomingMessage,
151
109
  res: ServerResponse,
152
110
  deps: ConnectorApiDeps,
153
- session: ApiSession,
154
111
  ): Promise<void> {
155
112
  const body = await readJsonBody(req);
156
- const project = projectParam(req);
157
- if (project === null) {
158
- sendJson(req, res, 400, { error: 'a project is required' });
159
- return;
160
- }
161
- const offered = asText(bodyField(body, 'value')).trim() !== '';
113
+ const offered = stringOf(bodyField(body, 'value')).trim() !== '';
162
114
  try {
163
- const created = await deps.createConnector(session.email, project, {
115
+ const created = await deps.createConnector({
164
116
  name: bodyField(body, 'name'),
165
117
  url: bodyField(body, 'url'),
166
118
  header: bodyField(body, 'header'),
167
119
  value: bodyField(body, 'value'),
120
+ clientId: bodyField(body, 'clientId'),
121
+ clientSecret: bodyField(body, 'clientSecret'),
168
122
  });
169
123
  log.info(
170
124
  { id: created.id, name: created.name, host: hostOf(created.url) },
@@ -173,7 +127,7 @@ async function handleCreate(
173
127
  sendJson(req, res, 201, connectorPayload(created));
174
128
  } catch (err) {
175
129
  if (offered || !(err instanceof ConnectorUnauthorized)) throw err;
176
- await startOAuth(req, res, deps, session, project, body, (row) =>
130
+ await startOAuth(req, res, deps, body, (row) =>
177
131
  connectorPayload(row),
178
132
  );
179
133
  }
@@ -183,10 +137,9 @@ async function handleVerify(
183
137
  req: IncomingMessage,
184
138
  res: ServerResponse,
185
139
  deps: ConnectorApiDeps,
186
- session: ApiSession,
187
140
  id: string,
188
141
  ): Promise<void> {
189
- const check = await deps.verifyConnector(session.email, id);
142
+ const check = await deps.verifyConnector(id);
190
143
  log.info(
191
144
  { id: check.id, name: check.name, ok: check.ok },
192
145
  'connector-api: re-verified connector',
@@ -198,10 +151,9 @@ async function handleDisconnect(
198
151
  req: IncomingMessage,
199
152
  res: ServerResponse,
200
153
  deps: ConnectorApiDeps,
201
- session: ApiSession,
202
154
  id: string,
203
155
  ): Promise<void> {
204
- const row = await deps.disconnectConnector(session.email, id);
156
+ const row = await deps.disconnectConnector(id);
205
157
  log.info(
206
158
  { id: row.id, name: row.name },
207
159
  'connector-api: signed the connector out',
@@ -213,10 +165,9 @@ async function handleDelete(
213
165
  req: IncomingMessage,
214
166
  res: ServerResponse,
215
167
  deps: ConnectorApiDeps,
216
- session: ApiSession,
217
168
  id: string,
218
169
  ): Promise<void> {
219
- const gone = await deps.deleteConnector(session.email, id);
170
+ const gone = await deps.deleteConnector(id);
220
171
  log.info(
221
172
  { id: gone.id, name: gone.name },
222
173
  'connector-api: deleted connector',
@@ -228,22 +179,20 @@ async function handleConnector(
228
179
  req: IncomingMessage,
229
180
  res: ServerResponse,
230
181
  deps: ConnectorApiDeps,
231
- session: ApiSession,
232
182
  id: string,
233
183
  ): Promise<void> {
234
184
  if (req.method !== 'GET') {
235
- await handleDelete(req, res, deps, session, id);
185
+ await handleDelete(req, res, deps, id);
236
186
  return;
237
187
  }
238
- const row = await deps.getConnector(session.email, id);
239
- sendJson(req, res, 200, connectorPayload(row, true));
188
+ const row = await deps.getConnector(id);
189
+ sendJson(req, res, 200, connectorPayload(row));
240
190
  }
241
191
 
242
192
  async function handleRename(
243
193
  req: IncomingMessage,
244
194
  res: ServerResponse,
245
195
  deps: ConnectorApiDeps,
246
- session: ApiSession,
247
196
  id: string,
248
197
  ): Promise<void> {
249
198
  const name = bodyField(await readJsonBody(req), 'name');
@@ -251,32 +200,48 @@ async function handleRename(
251
200
  sendJson(req, res, 400, { error: 'name is required' });
252
201
  return;
253
202
  }
254
- const row = await deps.renameConnector(session.email, id, name);
203
+ const row = await deps.renameConnector(id, name);
255
204
  log.info({ id: row.id, name: row.name }, 'connector-api: renamed connector');
256
205
  sendJson(req, res, 200, connectorPayload(row));
257
206
  }
258
207
 
208
+ async function handlePolicy(
209
+ req: IncomingMessage,
210
+ res: ServerResponse,
211
+ deps: ConnectorApiDeps,
212
+ id: string,
213
+ ): Promise<void> {
214
+ const policy = normalizePolicy(bodyField(await readJsonBody(req), 'policy'));
215
+ const row = await deps.setConnectorPolicy(id, policy);
216
+ log.info({ id: row.id, name: row.name, policy: row.policy }, 'connector-api: tool policy set');
217
+ sendJson(req, res, 200, connectorPayload(row));
218
+ }
219
+
220
+ type ById = Exclude<Routable['kind'], 'collection' | 'callback'>;
221
+
222
+ const BY_ID: Record<ById, (req: IncomingMessage, res: ServerResponse, deps: ConnectorApiDeps, id: string) => Promise<void>> = {
223
+ verify: handleVerify,
224
+ tools: async (req, res, deps, id) => {
225
+ sendJson(req, res, 200, { tools: await deps.connectorTools(id) });
226
+ },
227
+ connect: handleConnect,
228
+ disconnect: handleDisconnect,
229
+ rename: handleRename,
230
+ policy: handlePolicy,
231
+ connector: handleConnector,
232
+ };
233
+
259
234
  async function route(
260
235
  req: IncomingMessage,
261
236
  res: ServerResponse,
262
237
  deps: ConnectorApiDeps,
263
- session: ApiSession,
264
238
  tgt: Routable,
265
239
  ): Promise<void> {
266
240
  try {
267
241
  if (tgt.kind === 'callback') return;
268
- if (tgt.kind === 'verify')
269
- await handleVerify(req, res, deps, session, tgt.id);
270
- else if (tgt.kind === 'connect')
271
- await handleConnect(req, res, deps, session, tgt.id);
272
- else if (tgt.kind === 'disconnect')
273
- await handleDisconnect(req, res, deps, session, tgt.id);
274
- else if (tgt.kind === 'rename')
275
- await handleRename(req, res, deps, session, tgt.id);
276
- else if (tgt.kind === 'connector')
277
- await handleConnector(req, res, deps, session, tgt.id);
278
- else if (req.method === 'GET') await handleList(req, res, deps, session);
279
- else await handleCreate(req, res, deps, session);
242
+ if (tgt.kind !== 'collection') await BY_ID[tgt.kind](req, res, deps, tgt.id);
243
+ else if (req.method === 'GET') await handleList(req, res, deps);
244
+ else await handleCreate(req, res, deps);
280
245
  } catch (err) {
281
246
  apiFailure(req, res, err, 'connector-api');
282
247
  }
@@ -287,12 +252,14 @@ const ALLOWED: Record<Routable['kind'], string[]> = {
287
252
  callback: ['GET'],
288
253
  connector: ['GET', 'DELETE'],
289
254
  verify: ['POST'],
255
+ tools: ['GET'],
290
256
  connect: ['POST'],
291
257
  disconnect: ['POST'],
292
258
  rename: ['POST'],
259
+ policy: ['PUT'],
293
260
  };
294
261
 
295
- function dispatch(
262
+ async function dispatch(
296
263
  req: IncomingMessage,
297
264
  res: ServerResponse,
298
265
  deps: ConnectorApiDeps,
@@ -300,14 +267,14 @@ function dispatch(
300
267
  ): Promise<void> {
301
268
  if (tgt.kind === 'callback') {
302
269
  handleCallback(req, res, deps);
303
- return Promise.resolve();
270
+ return;
304
271
  }
305
- const session = apiSession(req);
272
+ const session = await apiSession(req);
306
273
  if (!session) {
307
274
  sendJson(req, res, 401, { error: 'unauthorized' });
308
- return Promise.resolve();
275
+ return;
309
276
  }
310
- return route(req, res, deps, session, tgt);
277
+ await route(req, res, deps, tgt);
311
278
  }
312
279
 
313
280
  export function handleConnectorApiRequest(
@@ -330,9 +297,8 @@ export function handleConnectorApiRequest(
330
297
  return true;
331
298
  }
332
299
  dispatch(req, res, deps, tgt).catch((err: unknown) => {
333
- log.warn({ err: errMsg(err) }, 'connector-api: unhandled error');
334
- if (!res.headersSent)
335
- sendJson(req, res, 500, { error: 'connector api failed' });
300
+ if (res.headersSent) return;
301
+ apiFailure(req, res, err, 'connector-api');
336
302
  });
337
303
  return true;
338
304
  }