agent-relay 1.2.0 → 1.2.3

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 (540) hide show
  1. package/.gitattributes +3 -0
  2. package/.nvmrc +1 -0
  3. package/.trajectories/completed/2026-01/traj_1dviorhnkcb5.json +65 -0
  4. package/.trajectories/completed/2026-01/traj_1dviorhnkcb5.md +37 -0
  5. package/.trajectories/completed/2026-01/traj_1k5if5snst2e.json +65 -0
  6. package/.trajectories/completed/2026-01/traj_1k5if5snst2e.md +37 -0
  7. package/.trajectories/completed/2026-01/traj_1rp3rges5811.json +49 -0
  8. package/.trajectories/completed/2026-01/traj_1rp3rges5811.md +31 -0
  9. package/.trajectories/completed/2026-01/traj_22bhyulruouw.json +113 -0
  10. package/.trajectories/completed/2026-01/traj_22bhyulruouw.md +57 -0
  11. package/.trajectories/completed/2026-01/traj_2dao7ddgnta0.json +53 -0
  12. package/.trajectories/completed/2026-01/traj_2dao7ddgnta0.md +32 -0
  13. package/.trajectories/completed/2026-01/traj_3t0440mjeunc.json +26 -0
  14. package/.trajectories/completed/2026-01/traj_3t0440mjeunc.md +6 -0
  15. package/.trajectories/completed/2026-01/traj_45x9494d9xnr.json +47 -0
  16. package/.trajectories/completed/2026-01/traj_45x9494d9xnr.md +32 -0
  17. package/.trajectories/completed/2026-01/traj_4aa0bb77s4nh.json +53 -0
  18. package/.trajectories/completed/2026-01/traj_4aa0bb77s4nh.md +32 -0
  19. package/.trajectories/completed/2026-01/traj_5lhmzq8rxpqv.json +59 -0
  20. package/.trajectories/completed/2026-01/traj_5lhmzq8rxpqv.md +33 -0
  21. package/.trajectories/completed/2026-01/traj_5vr4e9erb1fs.json +53 -0
  22. package/.trajectories/completed/2026-01/traj_5vr4e9erb1fs.md +32 -0
  23. package/.trajectories/completed/2026-01/traj_6fgiwdoklvym.json +48 -0
  24. package/.trajectories/completed/2026-01/traj_6fgiwdoklvym.md +24 -0
  25. package/.trajectories/completed/2026-01/traj_7ludwvz45veh.json +209 -0
  26. package/.trajectories/completed/2026-01/traj_7ludwvz45veh.md +97 -0
  27. package/.trajectories/completed/2026-01/traj_9921cuhel0pj.json +48 -0
  28. package/.trajectories/completed/2026-01/traj_9921cuhel0pj.md +24 -0
  29. package/.trajectories/completed/2026-01/traj_ajs7zqfux4wc.json +49 -0
  30. package/.trajectories/completed/2026-01/traj_ajs7zqfux4wc.md +23 -0
  31. package/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.json +53 -0
  32. package/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.md +32 -0
  33. package/.trajectories/completed/2026-01/traj_cxofprm2m2en.json +49 -0
  34. package/.trajectories/completed/2026-01/traj_cxofprm2m2en.md +31 -0
  35. package/.trajectories/completed/2026-01/traj_d2hhz3k0vrhn.json +26 -0
  36. package/.trajectories/completed/2026-01/traj_d2hhz3k0vrhn.md +6 -0
  37. package/.trajectories/completed/2026-01/traj_dfuvww9pege5.json +59 -0
  38. package/.trajectories/completed/2026-01/traj_dfuvww9pege5.md +37 -0
  39. package/.trajectories/completed/2026-01/traj_g0fisy9h51mf.json +77 -0
  40. package/.trajectories/completed/2026-01/traj_g0fisy9h51mf.md +42 -0
  41. package/.trajectories/completed/2026-01/traj_gjdre5voouod.json +53 -0
  42. package/.trajectories/completed/2026-01/traj_gjdre5voouod.md +32 -0
  43. package/.trajectories/completed/2026-01/traj_gtlyqtta3x8l.json +25 -0
  44. package/.trajectories/completed/2026-01/traj_gtlyqtta3x8l.md +15 -0
  45. package/.trajectories/completed/2026-01/traj_h4xijiuip3w4.json +101 -0
  46. package/.trajectories/completed/2026-01/traj_h4xijiuip3w4.md +44 -0
  47. package/.trajectories/completed/2026-01/traj_hhxte7w4gjjx.json +22 -0
  48. package/.trajectories/completed/2026-01/traj_hhxte7w4gjjx.md +5 -0
  49. package/.trajectories/completed/2026-01/traj_hpungyhoj6v5.json +53 -0
  50. package/.trajectories/completed/2026-01/traj_hpungyhoj6v5.md +32 -0
  51. package/.trajectories/completed/2026-01/traj_m2xkjv0w2sq7.json +25 -0
  52. package/.trajectories/completed/2026-01/traj_m2xkjv0w2sq7.md +15 -0
  53. package/.trajectories/completed/2026-01/traj_noq5zbvnrdvz.json +53 -0
  54. package/.trajectories/completed/2026-01/traj_noq5zbvnrdvz.md +32 -0
  55. package/.trajectories/completed/2026-01/traj_ntbs6ppopf46.json +53 -0
  56. package/.trajectories/completed/2026-01/traj_ntbs6ppopf46.md +32 -0
  57. package/.trajectories/completed/2026-01/traj_ozd98si6a7ns.json +48 -0
  58. package/.trajectories/completed/2026-01/traj_ozd98si6a7ns.md +24 -0
  59. package/.trajectories/completed/2026-01/traj_prdza7a5cxp5.json +53 -0
  60. package/.trajectories/completed/2026-01/traj_prdza7a5cxp5.md +32 -0
  61. package/.trajectories/completed/2026-01/traj_qb3twvvywfwi.json +77 -0
  62. package/.trajectories/completed/2026-01/traj_qb3twvvywfwi.md +42 -0
  63. package/.trajectories/completed/2026-01/traj_qft54mi7nfor.json +53 -0
  64. package/.trajectories/completed/2026-01/traj_qft54mi7nfor.md +32 -0
  65. package/.trajectories/completed/2026-01/traj_qx9uhf8whhxo.json +83 -0
  66. package/.trajectories/completed/2026-01/traj_qx9uhf8whhxo.md +47 -0
  67. package/.trajectories/completed/2026-01/traj_rd9toccj18a0.json +59 -0
  68. package/.trajectories/completed/2026-01/traj_rd9toccj18a0.md +37 -0
  69. package/.trajectories/completed/2026-01/traj_rt4fiw3ecp50.json +48 -0
  70. package/.trajectories/completed/2026-01/traj_rt4fiw3ecp50.md +16 -0
  71. package/.trajectories/completed/2026-01/traj_st8j35b0hrlc.json +59 -0
  72. package/.trajectories/completed/2026-01/traj_st8j35b0hrlc.md +37 -0
  73. package/.trajectories/completed/2026-01/traj_t1yy8m7hbuxp.json +53 -0
  74. package/.trajectories/completed/2026-01/traj_t1yy8m7hbuxp.md +32 -0
  75. package/.trajectories/completed/2026-01/traj_tmux_orchestrator_analysis.json +84 -0
  76. package/.trajectories/completed/2026-01/traj_tmux_orchestrator_analysis.md +109 -0
  77. package/.trajectories/completed/2026-01/traj_u9n9eqasw16k.json +53 -0
  78. package/.trajectories/completed/2026-01/traj_u9n9eqasw16k.md +32 -0
  79. package/.trajectories/completed/2026-01/traj_v87hypnongqx.json +71 -0
  80. package/.trajectories/completed/2026-01/traj_v87hypnongqx.md +42 -0
  81. package/.trajectories/completed/2026-01/traj_wkp2fgzdyinb.json +53 -0
  82. package/.trajectories/completed/2026-01/traj_wkp2fgzdyinb.md +32 -0
  83. package/.trajectories/completed/2026-01/traj_x14t8w8rn7xg.json +20 -0
  84. package/.trajectories/completed/2026-01/traj_x14t8w8rn7xg.md +6 -0
  85. package/.trajectories/completed/2026-01/traj_xnwbznkvv8ua.json +175 -0
  86. package/.trajectories/completed/2026-01/traj_xnwbznkvv8ua.md +82 -0
  87. package/.trajectories/completed/2026-01/traj_ysjc8zaeqtd3.json +47 -0
  88. package/.trajectories/completed/2026-01/traj_ysjc8zaeqtd3.md +32 -0
  89. package/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.json +59 -0
  90. package/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.md +37 -0
  91. package/.trajectories/completed/2026-01/traj_z0vcw1wrzide.json +53 -0
  92. package/.trajectories/completed/2026-01/traj_z0vcw1wrzide.md +32 -0
  93. package/.trajectories/index.json +314 -0
  94. package/ARCHITECTURE.md +1245 -0
  95. package/TESTING.md +278 -0
  96. package/deploy/init-db.sql +5 -0
  97. package/deploy/scripts/setup-fly-workspaces.sh +69 -0
  98. package/deploy/scripts/setup-railway.sh +75 -0
  99. package/deploy/workspace/entrypoint-browser.sh +118 -0
  100. package/deploy/workspace/entrypoint.sh +348 -0
  101. package/deploy/workspace/git-credential-relay +111 -0
  102. package/dist/cli/index.js +218 -1
  103. package/dist/cloud/api/billing.js +30 -9
  104. package/dist/cloud/api/codex-auth-helper.d.ts +15 -0
  105. package/dist/cloud/api/codex-auth-helper.js +100 -0
  106. package/dist/cloud/api/git.js +24 -3
  107. package/dist/cloud/api/onboarding.js +15 -2
  108. package/dist/cloud/api/repos.d.ts +1 -0
  109. package/dist/cloud/api/repos.js +186 -0
  110. package/dist/cloud/api/webhooks.d.ts +1 -0
  111. package/dist/cloud/api/webhooks.js +149 -0
  112. package/dist/cloud/api/workspaces.js +97 -6
  113. package/dist/cloud/billing/plans.js +19 -19
  114. package/dist/cloud/provisioner/index.d.ts +32 -0
  115. package/dist/cloud/provisioner/index.js +362 -21
  116. package/dist/cloud/server.js +6 -1
  117. package/dist/cloud/services/nango.d.ts +60 -0
  118. package/dist/cloud/services/nango.js +153 -0
  119. package/dist/cloud/services/planLimits.d.ts +22 -0
  120. package/dist/cloud/services/planLimits.js +58 -5
  121. package/dist/dashboard/out/404.html +1 -1
  122. package/dist/dashboard/out/_next/static/chunks/699-3b1cd6618a45d259.js +1 -0
  123. package/dist/dashboard/out/_next/static/chunks/766-1f2dd8cb7f766b0b.js +1 -0
  124. package/dist/dashboard/out/_next/static/chunks/app/app/onboarding/page-3fdfa60e53f2810d.js +1 -0
  125. package/dist/dashboard/out/_next/static/chunks/app/app/page-e6381e5a6e1fbcfd.js +1 -0
  126. package/dist/dashboard/out/_next/static/chunks/app/connect-repos/page-3538dfe0ffe984b8.js +1 -0
  127. package/dist/dashboard/out/_next/static/chunks/app/history/{page-56a8b4616a90dc43.js → page-abb9ab2d329f56e9.js} +1 -1
  128. package/dist/dashboard/out/_next/static/chunks/app/layout-c0d118c0f92d969c.js +1 -0
  129. package/dist/dashboard/out/_next/static/chunks/app/login/{page-3eac37ea6f5dd153.js → page-c22d080201cbd9fb.js} +1 -1
  130. package/dist/dashboard/out/_next/static/chunks/app/metrics/{page-1081dd190a331a91.js → page-67a3e98d9a43a6ed.js} +1 -1
  131. package/dist/dashboard/out/_next/static/chunks/app/{page-daf87e86f783f980.js → page-77e9c65420a06cfb.js} +1 -1
  132. package/dist/dashboard/out/_next/static/chunks/app/pricing/page-b08ed1c34d14434a.js +1 -0
  133. package/dist/dashboard/out/_next/static/chunks/app/providers/page-e88bc117ef7671c3.js +1 -0
  134. package/dist/dashboard/out/_next/static/chunks/app/signup/{page-fee4ed1709070bcd.js → page-68d34f50baa8ab6b.js} +1 -1
  135. package/dist/dashboard/out/_next/static/chunks/{main-app-5d692157a8eb1fd9.js → main-app-6e8e8d3ef4e0192a.js} +1 -1
  136. package/dist/dashboard/out/_next/static/chunks/{main-97850e03d723ea8c.js → main-ed4e1fb6f29c34cf.js} +1 -1
  137. package/dist/dashboard/out/_next/static/css/7c3ae9e8617d42a5.css +1 -0
  138. package/dist/dashboard/out/app/onboarding.html +1 -0
  139. package/dist/dashboard/out/app/onboarding.txt +7 -0
  140. package/dist/dashboard/out/app.html +1 -1
  141. package/dist/dashboard/out/app.txt +2 -2
  142. package/dist/dashboard/out/connect-repos.html +1 -1
  143. package/dist/dashboard/out/connect-repos.txt +2 -2
  144. package/dist/dashboard/out/history.html +1 -1
  145. package/dist/dashboard/out/history.txt +2 -2
  146. package/dist/dashboard/out/index.html +1 -1
  147. package/dist/dashboard/out/index.txt +2 -2
  148. package/dist/dashboard/out/login.html +2 -2
  149. package/dist/dashboard/out/login.txt +2 -2
  150. package/dist/dashboard/out/metrics.html +1 -1
  151. package/dist/dashboard/out/metrics.txt +2 -2
  152. package/dist/dashboard/out/pricing.html +3 -3
  153. package/dist/dashboard/out/pricing.txt +2 -2
  154. package/dist/dashboard/out/providers.html +1 -1
  155. package/dist/dashboard/out/providers.txt +2 -2
  156. package/dist/dashboard/out/signup.html +2 -2
  157. package/dist/dashboard/out/signup.txt +2 -2
  158. package/package.json +2 -11
  159. package/test-push.txt +1 -0
  160. package/bin/tmux +0 -0
  161. package/dist/bridge/config.d.ts.map +0 -1
  162. package/dist/bridge/config.js.map +0 -1
  163. package/dist/bridge/index.d.ts.map +0 -1
  164. package/dist/bridge/index.js.map +0 -1
  165. package/dist/bridge/multi-project-client.d.ts.map +0 -1
  166. package/dist/bridge/multi-project-client.js.map +0 -1
  167. package/dist/bridge/shadow-cli.d.ts.map +0 -1
  168. package/dist/bridge/shadow-cli.js.map +0 -1
  169. package/dist/bridge/shadow-config.d.ts.map +0 -1
  170. package/dist/bridge/shadow-config.js.map +0 -1
  171. package/dist/bridge/spawner.d.ts.map +0 -1
  172. package/dist/bridge/spawner.js.map +0 -1
  173. package/dist/bridge/teams-config.d.ts.map +0 -1
  174. package/dist/bridge/teams-config.js.map +0 -1
  175. package/dist/bridge/types.d.ts.map +0 -1
  176. package/dist/bridge/types.js.map +0 -1
  177. package/dist/bridge/utils.d.ts.map +0 -1
  178. package/dist/bridge/utils.js.map +0 -1
  179. package/dist/cli/index.d.ts.map +0 -1
  180. package/dist/cli/index.js.map +0 -1
  181. package/dist/cloud/api/auth.d.ts.map +0 -1
  182. package/dist/cloud/api/auth.js.map +0 -1
  183. package/dist/cloud/api/billing.d.ts.map +0 -1
  184. package/dist/cloud/api/billing.js.map +0 -1
  185. package/dist/cloud/api/cli-pty-runner.d.ts.map +0 -1
  186. package/dist/cloud/api/cli-pty-runner.js.map +0 -1
  187. package/dist/cloud/api/coordinators.d.ts.map +0 -1
  188. package/dist/cloud/api/coordinators.js.map +0 -1
  189. package/dist/cloud/api/daemons.d.ts.map +0 -1
  190. package/dist/cloud/api/daemons.js.map +0 -1
  191. package/dist/cloud/api/generic-webhooks.d.ts.map +0 -1
  192. package/dist/cloud/api/generic-webhooks.js.map +0 -1
  193. package/dist/cloud/api/git.d.ts.map +0 -1
  194. package/dist/cloud/api/git.js.map +0 -1
  195. package/dist/cloud/api/github-app.d.ts.map +0 -1
  196. package/dist/cloud/api/github-app.js.map +0 -1
  197. package/dist/cloud/api/middleware/planLimits.d.ts.map +0 -1
  198. package/dist/cloud/api/middleware/planLimits.js.map +0 -1
  199. package/dist/cloud/api/monitoring.d.ts.map +0 -1
  200. package/dist/cloud/api/monitoring.js.map +0 -1
  201. package/dist/cloud/api/nango-auth.d.ts.map +0 -1
  202. package/dist/cloud/api/nango-auth.js.map +0 -1
  203. package/dist/cloud/api/onboarding.d.ts.map +0 -1
  204. package/dist/cloud/api/onboarding.js.map +0 -1
  205. package/dist/cloud/api/policy.d.ts.map +0 -1
  206. package/dist/cloud/api/policy.js.map +0 -1
  207. package/dist/cloud/api/providers.d.ts.map +0 -1
  208. package/dist/cloud/api/providers.js.map +0 -1
  209. package/dist/cloud/api/repos.d.ts.map +0 -1
  210. package/dist/cloud/api/repos.js.map +0 -1
  211. package/dist/cloud/api/teams.d.ts.map +0 -1
  212. package/dist/cloud/api/teams.js.map +0 -1
  213. package/dist/cloud/api/test-helpers.d.ts.map +0 -1
  214. package/dist/cloud/api/test-helpers.js.map +0 -1
  215. package/dist/cloud/api/usage.d.ts.map +0 -1
  216. package/dist/cloud/api/usage.js.map +0 -1
  217. package/dist/cloud/api/webhooks.d.ts.map +0 -1
  218. package/dist/cloud/api/webhooks.js.map +0 -1
  219. package/dist/cloud/api/workspaces.d.ts.map +0 -1
  220. package/dist/cloud/api/workspaces.js.map +0 -1
  221. package/dist/cloud/billing/index.d.ts.map +0 -1
  222. package/dist/cloud/billing/index.js.map +0 -1
  223. package/dist/cloud/billing/plans.d.ts.map +0 -1
  224. package/dist/cloud/billing/plans.js.map +0 -1
  225. package/dist/cloud/billing/service.d.ts.map +0 -1
  226. package/dist/cloud/billing/service.js.map +0 -1
  227. package/dist/cloud/billing/types.d.ts.map +0 -1
  228. package/dist/cloud/billing/types.js.map +0 -1
  229. package/dist/cloud/config.d.ts.map +0 -1
  230. package/dist/cloud/config.js.map +0 -1
  231. package/dist/cloud/db/drizzle.d.ts.map +0 -1
  232. package/dist/cloud/db/drizzle.js.map +0 -1
  233. package/dist/cloud/db/index.d.ts.map +0 -1
  234. package/dist/cloud/db/index.js.map +0 -1
  235. package/dist/cloud/db/schema.d.ts.map +0 -1
  236. package/dist/cloud/db/schema.js.map +0 -1
  237. package/dist/cloud/index.d.ts.map +0 -1
  238. package/dist/cloud/index.js.map +0 -1
  239. package/dist/cloud/provisioner/index.d.ts.map +0 -1
  240. package/dist/cloud/provisioner/index.js.map +0 -1
  241. package/dist/cloud/server.d.ts.map +0 -1
  242. package/dist/cloud/server.js.map +0 -1
  243. package/dist/cloud/services/auto-scaler.d.ts.map +0 -1
  244. package/dist/cloud/services/auto-scaler.js.map +0 -1
  245. package/dist/cloud/services/capacity-manager.d.ts.map +0 -1
  246. package/dist/cloud/services/capacity-manager.js.map +0 -1
  247. package/dist/cloud/services/ci-agent-spawner.d.ts.map +0 -1
  248. package/dist/cloud/services/ci-agent-spawner.js.map +0 -1
  249. package/dist/cloud/services/coordinator.d.ts.map +0 -1
  250. package/dist/cloud/services/coordinator.js.map +0 -1
  251. package/dist/cloud/services/index.d.ts.map +0 -1
  252. package/dist/cloud/services/index.js.map +0 -1
  253. package/dist/cloud/services/mention-handler.d.ts.map +0 -1
  254. package/dist/cloud/services/mention-handler.js.map +0 -1
  255. package/dist/cloud/services/nango.d.ts.map +0 -1
  256. package/dist/cloud/services/nango.js.map +0 -1
  257. package/dist/cloud/services/persistence.d.ts.map +0 -1
  258. package/dist/cloud/services/persistence.js.map +0 -1
  259. package/dist/cloud/services/planLimits.d.ts.map +0 -1
  260. package/dist/cloud/services/planLimits.js.map +0 -1
  261. package/dist/cloud/services/scaling-orchestrator.d.ts.map +0 -1
  262. package/dist/cloud/services/scaling-orchestrator.js.map +0 -1
  263. package/dist/cloud/services/scaling-policy.d.ts.map +0 -1
  264. package/dist/cloud/services/scaling-policy.js.map +0 -1
  265. package/dist/cloud/vault/index.d.ts.map +0 -1
  266. package/dist/cloud/vault/index.js.map +0 -1
  267. package/dist/cloud/webhooks/index.d.ts.map +0 -1
  268. package/dist/cloud/webhooks/index.js.map +0 -1
  269. package/dist/cloud/webhooks/parsers/github.d.ts.map +0 -1
  270. package/dist/cloud/webhooks/parsers/github.js.map +0 -1
  271. package/dist/cloud/webhooks/parsers/index.d.ts.map +0 -1
  272. package/dist/cloud/webhooks/parsers/index.js.map +0 -1
  273. package/dist/cloud/webhooks/parsers/linear.d.ts.map +0 -1
  274. package/dist/cloud/webhooks/parsers/linear.js.map +0 -1
  275. package/dist/cloud/webhooks/parsers/slack.d.ts.map +0 -1
  276. package/dist/cloud/webhooks/parsers/slack.js.map +0 -1
  277. package/dist/cloud/webhooks/responders/github.d.ts.map +0 -1
  278. package/dist/cloud/webhooks/responders/github.js.map +0 -1
  279. package/dist/cloud/webhooks/responders/index.d.ts.map +0 -1
  280. package/dist/cloud/webhooks/responders/index.js.map +0 -1
  281. package/dist/cloud/webhooks/responders/linear.d.ts.map +0 -1
  282. package/dist/cloud/webhooks/responders/linear.js.map +0 -1
  283. package/dist/cloud/webhooks/responders/slack.d.ts.map +0 -1
  284. package/dist/cloud/webhooks/responders/slack.js.map +0 -1
  285. package/dist/cloud/webhooks/router.d.ts.map +0 -1
  286. package/dist/cloud/webhooks/router.js.map +0 -1
  287. package/dist/cloud/webhooks/rules-engine.d.ts.map +0 -1
  288. package/dist/cloud/webhooks/rules-engine.js.map +0 -1
  289. package/dist/cloud/webhooks/types.d.ts.map +0 -1
  290. package/dist/cloud/webhooks/types.js.map +0 -1
  291. package/dist/continuity/formatter.d.ts.map +0 -1
  292. package/dist/continuity/formatter.js.map +0 -1
  293. package/dist/continuity/handoff-store.d.ts.map +0 -1
  294. package/dist/continuity/handoff-store.js.map +0 -1
  295. package/dist/continuity/index.d.ts.map +0 -1
  296. package/dist/continuity/index.js.map +0 -1
  297. package/dist/continuity/ledger-store.d.ts.map +0 -1
  298. package/dist/continuity/ledger-store.js.map +0 -1
  299. package/dist/continuity/manager.d.ts.map +0 -1
  300. package/dist/continuity/manager.js.map +0 -1
  301. package/dist/continuity/parser.d.ts.map +0 -1
  302. package/dist/continuity/parser.js.map +0 -1
  303. package/dist/continuity/types.d.ts.map +0 -1
  304. package/dist/continuity/types.js.map +0 -1
  305. package/dist/daemon/agent-manager.d.ts.map +0 -1
  306. package/dist/daemon/agent-manager.js.map +0 -1
  307. package/dist/daemon/agent-registry.d.ts.map +0 -1
  308. package/dist/daemon/agent-registry.js.map +0 -1
  309. package/dist/daemon/api.d.ts.map +0 -1
  310. package/dist/daemon/api.js.map +0 -1
  311. package/dist/daemon/auth.d.ts.map +0 -1
  312. package/dist/daemon/auth.js.map +0 -1
  313. package/dist/daemon/cli-auth.d.ts.map +0 -1
  314. package/dist/daemon/cli-auth.js.map +0 -1
  315. package/dist/daemon/cloud-sync.d.ts.map +0 -1
  316. package/dist/daemon/cloud-sync.js.map +0 -1
  317. package/dist/daemon/connection.d.ts.map +0 -1
  318. package/dist/daemon/connection.js.map +0 -1
  319. package/dist/daemon/index.d.ts.map +0 -1
  320. package/dist/daemon/index.js.map +0 -1
  321. package/dist/daemon/orchestrator.d.ts.map +0 -1
  322. package/dist/daemon/orchestrator.js.map +0 -1
  323. package/dist/daemon/registry.d.ts.map +0 -1
  324. package/dist/daemon/registry.js.map +0 -1
  325. package/dist/daemon/router.d.ts.map +0 -1
  326. package/dist/daemon/router.js.map +0 -1
  327. package/dist/daemon/server.d.ts.map +0 -1
  328. package/dist/daemon/server.js.map +0 -1
  329. package/dist/daemon/services/browser-testing.d.ts.map +0 -1
  330. package/dist/daemon/services/browser-testing.js.map +0 -1
  331. package/dist/daemon/services/container-spawner.d.ts.map +0 -1
  332. package/dist/daemon/services/container-spawner.js.map +0 -1
  333. package/dist/daemon/types.d.ts.map +0 -1
  334. package/dist/daemon/types.js.map +0 -1
  335. package/dist/daemon/workspace-manager.d.ts.map +0 -1
  336. package/dist/daemon/workspace-manager.js.map +0 -1
  337. package/dist/dashboard/out/_next/static/chunks/480-2d4111711d4e473c.js +0 -1
  338. package/dist/dashboard/out/_next/static/chunks/766-c3a14283c88d815b.js +0 -1
  339. package/dist/dashboard/out/_next/static/chunks/app/app/page-7120be68bea622f3.js +0 -1
  340. package/dist/dashboard/out/_next/static/chunks/app/connect-repos/page-dc2e3a1a22478efc.js +0 -1
  341. package/dist/dashboard/out/_next/static/chunks/app/layout-2433bb48965f4333.js +0 -1
  342. package/dist/dashboard/out/_next/static/chunks/app/pricing/page-4d72d5a5d8a9b618.js +0 -1
  343. package/dist/dashboard/out/_next/static/chunks/app/providers/page-b68a681526eb145e.js +0 -1
  344. package/dist/dashboard/out/_next/static/css/411ce23ffeae9f76.css +0 -1
  345. package/dist/dashboard-server/metrics.d.ts.map +0 -1
  346. package/dist/dashboard-server/metrics.js.map +0 -1
  347. package/dist/dashboard-server/needs-attention.d.ts.map +0 -1
  348. package/dist/dashboard-server/needs-attention.js.map +0 -1
  349. package/dist/dashboard-server/server.d.ts.map +0 -1
  350. package/dist/dashboard-server/server.js.map +0 -1
  351. package/dist/dashboard-server/start.d.ts.map +0 -1
  352. package/dist/dashboard-server/start.js.map +0 -1
  353. package/dist/hooks/emitter.d.ts.map +0 -1
  354. package/dist/hooks/emitter.js.map +0 -1
  355. package/dist/hooks/inbox-check/hook.d.ts.map +0 -1
  356. package/dist/hooks/inbox-check/hook.js.map +0 -1
  357. package/dist/hooks/inbox-check/index.d.ts.map +0 -1
  358. package/dist/hooks/inbox-check/index.js.map +0 -1
  359. package/dist/hooks/inbox-check/types.d.ts.map +0 -1
  360. package/dist/hooks/inbox-check/types.js.map +0 -1
  361. package/dist/hooks/inbox-check/utils.d.ts.map +0 -1
  362. package/dist/hooks/inbox-check/utils.js.map +0 -1
  363. package/dist/hooks/index.d.ts.map +0 -1
  364. package/dist/hooks/index.js.map +0 -1
  365. package/dist/hooks/registry.d.ts.map +0 -1
  366. package/dist/hooks/registry.js.map +0 -1
  367. package/dist/hooks/trajectory-hooks.d.ts.map +0 -1
  368. package/dist/hooks/trajectory-hooks.js.map +0 -1
  369. package/dist/hooks/types.d.ts.map +0 -1
  370. package/dist/hooks/types.js.map +0 -1
  371. package/dist/index.d.ts.map +0 -1
  372. package/dist/index.js.map +0 -1
  373. package/dist/memory/adapters/index.d.ts.map +0 -1
  374. package/dist/memory/adapters/index.js.map +0 -1
  375. package/dist/memory/adapters/inmemory.d.ts.map +0 -1
  376. package/dist/memory/adapters/inmemory.js.map +0 -1
  377. package/dist/memory/adapters/supermemory.d.ts.map +0 -1
  378. package/dist/memory/adapters/supermemory.js.map +0 -1
  379. package/dist/memory/factory.d.ts.map +0 -1
  380. package/dist/memory/factory.js.map +0 -1
  381. package/dist/memory/index.d.ts.map +0 -1
  382. package/dist/memory/index.js.map +0 -1
  383. package/dist/memory/memory-hooks.d.ts.map +0 -1
  384. package/dist/memory/memory-hooks.js.map +0 -1
  385. package/dist/memory/service.d.ts.map +0 -1
  386. package/dist/memory/service.js.map +0 -1
  387. package/dist/memory/types.d.ts.map +0 -1
  388. package/dist/memory/types.js.map +0 -1
  389. package/dist/policy/agent-policy.d.ts.map +0 -1
  390. package/dist/policy/agent-policy.js.map +0 -1
  391. package/dist/policy/cloud-policy-fetcher.d.ts.map +0 -1
  392. package/dist/policy/cloud-policy-fetcher.js.map +0 -1
  393. package/dist/protocol/framing.d.ts.map +0 -1
  394. package/dist/protocol/framing.js.map +0 -1
  395. package/dist/protocol/index.d.ts.map +0 -1
  396. package/dist/protocol/index.js.map +0 -1
  397. package/dist/protocol/types.d.ts.map +0 -1
  398. package/dist/protocol/types.js.map +0 -1
  399. package/dist/resiliency/context-persistence.d.ts.map +0 -1
  400. package/dist/resiliency/context-persistence.js.map +0 -1
  401. package/dist/resiliency/crash-insights.d.ts.map +0 -1
  402. package/dist/resiliency/crash-insights.js.map +0 -1
  403. package/dist/resiliency/gossip-health.d.ts.map +0 -1
  404. package/dist/resiliency/gossip-health.js.map +0 -1
  405. package/dist/resiliency/health-monitor.d.ts.map +0 -1
  406. package/dist/resiliency/health-monitor.js.map +0 -1
  407. package/dist/resiliency/index.d.ts.map +0 -1
  408. package/dist/resiliency/index.js.map +0 -1
  409. package/dist/resiliency/leader-watchdog.d.ts.map +0 -1
  410. package/dist/resiliency/leader-watchdog.js.map +0 -1
  411. package/dist/resiliency/logger.d.ts.map +0 -1
  412. package/dist/resiliency/logger.js.map +0 -1
  413. package/dist/resiliency/memory-monitor.d.ts.map +0 -1
  414. package/dist/resiliency/memory-monitor.js.map +0 -1
  415. package/dist/resiliency/metrics.d.ts.map +0 -1
  416. package/dist/resiliency/metrics.js.map +0 -1
  417. package/dist/resiliency/provider-context.d.ts.map +0 -1
  418. package/dist/resiliency/provider-context.js.map +0 -1
  419. package/dist/resiliency/stateless-lead.d.ts.map +0 -1
  420. package/dist/resiliency/stateless-lead.js.map +0 -1
  421. package/dist/resiliency/supervisor.d.ts.map +0 -1
  422. package/dist/resiliency/supervisor.js.map +0 -1
  423. package/dist/shared/cli-auth-config.d.ts.map +0 -1
  424. package/dist/shared/cli-auth-config.js.map +0 -1
  425. package/dist/state/agent-state.d.ts.map +0 -1
  426. package/dist/state/agent-state.js.map +0 -1
  427. package/dist/storage/adapter.d.ts.map +0 -1
  428. package/dist/storage/adapter.js.map +0 -1
  429. package/dist/storage/sqlite-adapter.d.ts.map +0 -1
  430. package/dist/storage/sqlite-adapter.js.map +0 -1
  431. package/dist/trajectory/config.d.ts.map +0 -1
  432. package/dist/trajectory/config.js.map +0 -1
  433. package/dist/trajectory/index.d.ts.map +0 -1
  434. package/dist/trajectory/index.js.map +0 -1
  435. package/dist/trajectory/integration.d.ts.map +0 -1
  436. package/dist/trajectory/integration.js.map +0 -1
  437. package/dist/utils/agent-config.d.ts.map +0 -1
  438. package/dist/utils/agent-config.js.map +0 -1
  439. package/dist/utils/command-resolver.d.ts.map +0 -1
  440. package/dist/utils/command-resolver.js.map +0 -1
  441. package/dist/utils/index.d.ts.map +0 -1
  442. package/dist/utils/index.js.map +0 -1
  443. package/dist/utils/logger.d.ts.map +0 -1
  444. package/dist/utils/logger.js.map +0 -1
  445. package/dist/utils/name-generator.d.ts.map +0 -1
  446. package/dist/utils/name-generator.js.map +0 -1
  447. package/dist/utils/project-namespace.d.ts.map +0 -1
  448. package/dist/utils/project-namespace.js.map +0 -1
  449. package/dist/utils/tmux-resolver.d.ts.map +0 -1
  450. package/dist/utils/tmux-resolver.js.map +0 -1
  451. package/dist/utils/update-checker.d.ts.map +0 -1
  452. package/dist/utils/update-checker.js.map +0 -1
  453. package/dist/wrapper/client.d.ts.map +0 -1
  454. package/dist/wrapper/client.js.map +0 -1
  455. package/dist/wrapper/inbox.d.ts.map +0 -1
  456. package/dist/wrapper/inbox.js.map +0 -1
  457. package/dist/wrapper/index.d.ts.map +0 -1
  458. package/dist/wrapper/index.js.map +0 -1
  459. package/dist/wrapper/parser.d.ts.map +0 -1
  460. package/dist/wrapper/parser.js.map +0 -1
  461. package/dist/wrapper/pty-wrapper.d.ts.map +0 -1
  462. package/dist/wrapper/pty-wrapper.js.map +0 -1
  463. package/dist/wrapper/shared.d.ts.map +0 -1
  464. package/dist/wrapper/shared.js.map +0 -1
  465. package/dist/wrapper/tmux-wrapper.d.ts.map +0 -1
  466. package/dist/wrapper/tmux-wrapper.js.map +0 -1
  467. package/docs/AGENTS.md +0 -513
  468. package/docs/ARCHITECTURE_DECISIONS.md +0 -175
  469. package/docs/CLOUD-ARCHITECTURE.md +0 -804
  470. package/docs/CLOUD-ONBOARDING-DESIGN.md +0 -1983
  471. package/docs/CONTRIBUTING.md +0 -151
  472. package/docs/HOOKS_API.md +0 -394
  473. package/docs/INTEGRATION-GUIDE.md +0 -926
  474. package/docs/PROTOCOL.md +0 -325
  475. package/docs/WRAPPER_EVENTS.md +0 -358
  476. package/docs/agent-policy-snippet.md +0 -40
  477. package/docs/agent-relay-protocol.md +0 -238
  478. package/docs/agent-relay-snippet.md +0 -174
  479. package/docs/archive/CHANGELOG.md +0 -11
  480. package/docs/archive/CLI-SIMPLIFICATION-COMPLETE.md +0 -48
  481. package/docs/archive/DESIGN_BRIDGE_STAFFING.md +0 -878
  482. package/docs/archive/DESIGN_V2.md +0 -1079
  483. package/docs/archive/EXECUTIVE_SUMMARY.md +0 -358
  484. package/docs/archive/MONETIZATION.md +0 -1679
  485. package/docs/archive/PROPOSAL-trajectories.md +0 -1582
  486. package/docs/archive/ROADMAP.md +0 -329
  487. package/docs/archive/SCALING_ANALYSIS.md +0 -280
  488. package/docs/archive/TESTING_PRESENCE_FEATURES.md +0 -327
  489. package/docs/archive/TMUX_IMPLEMENTATION_NOTES.md +0 -364
  490. package/docs/archive/TMUX_IMPROVEMENTS.md +0 -968
  491. package/docs/archive/dashboard-v2-plan.md +0 -179
  492. package/docs/archive/removable-code-analysis.md +0 -24
  493. package/docs/competitive/GASTOWN.md +0 -451
  494. package/docs/competitive/MCP_AGENT_MAIL.md +0 -389
  495. package/docs/competitive/OVERVIEW.md +0 -898
  496. package/docs/competitive/README.md +0 -34
  497. package/docs/competitive/TMUX_ORCHESTRATOR.md +0 -605
  498. package/docs/dashboard.png +0 -0
  499. package/docs/design/ci-failure-webhooks.md +0 -812
  500. package/docs/design/comprehensive-integrations.md +0 -238
  501. package/docs/design/e2b-sandbox-integration.md +0 -504
  502. package/docs/design/github-app-permissions.md +0 -264
  503. package/docs/guides/CLOUD.md +0 -236
  504. package/docs/guides/LOCAL.md +0 -535
  505. package/docs/guides/SELF-HOSTED.md +0 -494
  506. package/docs/local-testing.md +0 -428
  507. package/docs/proposals/continuous-claude-integration.md +0 -622
  508. package/docs/proposals/custom-commands.md +0 -368
  509. package/docs/proposals/shadow-as-subagent.md +0 -765
  510. package/docs/proposals/slack-bot-integration.md +0 -1457
  511. package/docs/tasks/global-skills-system.tasks.md +0 -230
  512. package/docs/tasks/webhook-integrations.tasks.md +0 -184
  513. package/docs/tasks/workspace-capabilities.tasks.md +0 -121
  514. package/docs/testing/RESILIENCY-TEST-PLAN-2026-01-01.md +0 -366
  515. package/scripts/cloud-setup.sh +0 -96
  516. package/scripts/dev/PUBLIC_RELEASE_PLAN.md +0 -88
  517. package/scripts/dev/dev-team-setup.sh +0 -431
  518. package/scripts/e2e-test.sh +0 -119
  519. package/scripts/games/game-protocol.md +0 -79
  520. package/scripts/games/hearts-setup.sh +0 -264
  521. package/scripts/manual-qa.sh +0 -293
  522. package/scripts/run-cloud-qa.sh +0 -220
  523. package/scripts/test-cli-auth/Dockerfile +0 -44
  524. package/scripts/test-cli-auth/Dockerfile.real +0 -79
  525. package/scripts/test-cli-auth/README.md +0 -286
  526. package/scripts/test-cli-auth/ci-test-real-clis.ts +0 -251
  527. package/scripts/test-cli-auth/ci-test-runner.ts +0 -263
  528. package/scripts/test-cli-auth/mock-cli.sh +0 -147
  529. package/scripts/test-cli-auth/package.json +0 -14
  530. package/scripts/test-cli-auth/test-oauth-flow.ts +0 -220
  531. package/scripts/test-pty-input-auto.js +0 -222
  532. package/scripts/test-pty-input.js +0 -150
  533. package/scripts/tictactoe-setup.sh +0 -181
  534. /package/dist/dashboard/out/_next/static/chunks/{117-b100311aff8d5c61.js → 117-f7b8ab0809342e77.js} +0 -0
  535. /package/dist/dashboard/out/_next/static/chunks/{648-a13d3c2b1be45466.js → 648-5cc6e1921389a58a.js} +0 -0
  536. /package/dist/dashboard/out/_next/static/chunks/{724-73c1ee5f60abe860.js → 724-2dae7627550ab88f.js} +0 -0
  537. /package/dist/dashboard/out/_next/static/chunks/app/_not-found/{page-a4973f3e3c82fb67.js → page-53b8a69f76db17d0.js} +0 -0
  538. /package/dist/dashboard/out/_next/static/chunks/{fd9d1056-bf46c09eb57e019c.js → fd9d1056-609918ca7b6280bb.js} +0 -0
  539. /package/dist/dashboard/out/_next/static/{H5aWG0udPB4iOUIl_gytz → wPgKJtcOmTFLpUncDg16A}/_buildManifest.js +0 -0
  540. /package/dist/dashboard/out/_next/static/{H5aWG0udPB4iOUIl_gytz → wPgKJtcOmTFLpUncDg16A}/_ssgManifest.js +0 -0
@@ -2,10 +2,12 @@
2
2
  * Repos API Routes
3
3
  *
4
4
  * GitHub repository management - list, import, sync.
5
+ * Includes Nango-based GitHub permission checking for dashboard access control.
5
6
  */
6
7
  import { Router } from 'express';
7
8
  import { requireAuth } from './auth.js';
8
9
  import { db } from '../db/index.js';
10
+ import { nangoService } from '../services/nango.js';
9
11
  export const reposRouter = Router();
10
12
  // All routes require authentication
11
13
  reposRouter.use(requireAuth);
@@ -311,4 +313,188 @@ reposRouter.get('/search', async (req, res) => {
311
313
  res.status(500).json({ error: 'Failed to search repositories' });
312
314
  }
313
315
  });
316
+ // ============================================================================
317
+ // Nango-based GitHub Permission APIs (for dashboard access control)
318
+ // ============================================================================
319
+ /**
320
+ * GET /api/repos/check-access/:owner/:repo
321
+ * Check if authenticated user has access to a specific GitHub repository.
322
+ * Uses Nango proxy with user's GitHub OAuth token.
323
+ *
324
+ * Response:
325
+ * - hasAccess: boolean - Whether user can access this repo
326
+ * - permission: 'admin' | 'write' | 'read' | 'none' - User's permission level
327
+ * - repository: Repository details if user has access
328
+ *
329
+ * Use this for dashboard access control - grant access if hasAccess is true.
330
+ */
331
+ reposRouter.get('/check-access/:owner/:repo', async (req, res) => {
332
+ const userId = req.session.userId;
333
+ const { owner, repo } = req.params;
334
+ if (!owner || !repo) {
335
+ return res.status(400).json({ error: 'Owner and repo parameters are required' });
336
+ }
337
+ try {
338
+ // Get user's Nango connection ID
339
+ const user = await db.users.findById(userId);
340
+ if (!user) {
341
+ return res.status(404).json({ error: 'User not found' });
342
+ }
343
+ if (!user.nangoConnectionId) {
344
+ return res.status(400).json({
345
+ error: 'GitHub not connected via Nango',
346
+ code: 'NANGO_NOT_CONNECTED',
347
+ message: 'Please reconnect your GitHub account',
348
+ });
349
+ }
350
+ // Check access via Nango proxy
351
+ const accessResult = await nangoService.checkUserRepoAccess(user.nangoConnectionId, owner, repo);
352
+ res.json({
353
+ hasAccess: accessResult.hasAccess,
354
+ permission: accessResult.permission,
355
+ repository: accessResult.repository,
356
+ // Include user info for dashboard context
357
+ checkedBy: {
358
+ userId: user.id,
359
+ githubUsername: user.githubUsername,
360
+ },
361
+ });
362
+ }
363
+ catch (error) {
364
+ console.error('Error checking repo access:', error);
365
+ res.status(500).json({ error: 'Failed to check repository access' });
366
+ }
367
+ });
368
+ /**
369
+ * GET /api/repos/accessible
370
+ * List all GitHub repositories the authenticated user has access to.
371
+ * Uses Nango proxy with user's GitHub OAuth token.
372
+ *
373
+ * Query params:
374
+ * - page: Page number (default: 1)
375
+ * - perPage: Results per page (default: 100, max: 100)
376
+ * - type: Filter by type (all, owner, public, private, member)
377
+ * - sort: Sort by (created, updated, pushed, full_name)
378
+ *
379
+ * Use this to determine which dashboards/workspaces a user can access.
380
+ */
381
+ reposRouter.get('/accessible', async (req, res) => {
382
+ const userId = req.session.userId;
383
+ const { page, perPage, type, sort } = req.query;
384
+ try {
385
+ // Get user's Nango connection ID
386
+ const user = await db.users.findById(userId);
387
+ if (!user) {
388
+ return res.status(404).json({ error: 'User not found' });
389
+ }
390
+ if (!user.nangoConnectionId) {
391
+ return res.status(400).json({
392
+ error: 'GitHub not connected via Nango',
393
+ code: 'NANGO_NOT_CONNECTED',
394
+ message: 'Please reconnect your GitHub account',
395
+ });
396
+ }
397
+ // List accessible repos via Nango proxy
398
+ const result = await nangoService.listUserAccessibleRepos(user.nangoConnectionId, {
399
+ page: page ? parseInt(page, 10) : undefined,
400
+ perPage: perPage ? Math.min(parseInt(perPage, 10), 100) : undefined,
401
+ type: type,
402
+ sort: sort,
403
+ });
404
+ res.json({
405
+ repositories: result.repositories,
406
+ pagination: {
407
+ page: page ? parseInt(page, 10) : 1,
408
+ perPage: perPage ? Math.min(parseInt(perPage, 10), 100) : 100,
409
+ hasMore: result.hasMore,
410
+ },
411
+ // Include user info for context
412
+ checkedBy: {
413
+ userId: user.id,
414
+ githubUsername: user.githubUsername,
415
+ },
416
+ });
417
+ }
418
+ catch (error) {
419
+ console.error('Error listing accessible repos:', error);
420
+ res.status(500).json({ error: 'Failed to list accessible repositories' });
421
+ }
422
+ });
423
+ /**
424
+ * POST /api/repos/check-access-bulk
425
+ * Check access to multiple repositories at once.
426
+ * Useful for determining which workspaces a user can view.
427
+ *
428
+ * Body:
429
+ * - repositories: Array of "owner/repo" strings
430
+ *
431
+ * Response:
432
+ * - results: Array of { fullName, hasAccess, permission }
433
+ */
434
+ reposRouter.post('/check-access-bulk', async (req, res) => {
435
+ const userId = req.session.userId;
436
+ const { repositories } = req.body;
437
+ if (!repositories || !Array.isArray(repositories)) {
438
+ return res.status(400).json({ error: 'repositories array is required' });
439
+ }
440
+ if (repositories.length > 50) {
441
+ return res.status(400).json({ error: 'Maximum 50 repositories per request' });
442
+ }
443
+ try {
444
+ // Get user's Nango connection ID
445
+ const user = await db.users.findById(userId);
446
+ if (!user) {
447
+ return res.status(404).json({ error: 'User not found' });
448
+ }
449
+ if (!user.nangoConnectionId) {
450
+ return res.status(400).json({
451
+ error: 'GitHub not connected via Nango',
452
+ code: 'NANGO_NOT_CONNECTED',
453
+ message: 'Please reconnect your GitHub account',
454
+ });
455
+ }
456
+ // Check access for each repo (in parallel with concurrency limit)
457
+ const results = [];
458
+ // Process in batches of 10 to avoid rate limiting
459
+ const batchSize = 10;
460
+ for (let i = 0; i < repositories.length; i += batchSize) {
461
+ const batch = repositories.slice(i, i + batchSize);
462
+ const batchResults = await Promise.all(batch.map(async (fullName) => {
463
+ try {
464
+ const [owner, repo] = fullName.split('/');
465
+ if (!owner || !repo) {
466
+ return { fullName, hasAccess: false, error: 'Invalid repository format' };
467
+ }
468
+ const accessResult = await nangoService.checkUserRepoAccess(user.nangoConnectionId, owner, repo);
469
+ return {
470
+ fullName,
471
+ hasAccess: accessResult.hasAccess,
472
+ permission: accessResult.permission,
473
+ };
474
+ }
475
+ catch (_err) {
476
+ return { fullName, hasAccess: false, error: 'Check failed' };
477
+ }
478
+ }));
479
+ results.push(...batchResults);
480
+ }
481
+ const accessibleCount = results.filter(r => r.hasAccess).length;
482
+ res.json({
483
+ results,
484
+ summary: {
485
+ total: repositories.length,
486
+ accessible: accessibleCount,
487
+ denied: repositories.length - accessibleCount,
488
+ },
489
+ checkedBy: {
490
+ userId: user.id,
491
+ githubUsername: user.githubUsername,
492
+ },
493
+ });
494
+ }
495
+ catch (error) {
496
+ console.error('Error checking bulk repo access:', error);
497
+ res.status(500).json({ error: 'Failed to check repository access' });
498
+ }
499
+ });
314
500
  //# sourceMappingURL=repos.js.map
@@ -2,6 +2,7 @@
2
2
  * Webhook API Routes
3
3
  *
4
4
  * Handles GitHub App webhooks for installation events.
5
+ * Also provides workspace webhook forwarding for external integrations.
5
6
  */
6
7
  export declare const webhooksRouter: import("express-serve-static-core").Router;
7
8
  //# sourceMappingURL=webhooks.d.ts.map
@@ -2,12 +2,161 @@
2
2
  * Webhook API Routes
3
3
  *
4
4
  * Handles GitHub App webhooks for installation events.
5
+ * Also provides workspace webhook forwarding for external integrations.
5
6
  */
6
7
  import { Router } from 'express';
7
8
  import crypto from 'crypto';
8
9
  import { getConfig } from '../config.js';
9
10
  import { db } from '../db/index.js';
10
11
  export const webhooksRouter = Router();
12
+ // ============================================================================
13
+ // Workspace Webhook Forwarding
14
+ // ============================================================================
15
+ /**
16
+ * Convert workspace public URL to internal Fly.io URL
17
+ */
18
+ function getWorkspaceInternalUrl(publicUrl) {
19
+ const isOnFly = !!process.env.FLY_APP_NAME;
20
+ let url = publicUrl.replace(/\/$/, '');
21
+ if (isOnFly && url.includes('.fly.dev')) {
22
+ // Use Fly.io internal networking
23
+ // ar-583f273b.fly.dev -> http://ar-583f273b.internal:3888
24
+ // .internal uses IPv6 and works by default for apps in the same org
25
+ const appName = url.match(/https?:\/\/([^.]+)\.fly\.dev/)?.[1];
26
+ if (appName) {
27
+ url = `http://${appName}.internal:3888`;
28
+ }
29
+ }
30
+ return url;
31
+ }
32
+ /**
33
+ * Wake a suspended Fly.io workspace machine
34
+ */
35
+ async function wakeWorkspaceMachine(workspaceId) {
36
+ const workspace = await db.workspaces.findById(workspaceId);
37
+ if (!workspace?.computeId)
38
+ return false;
39
+ const appName = `ar-${workspaceId.substring(0, 8)}`;
40
+ const apiToken = process.env.FLY_API_TOKEN;
41
+ if (!apiToken) {
42
+ console.warn('[webhooks] FLY_API_TOKEN not set, cannot wake machine');
43
+ return false;
44
+ }
45
+ try {
46
+ const response = await fetch(`https://api.machines.dev/v1/apps/${appName}/machines/${workspace.computeId}/start`, {
47
+ method: 'POST',
48
+ headers: { Authorization: `Bearer ${apiToken}` },
49
+ });
50
+ if (response.ok) {
51
+ console.log(`[webhooks] Started workspace machine ${workspace.computeId}`);
52
+ // Wait a bit for machine to start
53
+ await new Promise(resolve => setTimeout(resolve, 5000));
54
+ return true;
55
+ }
56
+ // 200 OK means already running
57
+ if (response.status === 200) {
58
+ return true;
59
+ }
60
+ console.warn(`[webhooks] Failed to start machine: ${response.status}`);
61
+ return false;
62
+ }
63
+ catch (error) {
64
+ console.error('[webhooks] Error waking machine:', error);
65
+ return false;
66
+ }
67
+ }
68
+ /**
69
+ * POST /api/webhooks/workspace/:workspaceId/*
70
+ * Forward webhooks to a specific workspace
71
+ *
72
+ * External services can send webhooks to:
73
+ * https://agent-relay.com/api/webhooks/workspace/{workspaceId}/your/path
74
+ *
75
+ * This will be forwarded to:
76
+ * http://{workspace-internal}/webhooks/your/path
77
+ */
78
+ // Handler for workspace webhook forwarding - matches any path under /workspace/:workspaceId
79
+ async function handleWorkspaceWebhook(req, res) {
80
+ // Extract workspaceId from URL path
81
+ const pathMatch = req.originalUrl.match(/\/workspace\/([^/]+)\/?(.*)$/);
82
+ if (!pathMatch) {
83
+ res.status(400).json({ error: 'Invalid workspace webhook URL' });
84
+ return;
85
+ }
86
+ const workspaceId = pathMatch[1];
87
+ const forwardPath = pathMatch[2] || '';
88
+ console.log(`[webhooks] Forwarding to workspace ${workspaceId}: ${req.method} /${forwardPath}`);
89
+ try {
90
+ // Find the workspace
91
+ const workspace = await db.workspaces.findById(workspaceId);
92
+ if (!workspace) {
93
+ res.status(404).json({ error: 'Workspace not found' });
94
+ return;
95
+ }
96
+ if (!workspace.publicUrl) {
97
+ res.status(400).json({ error: 'Workspace has no public URL' });
98
+ return;
99
+ }
100
+ // Try to wake the machine if it might be suspended
101
+ if (workspace.status === 'running' || workspace.status === 'suspended') {
102
+ await wakeWorkspaceMachine(workspaceId);
103
+ }
104
+ // Get internal URL for server-to-server communication
105
+ const internalUrl = getWorkspaceInternalUrl(workspace.publicUrl);
106
+ const targetUrl = `${internalUrl}/webhooks/${forwardPath}`;
107
+ console.log(`[webhooks] Forwarding to: ${targetUrl}`);
108
+ // Forward the request with original headers and body
109
+ const forwardHeaders = {};
110
+ // Copy relevant headers
111
+ const headersToForward = [
112
+ 'content-type',
113
+ 'x-hub-signature-256',
114
+ 'x-hub-signature',
115
+ 'x-github-event',
116
+ 'x-github-delivery',
117
+ 'x-gitlab-token',
118
+ 'x-gitlab-event',
119
+ 'user-agent',
120
+ ];
121
+ for (const header of headersToForward) {
122
+ const value = req.get(header);
123
+ if (value) {
124
+ forwardHeaders[header] = value;
125
+ }
126
+ }
127
+ // Add workspace context header
128
+ forwardHeaders['x-forwarded-for-workspace'] = workspaceId;
129
+ forwardHeaders['x-original-host'] = req.get('host') || '';
130
+ // Get raw body if available, otherwise use JSON stringified body
131
+ const rawBody = req.rawBody || JSON.stringify(req.body);
132
+ const response = await fetch(targetUrl, {
133
+ method: req.method,
134
+ headers: forwardHeaders,
135
+ body: ['GET', 'HEAD'].includes(req.method) ? undefined : rawBody,
136
+ });
137
+ // Forward response back
138
+ const responseBody = await response.text();
139
+ res.status(response.status);
140
+ // Copy response headers
141
+ response.headers.forEach((value, key) => {
142
+ if (!['content-encoding', 'transfer-encoding', 'content-length'].includes(key.toLowerCase())) {
143
+ res.set(key, value);
144
+ }
145
+ });
146
+ res.send(responseBody);
147
+ }
148
+ catch (error) {
149
+ console.error(`[webhooks] Error forwarding to workspace ${workspaceId}:`, error);
150
+ res.status(502).json({
151
+ error: 'Failed to forward webhook to workspace',
152
+ details: error.message,
153
+ });
154
+ }
155
+ }
156
+ // TODO: Re-enable workspace webhook forwarding once route pattern issue is resolved
157
+ // The newer path-to-regexp version doesn't support wildcard patterns like /workspace/*
158
+ // See: https://git.new/pathToRegexpError
159
+ // webhooksRouter.all('/workspace/*', handleWorkspaceWebhook);
11
160
  // GitHub webhook signature verification
12
161
  function verifyGitHubSignature(payload, signature) {
13
162
  if (!signature)
@@ -6,8 +6,9 @@
6
6
  import { Router } from 'express';
7
7
  import { requireAuth } from './auth.js';
8
8
  import { db } from '../db/index.js';
9
- import { getProvisioner } from '../provisioner/index.js';
9
+ import { getProvisioner, getProvisioningStage } from '../provisioner/index.js';
10
10
  import { checkWorkspaceLimit } from './middleware/planLimits.js';
11
+ import { getConfig } from '../config.js';
11
12
  export const workspacesRouter = Router();
12
13
  // All routes require authentication
13
14
  workspacesRouter.use(requireAuth);
@@ -267,7 +268,17 @@ workspacesRouter.get('/:id/status', async (req, res) => {
267
268
  }
268
269
  const provisioner = getProvisioner();
269
270
  const status = await provisioner.getStatus(id);
270
- res.json({ status });
271
+ // Include provisioning progress info if it exists (even after status changes to 'running')
272
+ // This allows the frontend to see all stages including 'complete'
273
+ const provisioningProgress = getProvisioningStage(id);
274
+ res.json({
275
+ status,
276
+ provisioning: provisioningProgress ? {
277
+ stage: provisioningProgress.stage,
278
+ startedAt: provisioningProgress.startedAt,
279
+ elapsedMs: Date.now() - provisioningProgress.startedAt,
280
+ } : null,
281
+ });
271
282
  }
272
283
  catch (error) {
273
284
  console.error('Error getting workspace status:', error);
@@ -376,6 +387,77 @@ workspacesRouter.post('/:id/repos', async (req, res) => {
376
387
  res.status(500).json({ error: 'Failed to add repositories' });
377
388
  }
378
389
  });
390
+ /**
391
+ * POST /api/workspaces/:id/autoscale
392
+ * Trigger auto-scaling based on current agent count
393
+ * Supports both user session auth and workspace token auth
394
+ * Called by workspace container when spawning new agents
395
+ */
396
+ workspacesRouter.post('/:id/autoscale', async (req, res) => {
397
+ const { id } = req.params;
398
+ const { agentCount } = req.body;
399
+ if (typeof agentCount !== 'number' || agentCount < 0) {
400
+ return res.status(400).json({ error: 'agentCount must be a non-negative number' });
401
+ }
402
+ try {
403
+ const workspace = await db.workspaces.findById(id);
404
+ if (!workspace) {
405
+ return res.status(404).json({ error: 'Workspace not found' });
406
+ }
407
+ // Verify auth: either user session or workspace token
408
+ const userId = req.session?.userId;
409
+ const authHeader = req.get('authorization');
410
+ if (userId) {
411
+ // User session auth
412
+ if (workspace.userId !== userId) {
413
+ return res.status(403).json({ error: 'Unauthorized' });
414
+ }
415
+ }
416
+ else if (authHeader?.startsWith('Bearer ')) {
417
+ // Workspace token auth (for calls from within the workspace)
418
+ const crypto = await import('crypto');
419
+ const config = getConfig();
420
+ const providedToken = authHeader.slice(7);
421
+ const expectedToken = crypto.default
422
+ .createHmac('sha256', config.sessionSecret)
423
+ .update(`workspace:${id}`)
424
+ .digest('hex');
425
+ const isValid = crypto.default.timingSafeEqual(Buffer.from(providedToken), Buffer.from(expectedToken));
426
+ if (!isValid) {
427
+ return res.status(401).json({ error: 'Invalid workspace token' });
428
+ }
429
+ }
430
+ else {
431
+ return res.status(401).json({ error: 'Authentication required' });
432
+ }
433
+ const provisioner = getProvisioner();
434
+ const currentTier = await provisioner.getCurrentTier(id);
435
+ const recommendedTier = provisioner.getRecommendedTier(agentCount);
436
+ // Check if scaling is needed
437
+ if (recommendedTier.memoryMb <= currentTier.memoryMb) {
438
+ return res.json({
439
+ scaled: false,
440
+ currentTier: currentTier.name,
441
+ message: 'Current tier is sufficient',
442
+ });
443
+ }
444
+ // Perform the scale-up (respects plan limits)
445
+ const result = await provisioner.autoScale(id, agentCount);
446
+ res.json({
447
+ scaled: result.scaled,
448
+ previousTier: result.currentTier || currentTier.name,
449
+ newTier: result.targetTier || currentTier.name,
450
+ reason: result.reason,
451
+ message: result.scaled
452
+ ? `Scaled up to ${result.targetTier} tier`
453
+ : result.reason || 'Scaling not required',
454
+ });
455
+ }
456
+ catch (error) {
457
+ console.error('Error auto-scaling workspace:', error);
458
+ res.status(500).json({ error: 'Failed to auto-scale workspace' });
459
+ }
460
+ });
379
461
  /**
380
462
  * POST /api/workspaces/:id/domain
381
463
  * Add or update custom domain (Premium feature - Team/Enterprise only)
@@ -424,7 +506,7 @@ workspacesRouter.post('/:id/domain', async (req, res) => {
424
506
  instructions: {
425
507
  type: 'CNAME',
426
508
  name: domain,
427
- value: workspace.publicUrl?.replace('https://', '') || `${id}.agentrelay.dev`,
509
+ value: workspace.publicUrl?.replace('https://', '') || `${id}.agent-relay.com`,
428
510
  ttl: 300,
429
511
  },
430
512
  verifyEndpoint: `/api/workspaces/${id}/domain/verify`,
@@ -458,7 +540,7 @@ workspacesRouter.post('/:id/domain/verify', async (req, res) => {
458
540
  const dns = await import('dns').then(m => m.promises);
459
541
  try {
460
542
  const records = await dns.resolveCname(workspace.customDomain);
461
- const expectedTarget = workspace.publicUrl?.replace('https://', '') || `${id}.agentrelay.dev`;
543
+ const expectedTarget = workspace.publicUrl?.replace('https://', '') || `${id}.agent-relay.com`;
462
544
  if (records.some(r => r.includes(expectedTarget) || r.includes('agentrelay'))) {
463
545
  // DNS is configured, now provision SSL cert
464
546
  await db.workspaces.updateCustomDomainStatus(id, 'verifying');
@@ -600,10 +682,19 @@ workspacesRouter.all('/:id/proxy/{*proxyPath}', async (req, res) => {
600
682
  return res.status(400).json({ error: 'Workspace is not running' });
601
683
  }
602
684
  // Determine the internal URL for proxying
603
- // When running inside Docker, localhost URLs won't work - use the container name instead
685
+ // When running inside Docker or Fly.io, use internal networking
604
686
  let targetBaseUrl = workspace.publicUrl;
605
687
  const runningInDocker = process.env.RUNNING_IN_DOCKER === 'true';
606
- if (runningInDocker && workspace.computeId && targetBaseUrl.includes('localhost')) {
688
+ const runningOnFly = !!process.env.FLY_APP_NAME;
689
+ if (runningOnFly && targetBaseUrl.includes('.fly.dev')) {
690
+ // Use Fly.io internal networking (.internal uses IPv6, works by default)
691
+ // ar-583f273b.fly.dev -> http://ar-583f273b.internal:3888
692
+ const appName = targetBaseUrl.match(/https?:\/\/([^.]+)\.fly\.dev/)?.[1];
693
+ if (appName) {
694
+ targetBaseUrl = `http://${appName}.internal:3888`;
695
+ }
696
+ }
697
+ else if (runningInDocker && workspace.computeId && targetBaseUrl.includes('localhost')) {
607
698
  // Replace localhost URL with container name for Docker networking
608
699
  // workspace.computeId is the container name (e.g., "ar-abc12345")
609
700
  // The workspace port is 3888 inside the container
@@ -10,15 +10,15 @@ export const BILLING_PLANS = {
10
10
  free: {
11
11
  id: 'free',
12
12
  name: 'Free',
13
- description: 'For individuals exploring AI agent workflows',
13
+ description: 'Try AI agent workflows with limited access',
14
14
  priceMonthly: 0,
15
15
  priceYearly: 0,
16
16
  limits: {
17
- maxWorkspaces: 2,
18
- maxAgentsPerWorkspace: 3,
17
+ maxWorkspaces: 1,
18
+ maxAgentsPerWorkspace: 2,
19
19
  maxTeamMembers: 1,
20
20
  maxStorageGB: 1,
21
- maxComputeHoursPerMonth: 10,
21
+ maxComputeHoursPerMonth: 5, // Limited to 5 hours/month
22
22
  customDomains: false,
23
23
  prioritySupport: false,
24
24
  sla: false,
@@ -27,27 +27,27 @@ export const BILLING_PLANS = {
27
27
  sessionPersistence: false,
28
28
  },
29
29
  features: [
30
- 'Up to 2 workspaces',
31
- 'Up to 3 agents per workspace',
32
- '10 compute hours/month',
33
- '1 GB storage',
30
+ '1 workspace',
31
+ 'Up to 2 agents',
32
+ '5 compute hours/month',
33
+ 'Shared CPU (may throttle)',
34
34
  'Community support',
35
35
  ],
36
36
  },
37
37
  pro: {
38
38
  id: 'pro',
39
39
  name: 'Pro',
40
- description: 'For professional developers and small teams',
41
- priceMonthly: 2900, // $29/month
42
- priceYearly: 29000, // $290/year (2 months free)
40
+ description: 'For professional developers building with AI agents',
41
+ priceMonthly: 4900, // $49/month
42
+ priceYearly: 47000, // $470/year (2 months free)
43
43
  stripePriceIdMonthly: process.env.STRIPE_PRO_MONTHLY_PRICE_ID,
44
44
  stripePriceIdYearly: process.env.STRIPE_PRO_YEARLY_PRICE_ID,
45
45
  limits: {
46
- maxWorkspaces: 10,
47
- maxAgentsPerWorkspace: 10,
48
- maxTeamMembers: 5,
46
+ maxWorkspaces: 5,
47
+ maxAgentsPerWorkspace: 5,
48
+ maxTeamMembers: 3,
49
49
  maxStorageGB: 10,
50
- maxComputeHoursPerMonth: 100,
50
+ maxComputeHoursPerMonth: 50,
51
51
  customDomains: true,
52
52
  prioritySupport: false,
53
53
  sla: false,
@@ -56,11 +56,11 @@ export const BILLING_PLANS = {
56
56
  sessionPersistence: true,
57
57
  },
58
58
  features: [
59
- 'Up to 10 workspaces',
60
- 'Up to 10 agents per workspace',
61
- '100 compute hours/month',
59
+ 'Up to 5 workspaces',
60
+ 'Up to 5 agents per workspace',
61
+ '50 compute hours/month',
62
62
  '10 GB storage',
63
- '5 team members',
63
+ '3 team members',
64
64
  'Custom domains',
65
65
  'Session persistence',
66
66
  'Email support',
@@ -4,6 +4,16 @@
4
4
  * One-click provisioning for compute resources (Fly.io, Railway, Docker).
5
5
  */
6
6
  import { Workspace } from '../db/index.js';
7
+ export type ProvisioningStage = 'creating' | 'networking' | 'secrets' | 'machine' | 'booting' | 'health' | 'complete';
8
+ interface ProvisioningProgress {
9
+ stage: ProvisioningStage;
10
+ startedAt: number;
11
+ updatedAt: number;
12
+ }
13
+ /**
14
+ * Get the current provisioning stage for a workspace
15
+ */
16
+ export declare function getProvisioningStage(workspaceId: string): ProvisioningProgress | null;
7
17
  export interface ProvisionConfig {
8
18
  userId: string;
9
19
  name: string;
@@ -30,6 +40,7 @@ export interface ResourceTier {
30
40
  cpuCores: number;
31
41
  memoryMb: number;
32
42
  maxAgents: number;
43
+ cpuKind: 'shared' | 'performance';
33
44
  }
34
45
  export declare const RESOURCE_TIERS: Record<string, ResourceTier>;
35
46
  /**
@@ -40,8 +51,13 @@ export declare class WorkspaceProvisioner {
40
51
  constructor();
41
52
  /**
42
53
  * Provision a new workspace (one-click)
54
+ * Returns immediately with 'provisioning' status and runs actual provisioning in background
43
55
  */
44
56
  provision(config: ProvisionConfig): Promise<ProvisionResult>;
57
+ /**
58
+ * Run the actual provisioning work asynchronously
59
+ */
60
+ private runProvisioningAsync;
45
61
  /**
46
62
  * Deprovision a workspace
47
63
  */
@@ -70,6 +86,22 @@ export declare class WorkspaceProvisioner {
70
86
  * Get current resource tier for a workspace
71
87
  */
72
88
  getCurrentTier(workspaceId: string): Promise<ResourceTier>;
89
+ /**
90
+ * Get recommended tier based on agent count
91
+ * Uses 1.5-2GB per agent as baseline for Claude Code
92
+ */
93
+ getRecommendedTier(agentCount: number): ResourceTier;
94
+ /**
95
+ * Auto-scale workspace based on current agent count
96
+ * Respects plan limits - free tier cannot scale, others have max tier limits
97
+ * Returns { scaled: boolean, reason?: string }
98
+ */
99
+ autoScale(workspaceId: string, currentAgentCount: number): Promise<{
100
+ scaled: boolean;
101
+ reason?: string;
102
+ currentTier?: string;
103
+ targetTier?: string;
104
+ }>;
73
105
  }
74
106
  export declare function getProvisioner(): WorkspaceProvisioner;
75
107
  //# sourceMappingURL=index.d.ts.map