agent-relay 1.0.22 → 1.2.0

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 (613) hide show
  1. package/README.md +1 -1
  2. package/dist/bridge/shadow-cli.d.ts +17 -0
  3. package/dist/bridge/shadow-cli.d.ts.map +1 -0
  4. package/dist/bridge/shadow-cli.js +75 -0
  5. package/dist/bridge/shadow-cli.js.map +1 -0
  6. package/dist/bridge/shadow-config.d.ts +87 -0
  7. package/dist/bridge/shadow-config.d.ts.map +1 -0
  8. package/dist/bridge/shadow-config.js +134 -0
  9. package/dist/bridge/shadow-config.js.map +1 -0
  10. package/dist/bridge/spawner.d.ts +68 -1
  11. package/dist/bridge/spawner.d.ts.map +1 -1
  12. package/dist/bridge/spawner.js +360 -16
  13. package/dist/bridge/spawner.js.map +1 -1
  14. package/dist/bridge/types.d.ts +67 -0
  15. package/dist/bridge/types.d.ts.map +1 -1
  16. package/dist/cli/index.js +1196 -15
  17. package/dist/cli/index.js.map +1 -1
  18. package/dist/cloud/api/auth.d.ts +20 -0
  19. package/dist/cloud/api/auth.d.ts.map +1 -0
  20. package/dist/cloud/api/auth.js +128 -0
  21. package/dist/cloud/api/auth.js.map +1 -0
  22. package/dist/cloud/api/billing.d.ts +17 -0
  23. package/dist/cloud/api/billing.d.ts.map +1 -0
  24. package/dist/cloud/api/billing.js +353 -0
  25. package/dist/cloud/api/billing.js.map +1 -0
  26. package/dist/cloud/api/cli-pty-runner.d.ts +54 -0
  27. package/dist/cloud/api/cli-pty-runner.d.ts.map +1 -0
  28. package/dist/cloud/api/cli-pty-runner.js +119 -0
  29. package/dist/cloud/api/cli-pty-runner.js.map +1 -0
  30. package/dist/cloud/api/coordinators.d.ts +8 -0
  31. package/dist/cloud/api/coordinators.d.ts.map +1 -0
  32. package/dist/cloud/api/coordinators.js +347 -0
  33. package/dist/cloud/api/coordinators.js.map +1 -0
  34. package/dist/cloud/api/daemons.d.ts +12 -0
  35. package/dist/cloud/api/daemons.d.ts.map +1 -0
  36. package/dist/cloud/api/daemons.js +320 -0
  37. package/dist/cloud/api/daemons.js.map +1 -0
  38. package/dist/cloud/api/generic-webhooks.d.ts +8 -0
  39. package/dist/cloud/api/generic-webhooks.d.ts.map +1 -0
  40. package/dist/cloud/api/generic-webhooks.js +129 -0
  41. package/dist/cloud/api/generic-webhooks.js.map +1 -0
  42. package/dist/cloud/api/git.d.ts +8 -0
  43. package/dist/cloud/api/git.d.ts.map +1 -0
  44. package/dist/cloud/api/git.js +131 -0
  45. package/dist/cloud/api/git.js.map +1 -0
  46. package/dist/cloud/api/github-app.d.ts +11 -0
  47. package/dist/cloud/api/github-app.d.ts.map +1 -0
  48. package/dist/cloud/api/github-app.js +189 -0
  49. package/dist/cloud/api/github-app.js.map +1 -0
  50. package/dist/cloud/api/middleware/planLimits.d.ts +43 -0
  51. package/dist/cloud/api/middleware/planLimits.d.ts.map +1 -0
  52. package/dist/cloud/api/middleware/planLimits.js +202 -0
  53. package/dist/cloud/api/middleware/planLimits.js.map +1 -0
  54. package/dist/cloud/api/monitoring.d.ts +11 -0
  55. package/dist/cloud/api/monitoring.d.ts.map +1 -0
  56. package/dist/cloud/api/monitoring.js +578 -0
  57. package/dist/cloud/api/monitoring.js.map +1 -0
  58. package/dist/cloud/api/nango-auth.d.ts +9 -0
  59. package/dist/cloud/api/nango-auth.d.ts.map +1 -0
  60. package/dist/cloud/api/nango-auth.js +377 -0
  61. package/dist/cloud/api/nango-auth.js.map +1 -0
  62. package/dist/cloud/api/onboarding.d.ts +15 -0
  63. package/dist/cloud/api/onboarding.d.ts.map +1 -0
  64. package/dist/cloud/api/onboarding.js +588 -0
  65. package/dist/cloud/api/onboarding.js.map +1 -0
  66. package/dist/cloud/api/policy.d.ts +8 -0
  67. package/dist/cloud/api/policy.d.ts.map +1 -0
  68. package/dist/cloud/api/policy.js +229 -0
  69. package/dist/cloud/api/policy.js.map +1 -0
  70. package/dist/cloud/api/providers.d.ts +7 -0
  71. package/dist/cloud/api/providers.d.ts.map +1 -0
  72. package/dist/cloud/api/providers.js +507 -0
  73. package/dist/cloud/api/providers.js.map +1 -0
  74. package/dist/cloud/api/repos.d.ts +7 -0
  75. package/dist/cloud/api/repos.d.ts.map +1 -0
  76. package/dist/cloud/api/repos.js +314 -0
  77. package/dist/cloud/api/repos.js.map +1 -0
  78. package/dist/cloud/api/teams.d.ts +7 -0
  79. package/dist/cloud/api/teams.d.ts.map +1 -0
  80. package/dist/cloud/api/teams.js +279 -0
  81. package/dist/cloud/api/teams.js.map +1 -0
  82. package/dist/cloud/api/test-helpers.d.ts +10 -0
  83. package/dist/cloud/api/test-helpers.d.ts.map +1 -0
  84. package/dist/cloud/api/test-helpers.js +575 -0
  85. package/dist/cloud/api/test-helpers.js.map +1 -0
  86. package/dist/cloud/api/usage.d.ts +7 -0
  87. package/dist/cloud/api/usage.d.ts.map +1 -0
  88. package/dist/cloud/api/usage.js +98 -0
  89. package/dist/cloud/api/usage.js.map +1 -0
  90. package/dist/cloud/api/webhooks.d.ts +7 -0
  91. package/dist/cloud/api/webhooks.d.ts.map +1 -0
  92. package/dist/cloud/api/webhooks.js +496 -0
  93. package/dist/cloud/api/webhooks.js.map +1 -0
  94. package/dist/cloud/api/workspaces.d.ts +7 -0
  95. package/dist/cloud/api/workspaces.d.ts.map +1 -0
  96. package/dist/cloud/api/workspaces.js +727 -0
  97. package/dist/cloud/api/workspaces.js.map +1 -0
  98. package/dist/cloud/billing/index.d.ts +9 -0
  99. package/dist/cloud/billing/index.d.ts.map +1 -0
  100. package/dist/cloud/billing/index.js +9 -0
  101. package/dist/cloud/billing/index.js.map +1 -0
  102. package/dist/cloud/billing/plans.d.ts +39 -0
  103. package/dist/cloud/billing/plans.d.ts.map +1 -0
  104. package/dist/cloud/billing/plans.js +245 -0
  105. package/dist/cloud/billing/plans.js.map +1 -0
  106. package/dist/cloud/billing/service.d.ts +80 -0
  107. package/dist/cloud/billing/service.d.ts.map +1 -0
  108. package/dist/cloud/billing/service.js +388 -0
  109. package/dist/cloud/billing/service.js.map +1 -0
  110. package/dist/cloud/billing/types.d.ts +141 -0
  111. package/dist/cloud/billing/types.d.ts.map +1 -0
  112. package/dist/cloud/billing/types.js +7 -0
  113. package/dist/cloud/billing/types.js.map +1 -0
  114. package/dist/cloud/config.d.ts +66 -0
  115. package/dist/cloud/config.d.ts.map +1 -0
  116. package/dist/cloud/config.js +92 -0
  117. package/dist/cloud/config.js.map +1 -0
  118. package/dist/cloud/db/drizzle.d.ts +215 -0
  119. package/dist/cloud/db/drizzle.d.ts.map +1 -0
  120. package/dist/cloud/db/drizzle.js +1083 -0
  121. package/dist/cloud/db/drizzle.js.map +1 -0
  122. package/dist/cloud/db/index.d.ts +35 -0
  123. package/dist/cloud/db/index.d.ts.map +1 -0
  124. package/dist/cloud/db/index.js +52 -0
  125. package/dist/cloud/db/index.js.map +1 -0
  126. package/dist/cloud/db/schema.d.ts +4519 -0
  127. package/dist/cloud/db/schema.d.ts.map +1 -0
  128. package/dist/cloud/db/schema.js +547 -0
  129. package/dist/cloud/db/schema.js.map +1 -0
  130. package/dist/cloud/index.d.ts +12 -0
  131. package/dist/cloud/index.d.ts.map +1 -0
  132. package/dist/cloud/index.js +39 -0
  133. package/dist/cloud/index.js.map +1 -0
  134. package/dist/cloud/provisioner/index.d.ts +75 -0
  135. package/dist/cloud/provisioner/index.d.ts.map +1 -0
  136. package/dist/cloud/provisioner/index.js +977 -0
  137. package/dist/cloud/provisioner/index.js.map +1 -0
  138. package/dist/cloud/server.d.ts +17 -0
  139. package/dist/cloud/server.d.ts.map +1 -0
  140. package/dist/cloud/server.js +534 -0
  141. package/dist/cloud/server.js.map +1 -0
  142. package/dist/cloud/services/auto-scaler.d.ts +152 -0
  143. package/dist/cloud/services/auto-scaler.d.ts.map +1 -0
  144. package/dist/cloud/services/auto-scaler.js +439 -0
  145. package/dist/cloud/services/auto-scaler.js.map +1 -0
  146. package/dist/cloud/services/capacity-manager.d.ts +148 -0
  147. package/dist/cloud/services/capacity-manager.d.ts.map +1 -0
  148. package/dist/cloud/services/capacity-manager.js +449 -0
  149. package/dist/cloud/services/capacity-manager.js.map +1 -0
  150. package/dist/cloud/services/ci-agent-spawner.d.ts +49 -0
  151. package/dist/cloud/services/ci-agent-spawner.d.ts.map +1 -0
  152. package/dist/cloud/services/ci-agent-spawner.js +373 -0
  153. package/dist/cloud/services/ci-agent-spawner.js.map +1 -0
  154. package/dist/cloud/services/coordinator.d.ts +62 -0
  155. package/dist/cloud/services/coordinator.d.ts.map +1 -0
  156. package/dist/cloud/services/coordinator.js +389 -0
  157. package/dist/cloud/services/coordinator.js.map +1 -0
  158. package/dist/cloud/services/index.d.ts +12 -0
  159. package/dist/cloud/services/index.d.ts.map +1 -0
  160. package/dist/cloud/services/index.js +15 -0
  161. package/dist/cloud/services/index.js.map +1 -0
  162. package/dist/cloud/services/mention-handler.d.ts +65 -0
  163. package/dist/cloud/services/mention-handler.d.ts.map +1 -0
  164. package/dist/cloud/services/mention-handler.js +405 -0
  165. package/dist/cloud/services/mention-handler.js.map +1 -0
  166. package/dist/cloud/services/nango.d.ts +126 -0
  167. package/dist/cloud/services/nango.d.ts.map +1 -0
  168. package/dist/cloud/services/nango.js +191 -0
  169. package/dist/cloud/services/nango.js.map +1 -0
  170. package/dist/cloud/services/persistence.d.ts +131 -0
  171. package/dist/cloud/services/persistence.d.ts.map +1 -0
  172. package/dist/cloud/services/persistence.js +200 -0
  173. package/dist/cloud/services/persistence.js.map +1 -0
  174. package/dist/cloud/services/planLimits.d.ts +125 -0
  175. package/dist/cloud/services/planLimits.d.ts.map +1 -0
  176. package/dist/cloud/services/planLimits.js +282 -0
  177. package/dist/cloud/services/planLimits.js.map +1 -0
  178. package/dist/cloud/services/scaling-orchestrator.d.ts +159 -0
  179. package/dist/cloud/services/scaling-orchestrator.d.ts.map +1 -0
  180. package/dist/cloud/services/scaling-orchestrator.js +502 -0
  181. package/dist/cloud/services/scaling-orchestrator.js.map +1 -0
  182. package/dist/cloud/services/scaling-policy.d.ts +121 -0
  183. package/dist/cloud/services/scaling-policy.d.ts.map +1 -0
  184. package/dist/cloud/services/scaling-policy.js +415 -0
  185. package/dist/cloud/services/scaling-policy.js.map +1 -0
  186. package/dist/cloud/vault/index.d.ts +76 -0
  187. package/dist/cloud/vault/index.d.ts.map +1 -0
  188. package/dist/cloud/vault/index.js +219 -0
  189. package/dist/cloud/vault/index.js.map +1 -0
  190. package/dist/cloud/webhooks/index.d.ts +24 -0
  191. package/dist/cloud/webhooks/index.d.ts.map +1 -0
  192. package/dist/cloud/webhooks/index.js +29 -0
  193. package/dist/cloud/webhooks/index.js.map +1 -0
  194. package/dist/cloud/webhooks/parsers/github.d.ts +8 -0
  195. package/dist/cloud/webhooks/parsers/github.d.ts.map +1 -0
  196. package/dist/cloud/webhooks/parsers/github.js +234 -0
  197. package/dist/cloud/webhooks/parsers/github.js.map +1 -0
  198. package/dist/cloud/webhooks/parsers/index.d.ts +23 -0
  199. package/dist/cloud/webhooks/parsers/index.d.ts.map +1 -0
  200. package/dist/cloud/webhooks/parsers/index.js +30 -0
  201. package/dist/cloud/webhooks/parsers/index.js.map +1 -0
  202. package/dist/cloud/webhooks/parsers/linear.d.ts +9 -0
  203. package/dist/cloud/webhooks/parsers/linear.d.ts.map +1 -0
  204. package/dist/cloud/webhooks/parsers/linear.js +258 -0
  205. package/dist/cloud/webhooks/parsers/linear.js.map +1 -0
  206. package/dist/cloud/webhooks/parsers/slack.d.ts +9 -0
  207. package/dist/cloud/webhooks/parsers/slack.d.ts.map +1 -0
  208. package/dist/cloud/webhooks/parsers/slack.js +214 -0
  209. package/dist/cloud/webhooks/parsers/slack.js.map +1 -0
  210. package/dist/cloud/webhooks/responders/github.d.ts +8 -0
  211. package/dist/cloud/webhooks/responders/github.d.ts.map +1 -0
  212. package/dist/cloud/webhooks/responders/github.js +73 -0
  213. package/dist/cloud/webhooks/responders/github.js.map +1 -0
  214. package/dist/cloud/webhooks/responders/index.d.ts +23 -0
  215. package/dist/cloud/webhooks/responders/index.d.ts.map +1 -0
  216. package/dist/cloud/webhooks/responders/index.js +30 -0
  217. package/dist/cloud/webhooks/responders/index.js.map +1 -0
  218. package/dist/cloud/webhooks/responders/linear.d.ts +9 -0
  219. package/dist/cloud/webhooks/responders/linear.d.ts.map +1 -0
  220. package/dist/cloud/webhooks/responders/linear.js +149 -0
  221. package/dist/cloud/webhooks/responders/linear.js.map +1 -0
  222. package/dist/cloud/webhooks/responders/slack.d.ts +20 -0
  223. package/dist/cloud/webhooks/responders/slack.d.ts.map +1 -0
  224. package/dist/cloud/webhooks/responders/slack.js +178 -0
  225. package/dist/cloud/webhooks/responders/slack.js.map +1 -0
  226. package/dist/cloud/webhooks/router.d.ts +25 -0
  227. package/dist/cloud/webhooks/router.d.ts.map +1 -0
  228. package/dist/cloud/webhooks/router.js +504 -0
  229. package/dist/cloud/webhooks/router.js.map +1 -0
  230. package/dist/cloud/webhooks/rules-engine.d.ts +24 -0
  231. package/dist/cloud/webhooks/rules-engine.d.ts.map +1 -0
  232. package/dist/cloud/webhooks/rules-engine.js +287 -0
  233. package/dist/cloud/webhooks/rules-engine.js.map +1 -0
  234. package/dist/cloud/webhooks/types.d.ts +186 -0
  235. package/dist/cloud/webhooks/types.d.ts.map +1 -0
  236. package/dist/cloud/webhooks/types.js +8 -0
  237. package/dist/cloud/webhooks/types.js.map +1 -0
  238. package/dist/continuity/formatter.d.ts +51 -0
  239. package/dist/continuity/formatter.d.ts.map +1 -0
  240. package/dist/continuity/formatter.js +313 -0
  241. package/dist/continuity/formatter.js.map +1 -0
  242. package/dist/continuity/handoff-store.d.ts +67 -0
  243. package/dist/continuity/handoff-store.d.ts.map +1 -0
  244. package/dist/continuity/handoff-store.js +472 -0
  245. package/dist/continuity/handoff-store.js.map +1 -0
  246. package/dist/continuity/index.d.ts +45 -0
  247. package/dist/continuity/index.d.ts.map +1 -0
  248. package/dist/continuity/index.js +48 -0
  249. package/dist/continuity/index.js.map +1 -0
  250. package/dist/continuity/ledger-store.d.ts +110 -0
  251. package/dist/continuity/ledger-store.d.ts.map +1 -0
  252. package/dist/continuity/ledger-store.js +500 -0
  253. package/dist/continuity/ledger-store.js.map +1 -0
  254. package/dist/continuity/manager.d.ts +178 -0
  255. package/dist/continuity/manager.d.ts.map +1 -0
  256. package/dist/continuity/manager.js +562 -0
  257. package/dist/continuity/manager.js.map +1 -0
  258. package/dist/continuity/parser.d.ts +76 -0
  259. package/dist/continuity/parser.d.ts.map +1 -0
  260. package/dist/continuity/parser.js +579 -0
  261. package/dist/continuity/parser.js.map +1 -0
  262. package/dist/continuity/types.d.ts +180 -0
  263. package/dist/continuity/types.d.ts.map +1 -0
  264. package/dist/continuity/types.js +9 -0
  265. package/dist/continuity/types.js.map +1 -0
  266. package/dist/daemon/agent-manager.d.ts +114 -0
  267. package/dist/daemon/agent-manager.d.ts.map +1 -0
  268. package/dist/daemon/agent-manager.js +513 -0
  269. package/dist/daemon/agent-manager.js.map +1 -0
  270. package/dist/daemon/agent-registry.d.ts +34 -0
  271. package/dist/daemon/agent-registry.d.ts.map +1 -1
  272. package/dist/daemon/agent-registry.js +45 -2
  273. package/dist/daemon/agent-registry.js.map +1 -1
  274. package/dist/daemon/api.d.ts +81 -0
  275. package/dist/daemon/api.d.ts.map +1 -0
  276. package/dist/daemon/api.js +554 -0
  277. package/dist/daemon/api.js.map +1 -0
  278. package/dist/daemon/cli-auth.d.ts +67 -0
  279. package/dist/daemon/cli-auth.d.ts.map +1 -0
  280. package/dist/daemon/cli-auth.js +537 -0
  281. package/dist/daemon/cli-auth.js.map +1 -0
  282. package/dist/daemon/cloud-sync.d.ts +101 -0
  283. package/dist/daemon/cloud-sync.d.ts.map +1 -0
  284. package/dist/daemon/cloud-sync.js +263 -0
  285. package/dist/daemon/cloud-sync.js.map +1 -0
  286. package/dist/daemon/index.d.ts +4 -0
  287. package/dist/daemon/index.d.ts.map +1 -1
  288. package/dist/daemon/index.js +6 -0
  289. package/dist/daemon/index.js.map +1 -1
  290. package/dist/daemon/orchestrator.d.ts +155 -0
  291. package/dist/daemon/orchestrator.d.ts.map +1 -0
  292. package/dist/daemon/orchestrator.js +766 -0
  293. package/dist/daemon/orchestrator.js.map +1 -0
  294. package/dist/daemon/router.d.ts +29 -0
  295. package/dist/daemon/router.d.ts.map +1 -1
  296. package/dist/daemon/router.js +143 -21
  297. package/dist/daemon/router.js.map +1 -1
  298. package/dist/daemon/server.d.ts +42 -0
  299. package/dist/daemon/server.d.ts.map +1 -1
  300. package/dist/daemon/server.js +199 -16
  301. package/dist/daemon/server.js.map +1 -1
  302. package/dist/daemon/services/browser-testing.d.ts +88 -0
  303. package/dist/daemon/services/browser-testing.d.ts.map +1 -0
  304. package/dist/daemon/services/browser-testing.js +244 -0
  305. package/dist/daemon/services/browser-testing.js.map +1 -0
  306. package/dist/daemon/services/container-spawner.d.ts +135 -0
  307. package/dist/daemon/services/container-spawner.d.ts.map +1 -0
  308. package/dist/daemon/services/container-spawner.js +313 -0
  309. package/dist/daemon/services/container-spawner.js.map +1 -0
  310. package/dist/daemon/types.d.ts +131 -0
  311. package/dist/daemon/types.d.ts.map +1 -0
  312. package/dist/daemon/types.js +6 -0
  313. package/dist/daemon/types.js.map +1 -0
  314. package/dist/daemon/workspace-manager.d.ts +75 -0
  315. package/dist/daemon/workspace-manager.d.ts.map +1 -0
  316. package/dist/daemon/workspace-manager.js +289 -0
  317. package/dist/daemon/workspace-manager.js.map +1 -0
  318. package/dist/dashboard/out/404.html +1 -1
  319. package/dist/dashboard/out/_next/static/chunks/116-2502180def231162.js +1 -0
  320. package/dist/dashboard/out/_next/static/chunks/282-980c2eb8fff20123.js +1 -0
  321. package/dist/dashboard/out/_next/static/chunks/480-2d4111711d4e473c.js +1 -0
  322. package/dist/dashboard/out/_next/static/chunks/724-73c1ee5f60abe860.js +9 -0
  323. package/dist/dashboard/out/_next/static/chunks/766-c3a14283c88d815b.js +1 -0
  324. package/dist/dashboard/out/_next/static/chunks/app/app/page-7120be68bea622f3.js +1 -0
  325. package/dist/dashboard/out/_next/static/chunks/app/connect-repos/page-dc2e3a1a22478efc.js +1 -0
  326. package/dist/dashboard/out/_next/static/chunks/app/history/page-56a8b4616a90dc43.js +1 -0
  327. package/dist/dashboard/out/_next/static/chunks/app/layout-2433bb48965f4333.js +1 -0
  328. package/dist/dashboard/out/_next/static/chunks/app/login/page-3eac37ea6f5dd153.js +1 -0
  329. package/dist/dashboard/out/_next/static/chunks/app/metrics/page-1081dd190a331a91.js +1 -0
  330. package/dist/dashboard/out/_next/static/chunks/app/page-daf87e86f783f980.js +1 -0
  331. package/dist/dashboard/out/_next/static/chunks/app/pricing/page-4d72d5a5d8a9b618.js +1 -0
  332. package/dist/dashboard/out/_next/static/chunks/app/providers/page-b68a681526eb145e.js +1 -0
  333. package/dist/dashboard/out/_next/static/chunks/app/signup/page-fee4ed1709070bcd.js +1 -0
  334. package/dist/dashboard/out/_next/static/chunks/e868780c-48e5f147c90a3a41.js +18 -0
  335. package/dist/dashboard/out/_next/static/chunks/{main-e0a1f53fe0617a63.js → main-97850e03d723ea8c.js} +1 -1
  336. package/dist/dashboard/out/_next/static/chunks/main-app-5d692157a8eb1fd9.js +1 -0
  337. package/dist/dashboard/out/_next/static/chunks/webpack-1cdd8ed57114d5e1.js +1 -0
  338. package/dist/dashboard/out/_next/static/css/29852f26181969a0.css +1 -0
  339. package/dist/dashboard/out/_next/static/css/411ce23ffeae9f76.css +1 -0
  340. package/dist/dashboard/out/alt-logos/agent-relay-logo-128.png +0 -0
  341. package/dist/dashboard/out/alt-logos/agent-relay-logo-256.png +0 -0
  342. package/dist/dashboard/out/alt-logos/agent-relay-logo-32.png +0 -0
  343. package/dist/dashboard/out/alt-logos/agent-relay-logo-512.png +0 -0
  344. package/dist/dashboard/out/alt-logos/agent-relay-logo-64.png +0 -0
  345. package/dist/dashboard/out/alt-logos/agent-relay-logo.svg +45 -0
  346. package/dist/dashboard/out/alt-logos/logo.svg +38 -0
  347. package/dist/dashboard/out/alt-logos/monogram-logo-128.png +0 -0
  348. package/dist/dashboard/out/alt-logos/monogram-logo-256.png +0 -0
  349. package/dist/dashboard/out/alt-logos/monogram-logo-32.png +0 -0
  350. package/dist/dashboard/out/alt-logos/monogram-logo-512.png +0 -0
  351. package/dist/dashboard/out/alt-logos/monogram-logo-64.png +0 -0
  352. package/dist/dashboard/out/alt-logos/monogram-logo.svg +38 -0
  353. package/dist/dashboard/out/app.html +1 -0
  354. package/dist/dashboard/out/app.txt +7 -0
  355. package/dist/dashboard/out/connect-repos.html +1 -0
  356. package/dist/dashboard/out/connect-repos.txt +7 -0
  357. package/dist/dashboard/out/history.html +1 -0
  358. package/dist/dashboard/out/history.txt +7 -0
  359. package/dist/dashboard/out/index.html +1 -1
  360. package/dist/dashboard/out/index.txt +2 -2
  361. package/dist/dashboard/out/login.html +6 -0
  362. package/dist/dashboard/out/login.txt +7 -0
  363. package/dist/dashboard/out/metrics.html +1 -515
  364. package/dist/dashboard/out/metrics.txt +2 -2
  365. package/dist/dashboard/out/pricing.html +13 -0
  366. package/dist/dashboard/out/pricing.txt +7 -0
  367. package/dist/dashboard/out/providers.html +1 -0
  368. package/dist/dashboard/out/providers.txt +7 -0
  369. package/dist/dashboard/out/signup.html +6 -0
  370. package/dist/dashboard/out/signup.txt +7 -0
  371. package/dist/dashboard-server/metrics.d.ts.map +1 -1
  372. package/dist/dashboard-server/metrics.js +3 -2
  373. package/dist/dashboard-server/metrics.js.map +1 -1
  374. package/dist/dashboard-server/server.d.ts.map +1 -1
  375. package/dist/dashboard-server/server.js +2653 -130
  376. package/dist/dashboard-server/server.js.map +1 -1
  377. package/dist/hooks/emitter.d.ts +40 -0
  378. package/dist/hooks/emitter.d.ts.map +1 -0
  379. package/dist/hooks/emitter.js +63 -0
  380. package/dist/hooks/emitter.js.map +1 -0
  381. package/dist/hooks/index.d.ts +3 -0
  382. package/dist/hooks/index.d.ts.map +1 -1
  383. package/dist/hooks/index.js +3 -0
  384. package/dist/hooks/index.js.map +1 -1
  385. package/dist/hooks/registry.d.ts +173 -0
  386. package/dist/hooks/registry.d.ts.map +1 -0
  387. package/dist/hooks/registry.js +476 -0
  388. package/dist/hooks/registry.js.map +1 -0
  389. package/dist/hooks/trajectory-hooks.d.ts +52 -0
  390. package/dist/hooks/trajectory-hooks.d.ts.map +1 -0
  391. package/dist/hooks/trajectory-hooks.js +183 -0
  392. package/dist/hooks/trajectory-hooks.js.map +1 -0
  393. package/dist/hooks/types.d.ts +141 -0
  394. package/dist/hooks/types.d.ts.map +1 -1
  395. package/dist/index.d.ts +2 -0
  396. package/dist/index.d.ts.map +1 -1
  397. package/dist/index.js +3 -0
  398. package/dist/index.js.map +1 -1
  399. package/dist/memory/adapters/index.d.ts +8 -0
  400. package/dist/memory/adapters/index.d.ts.map +1 -0
  401. package/dist/memory/adapters/index.js +8 -0
  402. package/dist/memory/adapters/index.js.map +1 -0
  403. package/dist/memory/adapters/inmemory.d.ts +59 -0
  404. package/dist/memory/adapters/inmemory.d.ts.map +1 -0
  405. package/dist/memory/adapters/inmemory.js +195 -0
  406. package/dist/memory/adapters/inmemory.js.map +1 -0
  407. package/dist/memory/adapters/supermemory.d.ts +71 -0
  408. package/dist/memory/adapters/supermemory.d.ts.map +1 -0
  409. package/dist/memory/adapters/supermemory.js +338 -0
  410. package/dist/memory/adapters/supermemory.js.map +1 -0
  411. package/dist/memory/factory.d.ts +48 -0
  412. package/dist/memory/factory.d.ts.map +1 -0
  413. package/dist/memory/factory.js +143 -0
  414. package/dist/memory/factory.js.map +1 -0
  415. package/dist/memory/index.d.ts +32 -0
  416. package/dist/memory/index.d.ts.map +1 -0
  417. package/dist/memory/index.js +32 -0
  418. package/dist/memory/index.js.map +1 -0
  419. package/dist/memory/memory-hooks.d.ts +60 -0
  420. package/dist/memory/memory-hooks.d.ts.map +1 -0
  421. package/dist/memory/memory-hooks.js +313 -0
  422. package/dist/memory/memory-hooks.js.map +1 -0
  423. package/dist/memory/service.d.ts +49 -0
  424. package/dist/memory/service.d.ts.map +1 -0
  425. package/dist/memory/service.js +146 -0
  426. package/dist/memory/service.js.map +1 -0
  427. package/dist/memory/types.d.ts +195 -0
  428. package/dist/memory/types.d.ts.map +1 -0
  429. package/dist/memory/types.js +8 -0
  430. package/dist/memory/types.js.map +1 -0
  431. package/dist/policy/agent-policy.d.ts +225 -0
  432. package/dist/policy/agent-policy.d.ts.map +1 -0
  433. package/dist/policy/agent-policy.js +665 -0
  434. package/dist/policy/agent-policy.js.map +1 -0
  435. package/dist/policy/cloud-policy-fetcher.d.ts +12 -0
  436. package/dist/policy/cloud-policy-fetcher.d.ts.map +1 -0
  437. package/dist/policy/cloud-policy-fetcher.js +64 -0
  438. package/dist/policy/cloud-policy-fetcher.js.map +1 -0
  439. package/dist/protocol/types.d.ts +10 -1
  440. package/dist/protocol/types.d.ts.map +1 -1
  441. package/dist/resiliency/context-persistence.d.ts +140 -0
  442. package/dist/resiliency/context-persistence.d.ts.map +1 -0
  443. package/dist/resiliency/context-persistence.js +397 -0
  444. package/dist/resiliency/context-persistence.js.map +1 -0
  445. package/dist/resiliency/crash-insights.d.ts +156 -0
  446. package/dist/resiliency/crash-insights.d.ts.map +1 -0
  447. package/dist/resiliency/crash-insights.js +492 -0
  448. package/dist/resiliency/crash-insights.js.map +1 -0
  449. package/dist/resiliency/gossip-health.d.ts +137 -0
  450. package/dist/resiliency/gossip-health.d.ts.map +1 -0
  451. package/dist/resiliency/gossip-health.js +241 -0
  452. package/dist/resiliency/gossip-health.js.map +1 -0
  453. package/dist/resiliency/health-monitor.d.ts +97 -0
  454. package/dist/resiliency/health-monitor.d.ts.map +1 -0
  455. package/dist/resiliency/health-monitor.js +291 -0
  456. package/dist/resiliency/health-monitor.js.map +1 -0
  457. package/dist/resiliency/index.d.ts +68 -0
  458. package/dist/resiliency/index.d.ts.map +1 -0
  459. package/dist/resiliency/index.js +68 -0
  460. package/dist/resiliency/index.js.map +1 -0
  461. package/dist/resiliency/leader-watchdog.d.ts +109 -0
  462. package/dist/resiliency/leader-watchdog.d.ts.map +1 -0
  463. package/dist/resiliency/leader-watchdog.js +189 -0
  464. package/dist/resiliency/leader-watchdog.js.map +1 -0
  465. package/dist/resiliency/logger.d.ts +114 -0
  466. package/dist/resiliency/logger.d.ts.map +1 -0
  467. package/dist/resiliency/logger.js +250 -0
  468. package/dist/resiliency/logger.js.map +1 -0
  469. package/dist/resiliency/memory-monitor.d.ts +172 -0
  470. package/dist/resiliency/memory-monitor.d.ts.map +1 -0
  471. package/dist/resiliency/memory-monitor.js +593 -0
  472. package/dist/resiliency/memory-monitor.js.map +1 -0
  473. package/dist/resiliency/metrics.d.ts +115 -0
  474. package/dist/resiliency/metrics.d.ts.map +1 -0
  475. package/dist/resiliency/metrics.js +239 -0
  476. package/dist/resiliency/metrics.js.map +1 -0
  477. package/dist/resiliency/provider-context.d.ts +100 -0
  478. package/dist/resiliency/provider-context.d.ts.map +1 -0
  479. package/dist/resiliency/provider-context.js +360 -0
  480. package/dist/resiliency/provider-context.js.map +1 -0
  481. package/dist/resiliency/stateless-lead.d.ts +149 -0
  482. package/dist/resiliency/stateless-lead.d.ts.map +1 -0
  483. package/dist/resiliency/stateless-lead.js +308 -0
  484. package/dist/resiliency/stateless-lead.js.map +1 -0
  485. package/dist/resiliency/supervisor.d.ts +147 -0
  486. package/dist/resiliency/supervisor.d.ts.map +1 -0
  487. package/dist/resiliency/supervisor.js +459 -0
  488. package/dist/resiliency/supervisor.js.map +1 -0
  489. package/dist/shared/cli-auth-config.d.ts +91 -0
  490. package/dist/shared/cli-auth-config.d.ts.map +1 -0
  491. package/dist/shared/cli-auth-config.js +264 -0
  492. package/dist/shared/cli-auth-config.js.map +1 -0
  493. package/dist/storage/adapter.d.ts +3 -1
  494. package/dist/storage/adapter.d.ts.map +1 -1
  495. package/dist/storage/adapter.js +12 -2
  496. package/dist/storage/adapter.js.map +1 -1
  497. package/dist/storage/sqlite-adapter.d.ts.map +1 -1
  498. package/dist/storage/sqlite-adapter.js +18 -14
  499. package/dist/storage/sqlite-adapter.js.map +1 -1
  500. package/dist/trajectory/config.d.ts +84 -0
  501. package/dist/trajectory/config.d.ts.map +1 -0
  502. package/dist/trajectory/config.js +163 -0
  503. package/dist/trajectory/config.js.map +1 -0
  504. package/dist/trajectory/index.d.ts +8 -0
  505. package/dist/trajectory/index.d.ts.map +1 -0
  506. package/dist/trajectory/index.js +8 -0
  507. package/dist/trajectory/index.js.map +1 -0
  508. package/dist/trajectory/integration.d.ts +292 -0
  509. package/dist/trajectory/integration.d.ts.map +1 -0
  510. package/dist/trajectory/integration.js +834 -0
  511. package/dist/trajectory/integration.js.map +1 -0
  512. package/dist/utils/index.d.ts +1 -0
  513. package/dist/utils/index.d.ts.map +1 -1
  514. package/dist/utils/index.js +1 -0
  515. package/dist/utils/index.js.map +1 -1
  516. package/dist/utils/logger.d.ts +40 -0
  517. package/dist/utils/logger.d.ts.map +1 -0
  518. package/dist/utils/logger.js +84 -0
  519. package/dist/utils/logger.js.map +1 -0
  520. package/dist/utils/project-namespace.d.ts +24 -0
  521. package/dist/utils/project-namespace.d.ts.map +1 -1
  522. package/dist/utils/project-namespace.js +84 -0
  523. package/dist/utils/project-namespace.js.map +1 -1
  524. package/dist/wrapper/client.d.ts +16 -1
  525. package/dist/wrapper/client.d.ts.map +1 -1
  526. package/dist/wrapper/client.js +32 -1
  527. package/dist/wrapper/client.js.map +1 -1
  528. package/dist/wrapper/parser.d.ts +13 -0
  529. package/dist/wrapper/parser.d.ts.map +1 -1
  530. package/dist/wrapper/parser.js +217 -47
  531. package/dist/wrapper/parser.js.map +1 -1
  532. package/dist/wrapper/pty-wrapper.d.ts +219 -17
  533. package/dist/wrapper/pty-wrapper.d.ts.map +1 -1
  534. package/dist/wrapper/pty-wrapper.js +1050 -104
  535. package/dist/wrapper/pty-wrapper.js.map +1 -1
  536. package/dist/wrapper/shared.d.ts +165 -0
  537. package/dist/wrapper/shared.d.ts.map +1 -0
  538. package/dist/wrapper/shared.js +270 -0
  539. package/dist/wrapper/shared.js.map +1 -0
  540. package/dist/wrapper/tmux-wrapper.d.ts +78 -11
  541. package/dist/wrapper/tmux-wrapper.d.ts.map +1 -1
  542. package/dist/wrapper/tmux-wrapper.js +567 -106
  543. package/dist/wrapper/tmux-wrapper.js.map +1 -1
  544. package/docs/CLOUD-ARCHITECTURE.md +804 -0
  545. package/docs/CLOUD-ONBOARDING-DESIGN.md +1983 -0
  546. package/docs/HOOKS_API.md +394 -0
  547. package/docs/WRAPPER_EVENTS.md +358 -0
  548. package/docs/agent-policy-snippet.md +40 -0
  549. package/docs/agent-relay-protocol.md +238 -0
  550. package/docs/agent-relay-snippet.md +115 -6
  551. package/docs/archive/EXECUTIVE_SUMMARY.md +358 -0
  552. package/docs/archive/ROADMAP.md +329 -0
  553. package/docs/archive/TESTING_PRESENCE_FEATURES.md +327 -0
  554. package/docs/competitive/GASTOWN.md +451 -0
  555. package/docs/{COMPETITIVE_ANALYSIS.md → competitive/OVERVIEW.md} +1 -0
  556. package/docs/competitive/README.md +34 -0
  557. package/docs/competitive/TMUX_ORCHESTRATOR.md +605 -0
  558. package/docs/dashboard.png +0 -0
  559. package/docs/design/ci-failure-webhooks.md +812 -0
  560. package/docs/design/comprehensive-integrations.md +238 -0
  561. package/docs/design/e2b-sandbox-integration.md +504 -0
  562. package/docs/design/github-app-permissions.md +264 -0
  563. package/docs/guides/CLOUD.md +236 -0
  564. package/docs/guides/LOCAL.md +535 -0
  565. package/docs/guides/SELF-HOSTED.md +494 -0
  566. package/docs/local-testing.md +428 -0
  567. package/docs/proposals/continuous-claude-integration.md +622 -0
  568. package/docs/proposals/custom-commands.md +368 -0
  569. package/docs/proposals/shadow-as-subagent.md +765 -0
  570. package/docs/proposals/slack-bot-integration.md +1457 -0
  571. package/docs/tasks/global-skills-system.tasks.md +230 -0
  572. package/docs/tasks/webhook-integrations.tasks.md +184 -0
  573. package/docs/tasks/workspace-capabilities.tasks.md +121 -0
  574. package/docs/testing/RESILIENCY-TEST-PLAN-2026-01-01.md +366 -0
  575. package/package.json +45 -7
  576. package/scripts/cloud-setup.sh +96 -0
  577. package/scripts/manual-qa.sh +293 -0
  578. package/scripts/postinstall.js +60 -0
  579. package/scripts/run-cloud-qa.sh +220 -0
  580. package/scripts/test-cli-auth/Dockerfile +44 -0
  581. package/scripts/test-cli-auth/Dockerfile.real +79 -0
  582. package/scripts/test-cli-auth/README.md +286 -0
  583. package/scripts/test-cli-auth/ci-test-real-clis.ts +251 -0
  584. package/scripts/test-cli-auth/ci-test-runner.ts +263 -0
  585. package/scripts/test-cli-auth/mock-cli.sh +147 -0
  586. package/scripts/test-cli-auth/package.json +14 -0
  587. package/scripts/test-cli-auth/test-oauth-flow.ts +220 -0
  588. package/scripts/test-pty-input-auto.js +222 -0
  589. package/scripts/test-pty-input.js +150 -0
  590. package/dist/dashboard/out/_next/static/chunks/app/layout-c9d8c5d95e48c6bf.js +0 -1
  591. package/dist/dashboard/out/_next/static/chunks/app/metrics/page-8aa9936bc6c771ab.js +0 -1
  592. package/dist/dashboard/out/_next/static/chunks/app/page-4498be09a5157759.js +0 -1
  593. package/dist/dashboard/out/_next/static/chunks/main-app-bae2e535de00de50.js +0 -1
  594. package/dist/dashboard/out/_next/static/chunks/webpack-c81f7fd28659d64f.js +0 -1
  595. package/dist/dashboard/out/_next/static/css/50ed6996e3df7bdd.css +0 -1
  596. /package/dist/dashboard/out/_next/static/{DXFA-jj8wb3PcY5DX2xcU → H5aWG0udPB4iOUIl_gytz}/_buildManifest.js +0 -0
  597. /package/dist/dashboard/out/_next/static/{DXFA-jj8wb3PcY5DX2xcU → H5aWG0udPB4iOUIl_gytz}/_ssgManifest.js +0 -0
  598. /package/dist/dashboard/out/_next/static/chunks/{117-3bef7b19f3e60751.js → 117-b100311aff8d5c61.js} +0 -0
  599. /package/dist/dashboard/out/_next/static/chunks/{648-6cf686106c891ad3.js → 648-a13d3c2b1be45466.js} +0 -0
  600. /package/dist/dashboard/out/_next/static/chunks/app/_not-found/{page-8ff6572bc7c9bc61.js → page-a4973f3e3c82fb67.js} +0 -0
  601. /package/dist/dashboard/out/_next/static/chunks/{fd9d1056-26bd8d656b496dba.js → fd9d1056-bf46c09eb57e019c.js} +0 -0
  602. /package/docs/{CHANGELOG.md → archive/CHANGELOG.md} +0 -0
  603. /package/docs/{CLI-SIMPLIFICATION-COMPLETE.md → archive/CLI-SIMPLIFICATION-COMPLETE.md} +0 -0
  604. /package/docs/{DESIGN_BRIDGE_STAFFING.md → archive/DESIGN_BRIDGE_STAFFING.md} +0 -0
  605. /package/docs/{DESIGN_V2.md → archive/DESIGN_V2.md} +0 -0
  606. /package/docs/{MONETIZATION.md → archive/MONETIZATION.md} +0 -0
  607. /package/docs/{PROPOSAL-trajectories.md → archive/PROPOSAL-trajectories.md} +0 -0
  608. /package/docs/{SCALING_ANALYSIS.md → archive/SCALING_ANALYSIS.md} +0 -0
  609. /package/docs/{TMUX_IMPLEMENTATION_NOTES.md → archive/TMUX_IMPLEMENTATION_NOTES.md} +0 -0
  610. /package/docs/{TMUX_IMPROVEMENTS.md → archive/TMUX_IMPROVEMENTS.md} +0 -0
  611. /package/docs/{dashboard-v2-plan.md → archive/dashboard-v2-plan.md} +0 -0
  612. /package/docs/{removable-code-analysis.md → archive/removable-code-analysis.md} +0 -0
  613. /package/docs/{competitive-analysis-mcp-agent-mail.md → competitive/MCP_AGENT_MAIL.md} +0 -0
@@ -0,0 +1,977 @@
1
+ /**
2
+ * Agent Relay Cloud - Workspace Provisioner
3
+ *
4
+ * One-click provisioning for compute resources (Fly.io, Railway, Docker).
5
+ */
6
+ import * as crypto from 'crypto';
7
+ import { getConfig } from '../config.js';
8
+ import { db } from '../db/index.js';
9
+ import { vault } from '../vault/index.js';
10
+ import { nangoService } from '../services/nango.js';
11
+ const WORKSPACE_PORT = 3888;
12
+ const FETCH_TIMEOUT_MS = 10_000;
13
+ const WORKSPACE_IMAGE = process.env.WORKSPACE_IMAGE || 'ghcr.io/agentworkforce/relay-workspace:latest';
14
+ /**
15
+ * Get a fresh GitHub App installation token from Nango.
16
+ * Looks up the user's connected repositories to find a valid Nango connection.
17
+ */
18
+ async function getGithubAppTokenForUser(userId) {
19
+ try {
20
+ // Find any repository with a Nango connection for this user
21
+ const repos = await db.repositories.findByUserId(userId);
22
+ const repoWithConnection = repos.find(r => r.nangoConnectionId);
23
+ if (!repoWithConnection?.nangoConnectionId) {
24
+ console.warn(`[provisioner] No Nango GitHub App connection found for user ${userId}`);
25
+ return null;
26
+ }
27
+ // Get fresh installation token from Nango (handles refresh automatically)
28
+ const token = await nangoService.getGithubAppToken(repoWithConnection.nangoConnectionId);
29
+ return token;
30
+ }
31
+ catch (error) {
32
+ console.error(`[provisioner] Failed to get GitHub App token for user ${userId}:`, error);
33
+ return null;
34
+ }
35
+ }
36
+ async function loadCredentialToken(userId, provider) {
37
+ try {
38
+ const cred = await vault.getCredential(userId, provider);
39
+ if (cred?.accessToken) {
40
+ return cred.accessToken;
41
+ }
42
+ }
43
+ catch (error) {
44
+ console.warn(`Failed to decrypt ${provider} credential from vault; trying raw storage fallback`, error);
45
+ const raw = await db.credentials.findByUserAndProvider(userId, provider);
46
+ return raw?.accessToken ?? null;
47
+ }
48
+ return null;
49
+ }
50
+ async function wait(ms) {
51
+ return new Promise((resolve) => setTimeout(resolve, ms));
52
+ }
53
+ async function fetchWithRetry(url, options = {}) {
54
+ const retries = options.retries ?? 2;
55
+ let attempt = 0;
56
+ while (attempt <= retries) {
57
+ const controller = new AbortController();
58
+ const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
59
+ try {
60
+ const response = await fetch(url, { ...options, signal: controller.signal });
61
+ clearTimeout(timer);
62
+ if (!response.ok && response.status >= 500 && attempt < retries) {
63
+ attempt += 1;
64
+ await wait(500 * attempt);
65
+ continue;
66
+ }
67
+ return response;
68
+ }
69
+ catch (error) {
70
+ clearTimeout(timer);
71
+ if (attempt >= retries) {
72
+ throw error;
73
+ }
74
+ attempt += 1;
75
+ await wait(500 * attempt);
76
+ }
77
+ }
78
+ throw new Error('fetchWithRetry exhausted retries');
79
+ }
80
+ async function softHealthCheck(url) {
81
+ try {
82
+ const res = await fetchWithRetry(`${url.replace(/\/$/, '')}/health`, { method: 'GET', retries: 1 });
83
+ if (!res.ok) {
84
+ console.warn(`[health] Non-200 from ${url}/health: ${res.status}`);
85
+ }
86
+ }
87
+ catch (error) {
88
+ console.warn(`[health] Failed to reach ${url}/health`, error);
89
+ }
90
+ }
91
+ export const RESOURCE_TIERS = {
92
+ small: { name: 'small', cpuCores: 1, memoryMb: 512, maxAgents: 5 },
93
+ medium: { name: 'medium', cpuCores: 2, memoryMb: 1024, maxAgents: 10 },
94
+ large: { name: 'large', cpuCores: 4, memoryMb: 2048, maxAgents: 20 },
95
+ xlarge: { name: 'xlarge', cpuCores: 8, memoryMb: 4096, maxAgents: 50 },
96
+ };
97
+ /**
98
+ * Fly.io provisioner
99
+ */
100
+ class FlyProvisioner {
101
+ apiToken;
102
+ org;
103
+ region;
104
+ workspaceDomain;
105
+ cloudApiUrl;
106
+ sessionSecret;
107
+ registryAuth;
108
+ constructor() {
109
+ const config = getConfig();
110
+ if (!config.compute.fly) {
111
+ throw new Error('Fly.io configuration missing');
112
+ }
113
+ this.apiToken = config.compute.fly.apiToken;
114
+ this.org = config.compute.fly.org;
115
+ this.region = config.compute.fly.region || 'sjc';
116
+ this.workspaceDomain = config.compute.fly.workspaceDomain;
117
+ this.registryAuth = config.compute.fly.registryAuth;
118
+ this.cloudApiUrl = config.publicUrl;
119
+ this.sessionSecret = config.sessionSecret;
120
+ }
121
+ /**
122
+ * Generate a workspace token for API authentication
123
+ * This is a simple HMAC - in production, consider using JWTs
124
+ */
125
+ generateWorkspaceToken(workspaceId) {
126
+ return crypto
127
+ .createHmac('sha256', this.sessionSecret)
128
+ .update(`workspace:${workspaceId}`)
129
+ .digest('hex');
130
+ }
131
+ async provision(workspace, credentials) {
132
+ const appName = `ar-${workspace.id.substring(0, 8)}`;
133
+ // Create Fly app
134
+ await fetchWithRetry('https://api.machines.dev/v1/apps', {
135
+ method: 'POST',
136
+ headers: {
137
+ Authorization: `Bearer ${this.apiToken}`,
138
+ 'Content-Type': 'application/json',
139
+ },
140
+ body: JSON.stringify({
141
+ app_name: appName,
142
+ org_slug: this.org,
143
+ }),
144
+ });
145
+ // Set secrets (provider credentials)
146
+ const secrets = {};
147
+ for (const [provider, token] of credentials) {
148
+ secrets[`${provider.toUpperCase()}_TOKEN`] = token;
149
+ }
150
+ if (Object.keys(secrets).length > 0) {
151
+ await fetchWithRetry(`https://api.machines.dev/v1/apps/${appName}/secrets`, {
152
+ method: 'POST',
153
+ headers: {
154
+ Authorization: `Bearer ${this.apiToken}`,
155
+ 'Content-Type': 'application/json',
156
+ },
157
+ body: JSON.stringify(secrets),
158
+ });
159
+ }
160
+ // If custom workspace domain is configured, add certificate
161
+ const customHostname = this.workspaceDomain
162
+ ? `${appName}.${this.workspaceDomain}`
163
+ : null;
164
+ if (customHostname) {
165
+ await this.allocateCertificate(appName, customHostname);
166
+ }
167
+ // Create machine with auto-stop/start for cost optimization
168
+ const machineResponse = await fetchWithRetry(`https://api.machines.dev/v1/apps/${appName}/machines`, {
169
+ method: 'POST',
170
+ headers: {
171
+ Authorization: `Bearer ${this.apiToken}`,
172
+ 'Content-Type': 'application/json',
173
+ },
174
+ body: JSON.stringify({
175
+ region: this.region,
176
+ config: {
177
+ image: WORKSPACE_IMAGE,
178
+ // Registry auth for private ghcr.io images
179
+ ...(this.registryAuth && {
180
+ image_registry_auth: {
181
+ registry: 'ghcr.io',
182
+ username: this.registryAuth.username,
183
+ password: this.registryAuth.password,
184
+ },
185
+ }),
186
+ env: {
187
+ WORKSPACE_ID: workspace.id,
188
+ SUPERVISOR_ENABLED: String(workspace.config.supervisorEnabled ?? false),
189
+ MAX_AGENTS: String(workspace.config.maxAgents ?? 10),
190
+ REPOSITORIES: (workspace.config.repositories ?? []).join(','),
191
+ PROVIDERS: (workspace.config.providers ?? []).join(','),
192
+ PORT: String(WORKSPACE_PORT),
193
+ AGENT_RELAY_DASHBOARD_PORT: String(WORKSPACE_PORT),
194
+ // Git gateway configuration
195
+ CLOUD_API_URL: this.cloudApiUrl,
196
+ WORKSPACE_TOKEN: this.generateWorkspaceToken(workspace.id),
197
+ },
198
+ services: [
199
+ {
200
+ ports: [
201
+ { port: 443, handlers: ['tls', 'http'] },
202
+ { port: 80, handlers: ['http'] },
203
+ ],
204
+ protocol: 'tcp',
205
+ internal_port: WORKSPACE_PORT,
206
+ // Auto-stop after 5 minutes of inactivity
207
+ auto_stop_machines: true,
208
+ auto_start_machines: true,
209
+ min_machines_running: 0,
210
+ },
211
+ ],
212
+ guest: {
213
+ cpu_kind: 'shared',
214
+ cpus: 1,
215
+ memory_mb: 512,
216
+ },
217
+ },
218
+ }),
219
+ });
220
+ if (!machineResponse.ok) {
221
+ const error = await machineResponse.text();
222
+ throw new Error(`Failed to create Fly machine: ${error}`);
223
+ }
224
+ const machine = (await machineResponse.json());
225
+ // Return custom domain URL if configured, otherwise default fly.dev
226
+ const publicUrl = customHostname
227
+ ? `https://${customHostname}`
228
+ : `https://${appName}.fly.dev`;
229
+ await softHealthCheck(publicUrl);
230
+ return {
231
+ computeId: machine.id,
232
+ publicUrl,
233
+ };
234
+ }
235
+ /**
236
+ * Allocate SSL certificate for custom domain
237
+ */
238
+ async allocateCertificate(appName, hostname) {
239
+ const response = await fetchWithRetry(`https://api.machines.dev/v1/apps/${appName}/certificates`, {
240
+ method: 'POST',
241
+ headers: {
242
+ Authorization: `Bearer ${this.apiToken}`,
243
+ 'Content-Type': 'application/json',
244
+ },
245
+ body: JSON.stringify({ hostname }),
246
+ });
247
+ if (!response.ok) {
248
+ const error = await response.text();
249
+ // Don't fail if cert already exists
250
+ if (!error.includes('already exists')) {
251
+ throw new Error(`Failed to allocate certificate for ${hostname}: ${error}`);
252
+ }
253
+ }
254
+ }
255
+ async deprovision(workspace) {
256
+ const appName = `ar-${workspace.id.substring(0, 8)}`;
257
+ await fetchWithRetry(`https://api.machines.dev/v1/apps/${appName}`, {
258
+ method: 'DELETE',
259
+ headers: {
260
+ Authorization: `Bearer ${this.apiToken}`,
261
+ },
262
+ });
263
+ }
264
+ async getStatus(workspace) {
265
+ if (!workspace.computeId)
266
+ return 'error';
267
+ const appName = `ar-${workspace.id.substring(0, 8)}`;
268
+ const response = await fetchWithRetry(`https://api.machines.dev/v1/apps/${appName}/machines/${workspace.computeId}`, {
269
+ headers: {
270
+ Authorization: `Bearer ${this.apiToken}`,
271
+ },
272
+ });
273
+ if (!response.ok)
274
+ return 'error';
275
+ const machine = await response.json();
276
+ switch (machine.state) {
277
+ case 'started':
278
+ return 'running';
279
+ case 'stopped':
280
+ return 'stopped';
281
+ case 'created':
282
+ case 'starting':
283
+ return 'provisioning';
284
+ default:
285
+ return 'error';
286
+ }
287
+ }
288
+ async restart(workspace) {
289
+ if (!workspace.computeId)
290
+ return;
291
+ const appName = `ar-${workspace.id.substring(0, 8)}`;
292
+ await fetchWithRetry(`https://api.machines.dev/v1/apps/${appName}/machines/${workspace.computeId}/restart`, {
293
+ method: 'POST',
294
+ headers: {
295
+ Authorization: `Bearer ${this.apiToken}`,
296
+ },
297
+ });
298
+ }
299
+ /**
300
+ * Resize workspace - vertical scaling via Fly Machines API
301
+ */
302
+ async resize(workspace, tier) {
303
+ if (!workspace.computeId)
304
+ return;
305
+ const appName = `ar-${workspace.id.substring(0, 8)}`;
306
+ // Update machine configuration
307
+ await fetchWithRetry(`https://api.machines.dev/v1/apps/${appName}/machines/${workspace.computeId}`, {
308
+ method: 'POST',
309
+ headers: {
310
+ Authorization: `Bearer ${this.apiToken}`,
311
+ 'Content-Type': 'application/json',
312
+ },
313
+ body: JSON.stringify({
314
+ config: {
315
+ guest: {
316
+ cpu_kind: tier.cpuCores <= 2 ? 'shared' : 'performance',
317
+ cpus: tier.cpuCores,
318
+ memory_mb: tier.memoryMb,
319
+ },
320
+ env: {
321
+ MAX_AGENTS: String(tier.maxAgents),
322
+ },
323
+ },
324
+ }),
325
+ });
326
+ console.log(`[fly] Resized workspace ${workspace.id} to ${tier.name} (${tier.cpuCores} CPU, ${tier.memoryMb}MB RAM)`);
327
+ }
328
+ /**
329
+ * Update the max agent limit for a workspace
330
+ */
331
+ async updateAgentLimit(workspace, newLimit) {
332
+ if (!workspace.computeId)
333
+ return;
334
+ const appName = `ar-${workspace.id.substring(0, 8)}`;
335
+ // Update environment variable
336
+ await fetchWithRetry(`https://api.machines.dev/v1/apps/${appName}/machines/${workspace.computeId}`, {
337
+ method: 'POST',
338
+ headers: {
339
+ Authorization: `Bearer ${this.apiToken}`,
340
+ 'Content-Type': 'application/json',
341
+ },
342
+ body: JSON.stringify({
343
+ config: {
344
+ env: {
345
+ MAX_AGENTS: String(newLimit),
346
+ },
347
+ },
348
+ }),
349
+ });
350
+ console.log(`[fly] Updated workspace ${workspace.id} agent limit to ${newLimit}`);
351
+ }
352
+ /**
353
+ * Get current resource tier for a workspace
354
+ */
355
+ async getCurrentTier(workspace) {
356
+ if (!workspace.computeId) {
357
+ return RESOURCE_TIERS.small;
358
+ }
359
+ const appName = `ar-${workspace.id.substring(0, 8)}`;
360
+ const response = await fetchWithRetry(`https://api.machines.dev/v1/apps/${appName}/machines/${workspace.computeId}`, {
361
+ headers: {
362
+ Authorization: `Bearer ${this.apiToken}`,
363
+ },
364
+ });
365
+ if (!response.ok) {
366
+ return RESOURCE_TIERS.small;
367
+ }
368
+ const machine = await response.json();
369
+ const _cpus = machine.config?.guest?.cpus || 1;
370
+ const memoryMb = machine.config?.guest?.memory_mb || 512;
371
+ // Map to nearest tier
372
+ if (memoryMb >= 4096)
373
+ return RESOURCE_TIERS.xlarge;
374
+ if (memoryMb >= 2048)
375
+ return RESOURCE_TIERS.large;
376
+ if (memoryMb >= 1024)
377
+ return RESOURCE_TIERS.medium;
378
+ return RESOURCE_TIERS.small;
379
+ }
380
+ }
381
+ /**
382
+ * Railway provisioner
383
+ */
384
+ class RailwayProvisioner {
385
+ apiToken;
386
+ cloudApiUrl;
387
+ sessionSecret;
388
+ constructor() {
389
+ const config = getConfig();
390
+ if (!config.compute.railway) {
391
+ throw new Error('Railway configuration missing');
392
+ }
393
+ this.apiToken = config.compute.railway.apiToken;
394
+ this.cloudApiUrl = config.publicUrl;
395
+ this.sessionSecret = config.sessionSecret;
396
+ }
397
+ generateWorkspaceToken(workspaceId) {
398
+ return crypto
399
+ .createHmac('sha256', this.sessionSecret)
400
+ .update(`workspace:${workspaceId}`)
401
+ .digest('hex');
402
+ }
403
+ async provision(workspace, credentials) {
404
+ // Create project
405
+ const projectResponse = await fetchWithRetry('https://backboard.railway.app/graphql/v2', {
406
+ method: 'POST',
407
+ headers: {
408
+ Authorization: `Bearer ${this.apiToken}`,
409
+ 'Content-Type': 'application/json',
410
+ },
411
+ body: JSON.stringify({
412
+ query: `
413
+ mutation CreateProject($input: ProjectCreateInput!) {
414
+ projectCreate(input: $input) {
415
+ id
416
+ name
417
+ }
418
+ }
419
+ `,
420
+ variables: {
421
+ input: {
422
+ name: `agent-relay-${workspace.id.substring(0, 8)}`,
423
+ },
424
+ },
425
+ }),
426
+ });
427
+ const projectData = await projectResponse.json();
428
+ const projectId = projectData.data.projectCreate.id;
429
+ // Deploy service
430
+ const serviceResponse = await fetchWithRetry('https://backboard.railway.app/graphql/v2', {
431
+ method: 'POST',
432
+ headers: {
433
+ Authorization: `Bearer ${this.apiToken}`,
434
+ 'Content-Type': 'application/json',
435
+ },
436
+ body: JSON.stringify({
437
+ query: `
438
+ mutation CreateService($input: ServiceCreateInput!) {
439
+ serviceCreate(input: $input) {
440
+ id
441
+ }
442
+ }
443
+ `,
444
+ variables: {
445
+ input: {
446
+ projectId,
447
+ name: 'workspace',
448
+ source: {
449
+ image: WORKSPACE_IMAGE,
450
+ },
451
+ },
452
+ },
453
+ }),
454
+ });
455
+ const serviceData = await serviceResponse.json();
456
+ const serviceId = serviceData.data.serviceCreate.id;
457
+ // Set environment variables
458
+ const envVars = {
459
+ WORKSPACE_ID: workspace.id,
460
+ SUPERVISOR_ENABLED: String(workspace.config.supervisorEnabled ?? false),
461
+ MAX_AGENTS: String(workspace.config.maxAgents ?? 10),
462
+ REPOSITORIES: (workspace.config.repositories ?? []).join(','),
463
+ PROVIDERS: (workspace.config.providers ?? []).join(','),
464
+ PORT: String(WORKSPACE_PORT),
465
+ AGENT_RELAY_DASHBOARD_PORT: String(WORKSPACE_PORT),
466
+ CLOUD_API_URL: this.cloudApiUrl,
467
+ WORKSPACE_TOKEN: this.generateWorkspaceToken(workspace.id),
468
+ };
469
+ for (const [provider, token] of credentials) {
470
+ envVars[`${provider.toUpperCase()}_TOKEN`] = token;
471
+ }
472
+ await fetchWithRetry('https://backboard.railway.app/graphql/v2', {
473
+ method: 'POST',
474
+ headers: {
475
+ Authorization: `Bearer ${this.apiToken}`,
476
+ 'Content-Type': 'application/json',
477
+ },
478
+ body: JSON.stringify({
479
+ query: `
480
+ mutation SetVariables($input: VariableCollectionUpsertInput!) {
481
+ variableCollectionUpsert(input: $input)
482
+ }
483
+ `,
484
+ variables: {
485
+ input: {
486
+ projectId,
487
+ serviceId,
488
+ variables: envVars,
489
+ },
490
+ },
491
+ }),
492
+ });
493
+ // Generate domain
494
+ const domainResponse = await fetchWithRetry('https://backboard.railway.app/graphql/v2', {
495
+ method: 'POST',
496
+ headers: {
497
+ Authorization: `Bearer ${this.apiToken}`,
498
+ 'Content-Type': 'application/json',
499
+ },
500
+ body: JSON.stringify({
501
+ query: `
502
+ mutation CreateDomain($input: ServiceDomainCreateInput!) {
503
+ serviceDomainCreate(input: $input) {
504
+ domain
505
+ }
506
+ }
507
+ `,
508
+ variables: {
509
+ input: {
510
+ serviceId,
511
+ },
512
+ },
513
+ }),
514
+ });
515
+ const domainData = await domainResponse.json();
516
+ const domain = domainData.data.serviceDomainCreate.domain;
517
+ await softHealthCheck(`https://${domain}`);
518
+ return {
519
+ computeId: projectId,
520
+ publicUrl: `https://${domain}`,
521
+ };
522
+ }
523
+ async deprovision(workspace) {
524
+ if (!workspace.computeId)
525
+ return;
526
+ await fetchWithRetry('https://backboard.railway.app/graphql/v2', {
527
+ method: 'POST',
528
+ headers: {
529
+ Authorization: `Bearer ${this.apiToken}`,
530
+ 'Content-Type': 'application/json',
531
+ },
532
+ body: JSON.stringify({
533
+ query: `
534
+ mutation DeleteProject($id: String!) {
535
+ projectDelete(id: $id)
536
+ }
537
+ `,
538
+ variables: {
539
+ id: workspace.computeId,
540
+ },
541
+ }),
542
+ });
543
+ }
544
+ async getStatus(workspace) {
545
+ if (!workspace.computeId)
546
+ return 'error';
547
+ const response = await fetchWithRetry('https://backboard.railway.app/graphql/v2', {
548
+ method: 'POST',
549
+ headers: {
550
+ Authorization: `Bearer ${this.apiToken}`,
551
+ 'Content-Type': 'application/json',
552
+ },
553
+ body: JSON.stringify({
554
+ query: `
555
+ query GetProject($id: String!) {
556
+ project(id: $id) {
557
+ deployments {
558
+ edges {
559
+ node {
560
+ status
561
+ }
562
+ }
563
+ }
564
+ }
565
+ }
566
+ `,
567
+ variables: {
568
+ id: workspace.computeId,
569
+ },
570
+ }),
571
+ });
572
+ const data = await response.json();
573
+ const deployments = data.data?.project?.deployments?.edges;
574
+ if (!deployments || deployments.length === 0)
575
+ return 'provisioning';
576
+ const latestStatus = deployments[0].node.status;
577
+ switch (latestStatus) {
578
+ case 'SUCCESS':
579
+ return 'running';
580
+ case 'BUILDING':
581
+ case 'DEPLOYING':
582
+ return 'provisioning';
583
+ case 'CRASHED':
584
+ case 'FAILED':
585
+ return 'error';
586
+ default:
587
+ return 'stopped';
588
+ }
589
+ }
590
+ async restart(workspace) {
591
+ // Railway doesn't have a direct restart - redeploy instead
592
+ if (!workspace.computeId)
593
+ return;
594
+ await fetchWithRetry('https://backboard.railway.app/graphql/v2', {
595
+ method: 'POST',
596
+ headers: {
597
+ Authorization: `Bearer ${this.apiToken}`,
598
+ 'Content-Type': 'application/json',
599
+ },
600
+ body: JSON.stringify({
601
+ query: `
602
+ mutation RedeployService($input: DeploymentTriggerInput!) {
603
+ deploymentTrigger(input: $input)
604
+ }
605
+ `,
606
+ variables: {
607
+ input: {
608
+ projectId: workspace.computeId,
609
+ },
610
+ },
611
+ }),
612
+ });
613
+ }
614
+ }
615
+ /**
616
+ * Local Docker provisioner (for development/self-hosted)
617
+ */
618
+ class DockerProvisioner {
619
+ cloudApiUrl;
620
+ cloudApiUrlForContainer;
621
+ sessionSecret;
622
+ constructor() {
623
+ const config = getConfig();
624
+ this.cloudApiUrl = config.publicUrl;
625
+ this.sessionSecret = config.sessionSecret;
626
+ // For Docker containers, localhost won't work - they need to reach the host
627
+ // Convert localhost URLs to host.docker.internal for container access
628
+ if (this.cloudApiUrl.includes('localhost') || this.cloudApiUrl.includes('127.0.0.1')) {
629
+ this.cloudApiUrlForContainer = this.cloudApiUrl
630
+ .replace('localhost', 'host.docker.internal')
631
+ .replace('127.0.0.1', 'host.docker.internal');
632
+ console.log(`[docker] Container API URL: ${this.cloudApiUrlForContainer} (host: ${this.cloudApiUrl})`);
633
+ }
634
+ else {
635
+ this.cloudApiUrlForContainer = this.cloudApiUrl;
636
+ }
637
+ }
638
+ generateWorkspaceToken(workspaceId) {
639
+ return crypto
640
+ .createHmac('sha256', this.sessionSecret)
641
+ .update(`workspace:${workspaceId}`)
642
+ .digest('hex');
643
+ }
644
+ /**
645
+ * Wait for container to be healthy by polling the health endpoint
646
+ */
647
+ async waitForHealthy(publicUrl, timeoutMs = 60_000) {
648
+ const startTime = Date.now();
649
+ const pollInterval = 2000;
650
+ console.log(`[docker] Waiting for container to be healthy at ${publicUrl}...`);
651
+ while (Date.now() - startTime < timeoutMs) {
652
+ try {
653
+ const response = await fetch(`${publicUrl}/health`, {
654
+ method: 'GET',
655
+ signal: AbortSignal.timeout(5000),
656
+ });
657
+ if (response.ok) {
658
+ console.log(`[docker] Container healthy after ${Date.now() - startTime}ms`);
659
+ return;
660
+ }
661
+ }
662
+ catch {
663
+ // Container not ready yet, continue polling
664
+ }
665
+ await wait(pollInterval);
666
+ }
667
+ throw new Error(`Container did not become healthy within ${timeoutMs}ms`);
668
+ }
669
+ async provision(workspace, credentials) {
670
+ const containerName = `ar-${workspace.id.substring(0, 8)}`;
671
+ // Build environment variables
672
+ const envArgs = [
673
+ `-e WORKSPACE_ID=${workspace.id}`,
674
+ `-e SUPERVISOR_ENABLED=${workspace.config.supervisorEnabled ?? false}`,
675
+ `-e MAX_AGENTS=${workspace.config.maxAgents ?? 10}`,
676
+ `-e REPOSITORIES=${(workspace.config.repositories ?? []).join(',')}`,
677
+ `-e PROVIDERS=${(workspace.config.providers ?? []).join(',')}`,
678
+ `-e PORT=${WORKSPACE_PORT}`,
679
+ `-e AGENT_RELAY_DASHBOARD_PORT=${WORKSPACE_PORT}`,
680
+ `-e CLOUD_API_URL=${this.cloudApiUrlForContainer}`,
681
+ `-e WORKSPACE_TOKEN=${this.generateWorkspaceToken(workspace.id)}`,
682
+ ];
683
+ for (const [provider, token] of credentials) {
684
+ envArgs.push(`-e ${provider.toUpperCase()}_TOKEN=${token}`);
685
+ }
686
+ // Run container
687
+ const { execSync } = await import('child_process');
688
+ const hostPort = 3000 + Math.floor(Math.random() * 1000);
689
+ // When running in Docker, connect to the same network for container-to-container communication
690
+ const runningInDocker = process.env.RUNNING_IN_DOCKER === 'true';
691
+ const networkArg = runningInDocker ? '--network agent-relay-dev' : '';
692
+ // In development, mount local dist and docs folders for faster iteration
693
+ // Set WORKSPACE_DEV_MOUNT=true to enable
694
+ const devMount = process.env.WORKSPACE_DEV_MOUNT === 'true';
695
+ const volumeArgs = devMount
696
+ ? `-v "${process.cwd()}/dist:/app/dist:ro" -v "${process.cwd()}/docs:/app/docs:ro"`
697
+ : '';
698
+ if (devMount) {
699
+ console.log('[provisioner] Dev mode: mounting local dist/ and docs/ folders into workspace container');
700
+ }
701
+ try {
702
+ execSync(`docker run -d --user root --name ${containerName} ${networkArg} ${volumeArgs} -p ${hostPort}:${WORKSPACE_PORT} ${envArgs.join(' ')} ${WORKSPACE_IMAGE}`, { stdio: 'pipe' });
703
+ const publicUrl = `http://localhost:${hostPort}`;
704
+ // Wait for container to be healthy before returning
705
+ // When running in Docker, use the internal container name for health check
706
+ const healthCheckUrl = runningInDocker
707
+ ? `http://${containerName}:${WORKSPACE_PORT}`
708
+ : publicUrl;
709
+ await this.waitForHealthy(healthCheckUrl);
710
+ return {
711
+ computeId: containerName,
712
+ publicUrl,
713
+ };
714
+ }
715
+ catch (error) {
716
+ // Clean up container if it was created but health check failed
717
+ try {
718
+ const { execSync: execSyncCleanup } = await import('child_process');
719
+ execSyncCleanup(`docker rm -f ${containerName}`, { stdio: 'pipe' });
720
+ }
721
+ catch {
722
+ // Ignore cleanup errors
723
+ }
724
+ throw new Error(`Failed to start Docker container: ${error}`);
725
+ }
726
+ }
727
+ async deprovision(workspace) {
728
+ if (!workspace.computeId)
729
+ return;
730
+ const { execSync } = await import('child_process');
731
+ try {
732
+ execSync(`docker rm -f ${workspace.computeId}`, { stdio: 'pipe' });
733
+ }
734
+ catch {
735
+ // Container may already be removed
736
+ }
737
+ }
738
+ async getStatus(workspace) {
739
+ if (!workspace.computeId)
740
+ return 'error';
741
+ const { execSync } = await import('child_process');
742
+ try {
743
+ const result = execSync(`docker inspect -f '{{.State.Status}}' ${workspace.computeId}`, { stdio: 'pipe' }).toString().trim();
744
+ switch (result) {
745
+ case 'running':
746
+ return 'running';
747
+ case 'exited':
748
+ case 'dead':
749
+ return 'stopped';
750
+ case 'created':
751
+ case 'restarting':
752
+ return 'provisioning';
753
+ default:
754
+ return 'error';
755
+ }
756
+ }
757
+ catch {
758
+ return 'error';
759
+ }
760
+ }
761
+ async restart(workspace) {
762
+ if (!workspace.computeId)
763
+ return;
764
+ const { execSync } = await import('child_process');
765
+ try {
766
+ execSync(`docker restart ${workspace.computeId}`, { stdio: 'pipe' });
767
+ }
768
+ catch (error) {
769
+ throw new Error(`Failed to restart container: ${error}`);
770
+ }
771
+ }
772
+ }
773
+ /**
774
+ * Main Workspace Provisioner
775
+ */
776
+ export class WorkspaceProvisioner {
777
+ provisioner;
778
+ constructor() {
779
+ const config = getConfig();
780
+ switch (config.compute.provider) {
781
+ case 'fly':
782
+ this.provisioner = new FlyProvisioner();
783
+ break;
784
+ case 'railway':
785
+ this.provisioner = new RailwayProvisioner();
786
+ break;
787
+ case 'docker':
788
+ default:
789
+ this.provisioner = new DockerProvisioner();
790
+ }
791
+ }
792
+ /**
793
+ * Provision a new workspace (one-click)
794
+ */
795
+ async provision(config) {
796
+ // Create workspace record
797
+ const workspace = await db.workspaces.create({
798
+ userId: config.userId,
799
+ name: config.name,
800
+ computeProvider: getConfig().compute.provider,
801
+ config: {
802
+ providers: config.providers,
803
+ repositories: config.repositories,
804
+ supervisorEnabled: config.supervisorEnabled ?? true,
805
+ maxAgents: config.maxAgents ?? 10,
806
+ },
807
+ });
808
+ // Add creator as owner in workspace_members for team collaboration support
809
+ await db.workspaceMembers.addMember({
810
+ workspaceId: workspace.id,
811
+ userId: config.userId,
812
+ role: 'owner',
813
+ invitedBy: config.userId, // Self-invited as creator
814
+ });
815
+ // Auto-accept the creator's membership
816
+ await db.workspaceMembers.acceptInvite(workspace.id, config.userId);
817
+ // Get credentials
818
+ const credentials = new Map();
819
+ for (const provider of config.providers) {
820
+ const token = await loadCredentialToken(config.userId, provider);
821
+ if (token) {
822
+ credentials.set(provider, token);
823
+ }
824
+ }
825
+ // GitHub token is required for cloning repositories
826
+ // Use direct token if provided (for testing), otherwise get from Nango
827
+ if (config.repositories.length > 0) {
828
+ if (config.githubToken) {
829
+ // Direct token provided (for testing)
830
+ credentials.set('github', config.githubToken);
831
+ console.log('[provisioner] Using provided GitHub token');
832
+ }
833
+ else {
834
+ // Get fresh installation token from Nango GitHub App
835
+ const githubToken = await getGithubAppTokenForUser(config.userId);
836
+ if (githubToken) {
837
+ credentials.set('github', githubToken);
838
+ }
839
+ else {
840
+ console.warn(`[provisioner] No GitHub App token for user ${config.userId}; repository cloning may fail.`);
841
+ }
842
+ }
843
+ }
844
+ // Provision compute
845
+ try {
846
+ const { computeId, publicUrl } = await this.provisioner.provision(workspace, credentials);
847
+ await db.workspaces.updateStatus(workspace.id, 'running', {
848
+ computeId,
849
+ publicUrl,
850
+ });
851
+ return {
852
+ workspaceId: workspace.id,
853
+ status: 'running',
854
+ publicUrl,
855
+ };
856
+ }
857
+ catch (error) {
858
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
859
+ await db.workspaces.updateStatus(workspace.id, 'error', {
860
+ errorMessage,
861
+ });
862
+ return {
863
+ workspaceId: workspace.id,
864
+ status: 'error',
865
+ error: errorMessage,
866
+ };
867
+ }
868
+ }
869
+ /**
870
+ * Deprovision a workspace
871
+ */
872
+ async deprovision(workspaceId) {
873
+ const workspace = await db.workspaces.findById(workspaceId);
874
+ if (!workspace) {
875
+ throw new Error('Workspace not found');
876
+ }
877
+ await this.provisioner.deprovision(workspace);
878
+ await db.workspaces.delete(workspaceId);
879
+ }
880
+ /**
881
+ * Get workspace status
882
+ */
883
+ async getStatus(workspaceId) {
884
+ const workspace = await db.workspaces.findById(workspaceId);
885
+ if (!workspace) {
886
+ throw new Error('Workspace not found');
887
+ }
888
+ const status = await this.provisioner.getStatus(workspace);
889
+ // Update database if status changed
890
+ if (status !== workspace.status) {
891
+ await db.workspaces.updateStatus(workspaceId, status);
892
+ }
893
+ return status;
894
+ }
895
+ /**
896
+ * Restart a workspace
897
+ */
898
+ async restart(workspaceId) {
899
+ const workspace = await db.workspaces.findById(workspaceId);
900
+ if (!workspace) {
901
+ throw new Error('Workspace not found');
902
+ }
903
+ await this.provisioner.restart(workspace);
904
+ }
905
+ /**
906
+ * Stop a workspace
907
+ */
908
+ async stop(workspaceId) {
909
+ const workspace = await db.workspaces.findById(workspaceId);
910
+ if (!workspace) {
911
+ throw new Error('Workspace not found');
912
+ }
913
+ // For now, just deprovision to stop
914
+ await this.provisioner.deprovision(workspace);
915
+ await db.workspaces.updateStatus(workspaceId, 'stopped');
916
+ }
917
+ /**
918
+ * Resize a workspace (vertical scaling)
919
+ */
920
+ async resize(workspaceId, tier) {
921
+ const workspace = await db.workspaces.findById(workspaceId);
922
+ if (!workspace) {
923
+ throw new Error('Workspace not found');
924
+ }
925
+ if (!this.provisioner.resize) {
926
+ throw new Error('Resize not supported by current compute provider');
927
+ }
928
+ await this.provisioner.resize(workspace, tier);
929
+ // Update workspace config with new limits
930
+ await db.workspaces.updateConfig(workspaceId, {
931
+ ...workspace.config,
932
+ maxAgents: tier.maxAgents,
933
+ resourceTier: tier.name,
934
+ });
935
+ }
936
+ /**
937
+ * Update the max agent limit for a workspace
938
+ */
939
+ async updateAgentLimit(workspaceId, newLimit) {
940
+ const workspace = await db.workspaces.findById(workspaceId);
941
+ if (!workspace) {
942
+ throw new Error('Workspace not found');
943
+ }
944
+ if (this.provisioner.updateAgentLimit) {
945
+ await this.provisioner.updateAgentLimit(workspace, newLimit);
946
+ }
947
+ // Update workspace config
948
+ await db.workspaces.updateConfig(workspaceId, {
949
+ ...workspace.config,
950
+ maxAgents: newLimit,
951
+ });
952
+ }
953
+ /**
954
+ * Get current resource tier for a workspace
955
+ */
956
+ async getCurrentTier(workspaceId) {
957
+ const workspace = await db.workspaces.findById(workspaceId);
958
+ if (!workspace) {
959
+ throw new Error('Workspace not found');
960
+ }
961
+ if (this.provisioner.getCurrentTier) {
962
+ return this.provisioner.getCurrentTier(workspace);
963
+ }
964
+ // Fallback: determine from config or default to small
965
+ const tierName = workspace.config.resourceTier || 'small';
966
+ return RESOURCE_TIERS[tierName] || RESOURCE_TIERS.small;
967
+ }
968
+ }
969
+ // Singleton instance
970
+ let _provisioner = null;
971
+ export function getProvisioner() {
972
+ if (!_provisioner) {
973
+ _provisioner = new WorkspaceProvisioner();
974
+ }
975
+ return _provisioner;
976
+ }
977
+ //# sourceMappingURL=index.js.map