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.
- package/.gitattributes +3 -0
- package/.nvmrc +1 -0
- package/.trajectories/completed/2026-01/traj_1dviorhnkcb5.json +65 -0
- package/.trajectories/completed/2026-01/traj_1dviorhnkcb5.md +37 -0
- package/.trajectories/completed/2026-01/traj_1k5if5snst2e.json +65 -0
- package/.trajectories/completed/2026-01/traj_1k5if5snst2e.md +37 -0
- package/.trajectories/completed/2026-01/traj_1rp3rges5811.json +49 -0
- package/.trajectories/completed/2026-01/traj_1rp3rges5811.md +31 -0
- package/.trajectories/completed/2026-01/traj_22bhyulruouw.json +113 -0
- package/.trajectories/completed/2026-01/traj_22bhyulruouw.md +57 -0
- package/.trajectories/completed/2026-01/traj_2dao7ddgnta0.json +53 -0
- package/.trajectories/completed/2026-01/traj_2dao7ddgnta0.md +32 -0
- package/.trajectories/completed/2026-01/traj_3t0440mjeunc.json +26 -0
- package/.trajectories/completed/2026-01/traj_3t0440mjeunc.md +6 -0
- package/.trajectories/completed/2026-01/traj_45x9494d9xnr.json +47 -0
- package/.trajectories/completed/2026-01/traj_45x9494d9xnr.md +32 -0
- package/.trajectories/completed/2026-01/traj_4aa0bb77s4nh.json +53 -0
- package/.trajectories/completed/2026-01/traj_4aa0bb77s4nh.md +32 -0
- package/.trajectories/completed/2026-01/traj_5lhmzq8rxpqv.json +59 -0
- package/.trajectories/completed/2026-01/traj_5lhmzq8rxpqv.md +33 -0
- package/.trajectories/completed/2026-01/traj_5vr4e9erb1fs.json +53 -0
- package/.trajectories/completed/2026-01/traj_5vr4e9erb1fs.md +32 -0
- package/.trajectories/completed/2026-01/traj_6fgiwdoklvym.json +48 -0
- package/.trajectories/completed/2026-01/traj_6fgiwdoklvym.md +24 -0
- package/.trajectories/completed/2026-01/traj_7ludwvz45veh.json +209 -0
- package/.trajectories/completed/2026-01/traj_7ludwvz45veh.md +97 -0
- package/.trajectories/completed/2026-01/traj_9921cuhel0pj.json +48 -0
- package/.trajectories/completed/2026-01/traj_9921cuhel0pj.md +24 -0
- package/.trajectories/completed/2026-01/traj_ajs7zqfux4wc.json +49 -0
- package/.trajectories/completed/2026-01/traj_ajs7zqfux4wc.md +23 -0
- package/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.json +53 -0
- package/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.md +32 -0
- package/.trajectories/completed/2026-01/traj_cxofprm2m2en.json +49 -0
- package/.trajectories/completed/2026-01/traj_cxofprm2m2en.md +31 -0
- package/.trajectories/completed/2026-01/traj_d2hhz3k0vrhn.json +26 -0
- package/.trajectories/completed/2026-01/traj_d2hhz3k0vrhn.md +6 -0
- package/.trajectories/completed/2026-01/traj_dfuvww9pege5.json +59 -0
- package/.trajectories/completed/2026-01/traj_dfuvww9pege5.md +37 -0
- package/.trajectories/completed/2026-01/traj_g0fisy9h51mf.json +77 -0
- package/.trajectories/completed/2026-01/traj_g0fisy9h51mf.md +42 -0
- package/.trajectories/completed/2026-01/traj_gjdre5voouod.json +53 -0
- package/.trajectories/completed/2026-01/traj_gjdre5voouod.md +32 -0
- package/.trajectories/completed/2026-01/traj_gtlyqtta3x8l.json +25 -0
- package/.trajectories/completed/2026-01/traj_gtlyqtta3x8l.md +15 -0
- package/.trajectories/completed/2026-01/traj_h4xijiuip3w4.json +101 -0
- package/.trajectories/completed/2026-01/traj_h4xijiuip3w4.md +44 -0
- package/.trajectories/completed/2026-01/traj_hhxte7w4gjjx.json +22 -0
- package/.trajectories/completed/2026-01/traj_hhxte7w4gjjx.md +5 -0
- package/.trajectories/completed/2026-01/traj_hpungyhoj6v5.json +53 -0
- package/.trajectories/completed/2026-01/traj_hpungyhoj6v5.md +32 -0
- package/.trajectories/completed/2026-01/traj_m2xkjv0w2sq7.json +25 -0
- package/.trajectories/completed/2026-01/traj_m2xkjv0w2sq7.md +15 -0
- package/.trajectories/completed/2026-01/traj_noq5zbvnrdvz.json +53 -0
- package/.trajectories/completed/2026-01/traj_noq5zbvnrdvz.md +32 -0
- package/.trajectories/completed/2026-01/traj_ntbs6ppopf46.json +53 -0
- package/.trajectories/completed/2026-01/traj_ntbs6ppopf46.md +32 -0
- package/.trajectories/completed/2026-01/traj_ozd98si6a7ns.json +48 -0
- package/.trajectories/completed/2026-01/traj_ozd98si6a7ns.md +24 -0
- package/.trajectories/completed/2026-01/traj_prdza7a5cxp5.json +53 -0
- package/.trajectories/completed/2026-01/traj_prdza7a5cxp5.md +32 -0
- package/.trajectories/completed/2026-01/traj_qb3twvvywfwi.json +77 -0
- package/.trajectories/completed/2026-01/traj_qb3twvvywfwi.md +42 -0
- package/.trajectories/completed/2026-01/traj_qft54mi7nfor.json +53 -0
- package/.trajectories/completed/2026-01/traj_qft54mi7nfor.md +32 -0
- package/.trajectories/completed/2026-01/traj_qx9uhf8whhxo.json +83 -0
- package/.trajectories/completed/2026-01/traj_qx9uhf8whhxo.md +47 -0
- package/.trajectories/completed/2026-01/traj_rd9toccj18a0.json +59 -0
- package/.trajectories/completed/2026-01/traj_rd9toccj18a0.md +37 -0
- package/.trajectories/completed/2026-01/traj_rt4fiw3ecp50.json +48 -0
- package/.trajectories/completed/2026-01/traj_rt4fiw3ecp50.md +16 -0
- package/.trajectories/completed/2026-01/traj_st8j35b0hrlc.json +59 -0
- package/.trajectories/completed/2026-01/traj_st8j35b0hrlc.md +37 -0
- package/.trajectories/completed/2026-01/traj_t1yy8m7hbuxp.json +53 -0
- package/.trajectories/completed/2026-01/traj_t1yy8m7hbuxp.md +32 -0
- package/.trajectories/completed/2026-01/traj_tmux_orchestrator_analysis.json +84 -0
- package/.trajectories/completed/2026-01/traj_tmux_orchestrator_analysis.md +109 -0
- package/.trajectories/completed/2026-01/traj_u9n9eqasw16k.json +53 -0
- package/.trajectories/completed/2026-01/traj_u9n9eqasw16k.md +32 -0
- package/.trajectories/completed/2026-01/traj_v87hypnongqx.json +71 -0
- package/.trajectories/completed/2026-01/traj_v87hypnongqx.md +42 -0
- package/.trajectories/completed/2026-01/traj_wkp2fgzdyinb.json +53 -0
- package/.trajectories/completed/2026-01/traj_wkp2fgzdyinb.md +32 -0
- package/.trajectories/completed/2026-01/traj_x14t8w8rn7xg.json +20 -0
- package/.trajectories/completed/2026-01/traj_x14t8w8rn7xg.md +6 -0
- package/.trajectories/completed/2026-01/traj_xnwbznkvv8ua.json +175 -0
- package/.trajectories/completed/2026-01/traj_xnwbznkvv8ua.md +82 -0
- package/.trajectories/completed/2026-01/traj_ysjc8zaeqtd3.json +47 -0
- package/.trajectories/completed/2026-01/traj_ysjc8zaeqtd3.md +32 -0
- package/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.json +59 -0
- package/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.md +37 -0
- package/.trajectories/completed/2026-01/traj_z0vcw1wrzide.json +53 -0
- package/.trajectories/completed/2026-01/traj_z0vcw1wrzide.md +32 -0
- package/.trajectories/index.json +314 -0
- package/ARCHITECTURE.md +1245 -0
- package/TESTING.md +278 -0
- package/deploy/init-db.sql +5 -0
- package/deploy/scripts/setup-fly-workspaces.sh +69 -0
- package/deploy/scripts/setup-railway.sh +75 -0
- package/deploy/workspace/entrypoint-browser.sh +118 -0
- package/deploy/workspace/entrypoint.sh +348 -0
- package/deploy/workspace/git-credential-relay +111 -0
- package/dist/cli/index.js +218 -1
- package/dist/cloud/api/billing.js +30 -9
- package/dist/cloud/api/codex-auth-helper.d.ts +15 -0
- package/dist/cloud/api/codex-auth-helper.js +100 -0
- package/dist/cloud/api/git.js +24 -3
- package/dist/cloud/api/onboarding.js +15 -2
- package/dist/cloud/api/repos.d.ts +1 -0
- package/dist/cloud/api/repos.js +186 -0
- package/dist/cloud/api/webhooks.d.ts +1 -0
- package/dist/cloud/api/webhooks.js +149 -0
- package/dist/cloud/api/workspaces.js +97 -6
- package/dist/cloud/billing/plans.js +19 -19
- package/dist/cloud/provisioner/index.d.ts +32 -0
- package/dist/cloud/provisioner/index.js +362 -21
- package/dist/cloud/server.js +6 -1
- package/dist/cloud/services/nango.d.ts +60 -0
- package/dist/cloud/services/nango.js +153 -0
- package/dist/cloud/services/planLimits.d.ts +22 -0
- package/dist/cloud/services/planLimits.js +58 -5
- package/dist/dashboard/out/404.html +1 -1
- package/dist/dashboard/out/_next/static/chunks/699-3b1cd6618a45d259.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/766-1f2dd8cb7f766b0b.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/onboarding/page-3fdfa60e53f2810d.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/page-e6381e5a6e1fbcfd.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/connect-repos/page-3538dfe0ffe984b8.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/history/{page-56a8b4616a90dc43.js → page-abb9ab2d329f56e9.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/app/layout-c0d118c0f92d969c.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/login/{page-3eac37ea6f5dd153.js → page-c22d080201cbd9fb.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/app/metrics/{page-1081dd190a331a91.js → page-67a3e98d9a43a6ed.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/app/{page-daf87e86f783f980.js → page-77e9c65420a06cfb.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/app/pricing/page-b08ed1c34d14434a.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/providers/page-e88bc117ef7671c3.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/signup/{page-fee4ed1709070bcd.js → page-68d34f50baa8ab6b.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/{main-app-5d692157a8eb1fd9.js → main-app-6e8e8d3ef4e0192a.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/{main-97850e03d723ea8c.js → main-ed4e1fb6f29c34cf.js} +1 -1
- package/dist/dashboard/out/_next/static/css/7c3ae9e8617d42a5.css +1 -0
- package/dist/dashboard/out/app/onboarding.html +1 -0
- package/dist/dashboard/out/app/onboarding.txt +7 -0
- package/dist/dashboard/out/app.html +1 -1
- package/dist/dashboard/out/app.txt +2 -2
- package/dist/dashboard/out/connect-repos.html +1 -1
- package/dist/dashboard/out/connect-repos.txt +2 -2
- package/dist/dashboard/out/history.html +1 -1
- package/dist/dashboard/out/history.txt +2 -2
- package/dist/dashboard/out/index.html +1 -1
- package/dist/dashboard/out/index.txt +2 -2
- package/dist/dashboard/out/login.html +2 -2
- package/dist/dashboard/out/login.txt +2 -2
- package/dist/dashboard/out/metrics.html +1 -1
- package/dist/dashboard/out/metrics.txt +2 -2
- package/dist/dashboard/out/pricing.html +3 -3
- package/dist/dashboard/out/pricing.txt +2 -2
- package/dist/dashboard/out/providers.html +1 -1
- package/dist/dashboard/out/providers.txt +2 -2
- package/dist/dashboard/out/signup.html +2 -2
- package/dist/dashboard/out/signup.txt +2 -2
- package/package.json +2 -11
- package/test-push.txt +1 -0
- package/bin/tmux +0 -0
- package/dist/bridge/config.d.ts.map +0 -1
- package/dist/bridge/config.js.map +0 -1
- package/dist/bridge/index.d.ts.map +0 -1
- package/dist/bridge/index.js.map +0 -1
- package/dist/bridge/multi-project-client.d.ts.map +0 -1
- package/dist/bridge/multi-project-client.js.map +0 -1
- package/dist/bridge/shadow-cli.d.ts.map +0 -1
- package/dist/bridge/shadow-cli.js.map +0 -1
- package/dist/bridge/shadow-config.d.ts.map +0 -1
- package/dist/bridge/shadow-config.js.map +0 -1
- package/dist/bridge/spawner.d.ts.map +0 -1
- package/dist/bridge/spawner.js.map +0 -1
- package/dist/bridge/teams-config.d.ts.map +0 -1
- package/dist/bridge/teams-config.js.map +0 -1
- package/dist/bridge/types.d.ts.map +0 -1
- package/dist/bridge/types.js.map +0 -1
- package/dist/bridge/utils.d.ts.map +0 -1
- package/dist/bridge/utils.js.map +0 -1
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js.map +0 -1
- package/dist/cloud/api/auth.d.ts.map +0 -1
- package/dist/cloud/api/auth.js.map +0 -1
- package/dist/cloud/api/billing.d.ts.map +0 -1
- package/dist/cloud/api/billing.js.map +0 -1
- package/dist/cloud/api/cli-pty-runner.d.ts.map +0 -1
- package/dist/cloud/api/cli-pty-runner.js.map +0 -1
- package/dist/cloud/api/coordinators.d.ts.map +0 -1
- package/dist/cloud/api/coordinators.js.map +0 -1
- package/dist/cloud/api/daemons.d.ts.map +0 -1
- package/dist/cloud/api/daemons.js.map +0 -1
- package/dist/cloud/api/generic-webhooks.d.ts.map +0 -1
- package/dist/cloud/api/generic-webhooks.js.map +0 -1
- package/dist/cloud/api/git.d.ts.map +0 -1
- package/dist/cloud/api/git.js.map +0 -1
- package/dist/cloud/api/github-app.d.ts.map +0 -1
- package/dist/cloud/api/github-app.js.map +0 -1
- package/dist/cloud/api/middleware/planLimits.d.ts.map +0 -1
- package/dist/cloud/api/middleware/planLimits.js.map +0 -1
- package/dist/cloud/api/monitoring.d.ts.map +0 -1
- package/dist/cloud/api/monitoring.js.map +0 -1
- package/dist/cloud/api/nango-auth.d.ts.map +0 -1
- package/dist/cloud/api/nango-auth.js.map +0 -1
- package/dist/cloud/api/onboarding.d.ts.map +0 -1
- package/dist/cloud/api/onboarding.js.map +0 -1
- package/dist/cloud/api/policy.d.ts.map +0 -1
- package/dist/cloud/api/policy.js.map +0 -1
- package/dist/cloud/api/providers.d.ts.map +0 -1
- package/dist/cloud/api/providers.js.map +0 -1
- package/dist/cloud/api/repos.d.ts.map +0 -1
- package/dist/cloud/api/repos.js.map +0 -1
- package/dist/cloud/api/teams.d.ts.map +0 -1
- package/dist/cloud/api/teams.js.map +0 -1
- package/dist/cloud/api/test-helpers.d.ts.map +0 -1
- package/dist/cloud/api/test-helpers.js.map +0 -1
- package/dist/cloud/api/usage.d.ts.map +0 -1
- package/dist/cloud/api/usage.js.map +0 -1
- package/dist/cloud/api/webhooks.d.ts.map +0 -1
- package/dist/cloud/api/webhooks.js.map +0 -1
- package/dist/cloud/api/workspaces.d.ts.map +0 -1
- package/dist/cloud/api/workspaces.js.map +0 -1
- package/dist/cloud/billing/index.d.ts.map +0 -1
- package/dist/cloud/billing/index.js.map +0 -1
- package/dist/cloud/billing/plans.d.ts.map +0 -1
- package/dist/cloud/billing/plans.js.map +0 -1
- package/dist/cloud/billing/service.d.ts.map +0 -1
- package/dist/cloud/billing/service.js.map +0 -1
- package/dist/cloud/billing/types.d.ts.map +0 -1
- package/dist/cloud/billing/types.js.map +0 -1
- package/dist/cloud/config.d.ts.map +0 -1
- package/dist/cloud/config.js.map +0 -1
- package/dist/cloud/db/drizzle.d.ts.map +0 -1
- package/dist/cloud/db/drizzle.js.map +0 -1
- package/dist/cloud/db/index.d.ts.map +0 -1
- package/dist/cloud/db/index.js.map +0 -1
- package/dist/cloud/db/schema.d.ts.map +0 -1
- package/dist/cloud/db/schema.js.map +0 -1
- package/dist/cloud/index.d.ts.map +0 -1
- package/dist/cloud/index.js.map +0 -1
- package/dist/cloud/provisioner/index.d.ts.map +0 -1
- package/dist/cloud/provisioner/index.js.map +0 -1
- package/dist/cloud/server.d.ts.map +0 -1
- package/dist/cloud/server.js.map +0 -1
- package/dist/cloud/services/auto-scaler.d.ts.map +0 -1
- package/dist/cloud/services/auto-scaler.js.map +0 -1
- package/dist/cloud/services/capacity-manager.d.ts.map +0 -1
- package/dist/cloud/services/capacity-manager.js.map +0 -1
- package/dist/cloud/services/ci-agent-spawner.d.ts.map +0 -1
- package/dist/cloud/services/ci-agent-spawner.js.map +0 -1
- package/dist/cloud/services/coordinator.d.ts.map +0 -1
- package/dist/cloud/services/coordinator.js.map +0 -1
- package/dist/cloud/services/index.d.ts.map +0 -1
- package/dist/cloud/services/index.js.map +0 -1
- package/dist/cloud/services/mention-handler.d.ts.map +0 -1
- package/dist/cloud/services/mention-handler.js.map +0 -1
- package/dist/cloud/services/nango.d.ts.map +0 -1
- package/dist/cloud/services/nango.js.map +0 -1
- package/dist/cloud/services/persistence.d.ts.map +0 -1
- package/dist/cloud/services/persistence.js.map +0 -1
- package/dist/cloud/services/planLimits.d.ts.map +0 -1
- package/dist/cloud/services/planLimits.js.map +0 -1
- package/dist/cloud/services/scaling-orchestrator.d.ts.map +0 -1
- package/dist/cloud/services/scaling-orchestrator.js.map +0 -1
- package/dist/cloud/services/scaling-policy.d.ts.map +0 -1
- package/dist/cloud/services/scaling-policy.js.map +0 -1
- package/dist/cloud/vault/index.d.ts.map +0 -1
- package/dist/cloud/vault/index.js.map +0 -1
- package/dist/cloud/webhooks/index.d.ts.map +0 -1
- package/dist/cloud/webhooks/index.js.map +0 -1
- package/dist/cloud/webhooks/parsers/github.d.ts.map +0 -1
- package/dist/cloud/webhooks/parsers/github.js.map +0 -1
- package/dist/cloud/webhooks/parsers/index.d.ts.map +0 -1
- package/dist/cloud/webhooks/parsers/index.js.map +0 -1
- package/dist/cloud/webhooks/parsers/linear.d.ts.map +0 -1
- package/dist/cloud/webhooks/parsers/linear.js.map +0 -1
- package/dist/cloud/webhooks/parsers/slack.d.ts.map +0 -1
- package/dist/cloud/webhooks/parsers/slack.js.map +0 -1
- package/dist/cloud/webhooks/responders/github.d.ts.map +0 -1
- package/dist/cloud/webhooks/responders/github.js.map +0 -1
- package/dist/cloud/webhooks/responders/index.d.ts.map +0 -1
- package/dist/cloud/webhooks/responders/index.js.map +0 -1
- package/dist/cloud/webhooks/responders/linear.d.ts.map +0 -1
- package/dist/cloud/webhooks/responders/linear.js.map +0 -1
- package/dist/cloud/webhooks/responders/slack.d.ts.map +0 -1
- package/dist/cloud/webhooks/responders/slack.js.map +0 -1
- package/dist/cloud/webhooks/router.d.ts.map +0 -1
- package/dist/cloud/webhooks/router.js.map +0 -1
- package/dist/cloud/webhooks/rules-engine.d.ts.map +0 -1
- package/dist/cloud/webhooks/rules-engine.js.map +0 -1
- package/dist/cloud/webhooks/types.d.ts.map +0 -1
- package/dist/cloud/webhooks/types.js.map +0 -1
- package/dist/continuity/formatter.d.ts.map +0 -1
- package/dist/continuity/formatter.js.map +0 -1
- package/dist/continuity/handoff-store.d.ts.map +0 -1
- package/dist/continuity/handoff-store.js.map +0 -1
- package/dist/continuity/index.d.ts.map +0 -1
- package/dist/continuity/index.js.map +0 -1
- package/dist/continuity/ledger-store.d.ts.map +0 -1
- package/dist/continuity/ledger-store.js.map +0 -1
- package/dist/continuity/manager.d.ts.map +0 -1
- package/dist/continuity/manager.js.map +0 -1
- package/dist/continuity/parser.d.ts.map +0 -1
- package/dist/continuity/parser.js.map +0 -1
- package/dist/continuity/types.d.ts.map +0 -1
- package/dist/continuity/types.js.map +0 -1
- package/dist/daemon/agent-manager.d.ts.map +0 -1
- package/dist/daemon/agent-manager.js.map +0 -1
- package/dist/daemon/agent-registry.d.ts.map +0 -1
- package/dist/daemon/agent-registry.js.map +0 -1
- package/dist/daemon/api.d.ts.map +0 -1
- package/dist/daemon/api.js.map +0 -1
- package/dist/daemon/auth.d.ts.map +0 -1
- package/dist/daemon/auth.js.map +0 -1
- package/dist/daemon/cli-auth.d.ts.map +0 -1
- package/dist/daemon/cli-auth.js.map +0 -1
- package/dist/daemon/cloud-sync.d.ts.map +0 -1
- package/dist/daemon/cloud-sync.js.map +0 -1
- package/dist/daemon/connection.d.ts.map +0 -1
- package/dist/daemon/connection.js.map +0 -1
- package/dist/daemon/index.d.ts.map +0 -1
- package/dist/daemon/index.js.map +0 -1
- package/dist/daemon/orchestrator.d.ts.map +0 -1
- package/dist/daemon/orchestrator.js.map +0 -1
- package/dist/daemon/registry.d.ts.map +0 -1
- package/dist/daemon/registry.js.map +0 -1
- package/dist/daemon/router.d.ts.map +0 -1
- package/dist/daemon/router.js.map +0 -1
- package/dist/daemon/server.d.ts.map +0 -1
- package/dist/daemon/server.js.map +0 -1
- package/dist/daemon/services/browser-testing.d.ts.map +0 -1
- package/dist/daemon/services/browser-testing.js.map +0 -1
- package/dist/daemon/services/container-spawner.d.ts.map +0 -1
- package/dist/daemon/services/container-spawner.js.map +0 -1
- package/dist/daemon/types.d.ts.map +0 -1
- package/dist/daemon/types.js.map +0 -1
- package/dist/daemon/workspace-manager.d.ts.map +0 -1
- package/dist/daemon/workspace-manager.js.map +0 -1
- package/dist/dashboard/out/_next/static/chunks/480-2d4111711d4e473c.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/766-c3a14283c88d815b.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/app/page-7120be68bea622f3.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/connect-repos/page-dc2e3a1a22478efc.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/layout-2433bb48965f4333.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/pricing/page-4d72d5a5d8a9b618.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/providers/page-b68a681526eb145e.js +0 -1
- package/dist/dashboard/out/_next/static/css/411ce23ffeae9f76.css +0 -1
- package/dist/dashboard-server/metrics.d.ts.map +0 -1
- package/dist/dashboard-server/metrics.js.map +0 -1
- package/dist/dashboard-server/needs-attention.d.ts.map +0 -1
- package/dist/dashboard-server/needs-attention.js.map +0 -1
- package/dist/dashboard-server/server.d.ts.map +0 -1
- package/dist/dashboard-server/server.js.map +0 -1
- package/dist/dashboard-server/start.d.ts.map +0 -1
- package/dist/dashboard-server/start.js.map +0 -1
- package/dist/hooks/emitter.d.ts.map +0 -1
- package/dist/hooks/emitter.js.map +0 -1
- package/dist/hooks/inbox-check/hook.d.ts.map +0 -1
- package/dist/hooks/inbox-check/hook.js.map +0 -1
- package/dist/hooks/inbox-check/index.d.ts.map +0 -1
- package/dist/hooks/inbox-check/index.js.map +0 -1
- package/dist/hooks/inbox-check/types.d.ts.map +0 -1
- package/dist/hooks/inbox-check/types.js.map +0 -1
- package/dist/hooks/inbox-check/utils.d.ts.map +0 -1
- package/dist/hooks/inbox-check/utils.js.map +0 -1
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/hooks/index.js.map +0 -1
- package/dist/hooks/registry.d.ts.map +0 -1
- package/dist/hooks/registry.js.map +0 -1
- package/dist/hooks/trajectory-hooks.d.ts.map +0 -1
- package/dist/hooks/trajectory-hooks.js.map +0 -1
- package/dist/hooks/types.d.ts.map +0 -1
- package/dist/hooks/types.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/memory/adapters/index.d.ts.map +0 -1
- package/dist/memory/adapters/index.js.map +0 -1
- package/dist/memory/adapters/inmemory.d.ts.map +0 -1
- package/dist/memory/adapters/inmemory.js.map +0 -1
- package/dist/memory/adapters/supermemory.d.ts.map +0 -1
- package/dist/memory/adapters/supermemory.js.map +0 -1
- package/dist/memory/factory.d.ts.map +0 -1
- package/dist/memory/factory.js.map +0 -1
- package/dist/memory/index.d.ts.map +0 -1
- package/dist/memory/index.js.map +0 -1
- package/dist/memory/memory-hooks.d.ts.map +0 -1
- package/dist/memory/memory-hooks.js.map +0 -1
- package/dist/memory/service.d.ts.map +0 -1
- package/dist/memory/service.js.map +0 -1
- package/dist/memory/types.d.ts.map +0 -1
- package/dist/memory/types.js.map +0 -1
- package/dist/policy/agent-policy.d.ts.map +0 -1
- package/dist/policy/agent-policy.js.map +0 -1
- package/dist/policy/cloud-policy-fetcher.d.ts.map +0 -1
- package/dist/policy/cloud-policy-fetcher.js.map +0 -1
- package/dist/protocol/framing.d.ts.map +0 -1
- package/dist/protocol/framing.js.map +0 -1
- package/dist/protocol/index.d.ts.map +0 -1
- package/dist/protocol/index.js.map +0 -1
- package/dist/protocol/types.d.ts.map +0 -1
- package/dist/protocol/types.js.map +0 -1
- package/dist/resiliency/context-persistence.d.ts.map +0 -1
- package/dist/resiliency/context-persistence.js.map +0 -1
- package/dist/resiliency/crash-insights.d.ts.map +0 -1
- package/dist/resiliency/crash-insights.js.map +0 -1
- package/dist/resiliency/gossip-health.d.ts.map +0 -1
- package/dist/resiliency/gossip-health.js.map +0 -1
- package/dist/resiliency/health-monitor.d.ts.map +0 -1
- package/dist/resiliency/health-monitor.js.map +0 -1
- package/dist/resiliency/index.d.ts.map +0 -1
- package/dist/resiliency/index.js.map +0 -1
- package/dist/resiliency/leader-watchdog.d.ts.map +0 -1
- package/dist/resiliency/leader-watchdog.js.map +0 -1
- package/dist/resiliency/logger.d.ts.map +0 -1
- package/dist/resiliency/logger.js.map +0 -1
- package/dist/resiliency/memory-monitor.d.ts.map +0 -1
- package/dist/resiliency/memory-monitor.js.map +0 -1
- package/dist/resiliency/metrics.d.ts.map +0 -1
- package/dist/resiliency/metrics.js.map +0 -1
- package/dist/resiliency/provider-context.d.ts.map +0 -1
- package/dist/resiliency/provider-context.js.map +0 -1
- package/dist/resiliency/stateless-lead.d.ts.map +0 -1
- package/dist/resiliency/stateless-lead.js.map +0 -1
- package/dist/resiliency/supervisor.d.ts.map +0 -1
- package/dist/resiliency/supervisor.js.map +0 -1
- package/dist/shared/cli-auth-config.d.ts.map +0 -1
- package/dist/shared/cli-auth-config.js.map +0 -1
- package/dist/state/agent-state.d.ts.map +0 -1
- package/dist/state/agent-state.js.map +0 -1
- package/dist/storage/adapter.d.ts.map +0 -1
- package/dist/storage/adapter.js.map +0 -1
- package/dist/storage/sqlite-adapter.d.ts.map +0 -1
- package/dist/storage/sqlite-adapter.js.map +0 -1
- package/dist/trajectory/config.d.ts.map +0 -1
- package/dist/trajectory/config.js.map +0 -1
- package/dist/trajectory/index.d.ts.map +0 -1
- package/dist/trajectory/index.js.map +0 -1
- package/dist/trajectory/integration.d.ts.map +0 -1
- package/dist/trajectory/integration.js.map +0 -1
- package/dist/utils/agent-config.d.ts.map +0 -1
- package/dist/utils/agent-config.js.map +0 -1
- package/dist/utils/command-resolver.d.ts.map +0 -1
- package/dist/utils/command-resolver.js.map +0 -1
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/name-generator.d.ts.map +0 -1
- package/dist/utils/name-generator.js.map +0 -1
- package/dist/utils/project-namespace.d.ts.map +0 -1
- package/dist/utils/project-namespace.js.map +0 -1
- package/dist/utils/tmux-resolver.d.ts.map +0 -1
- package/dist/utils/tmux-resolver.js.map +0 -1
- package/dist/utils/update-checker.d.ts.map +0 -1
- package/dist/utils/update-checker.js.map +0 -1
- package/dist/wrapper/client.d.ts.map +0 -1
- package/dist/wrapper/client.js.map +0 -1
- package/dist/wrapper/inbox.d.ts.map +0 -1
- package/dist/wrapper/inbox.js.map +0 -1
- package/dist/wrapper/index.d.ts.map +0 -1
- package/dist/wrapper/index.js.map +0 -1
- package/dist/wrapper/parser.d.ts.map +0 -1
- package/dist/wrapper/parser.js.map +0 -1
- package/dist/wrapper/pty-wrapper.d.ts.map +0 -1
- package/dist/wrapper/pty-wrapper.js.map +0 -1
- package/dist/wrapper/shared.d.ts.map +0 -1
- package/dist/wrapper/shared.js.map +0 -1
- package/dist/wrapper/tmux-wrapper.d.ts.map +0 -1
- package/dist/wrapper/tmux-wrapper.js.map +0 -1
- package/docs/AGENTS.md +0 -513
- package/docs/ARCHITECTURE_DECISIONS.md +0 -175
- package/docs/CLOUD-ARCHITECTURE.md +0 -804
- package/docs/CLOUD-ONBOARDING-DESIGN.md +0 -1983
- package/docs/CONTRIBUTING.md +0 -151
- package/docs/HOOKS_API.md +0 -394
- package/docs/INTEGRATION-GUIDE.md +0 -926
- package/docs/PROTOCOL.md +0 -325
- package/docs/WRAPPER_EVENTS.md +0 -358
- package/docs/agent-policy-snippet.md +0 -40
- package/docs/agent-relay-protocol.md +0 -238
- package/docs/agent-relay-snippet.md +0 -174
- package/docs/archive/CHANGELOG.md +0 -11
- package/docs/archive/CLI-SIMPLIFICATION-COMPLETE.md +0 -48
- package/docs/archive/DESIGN_BRIDGE_STAFFING.md +0 -878
- package/docs/archive/DESIGN_V2.md +0 -1079
- package/docs/archive/EXECUTIVE_SUMMARY.md +0 -358
- package/docs/archive/MONETIZATION.md +0 -1679
- package/docs/archive/PROPOSAL-trajectories.md +0 -1582
- package/docs/archive/ROADMAP.md +0 -329
- package/docs/archive/SCALING_ANALYSIS.md +0 -280
- package/docs/archive/TESTING_PRESENCE_FEATURES.md +0 -327
- package/docs/archive/TMUX_IMPLEMENTATION_NOTES.md +0 -364
- package/docs/archive/TMUX_IMPROVEMENTS.md +0 -968
- package/docs/archive/dashboard-v2-plan.md +0 -179
- package/docs/archive/removable-code-analysis.md +0 -24
- package/docs/competitive/GASTOWN.md +0 -451
- package/docs/competitive/MCP_AGENT_MAIL.md +0 -389
- package/docs/competitive/OVERVIEW.md +0 -898
- package/docs/competitive/README.md +0 -34
- package/docs/competitive/TMUX_ORCHESTRATOR.md +0 -605
- package/docs/dashboard.png +0 -0
- package/docs/design/ci-failure-webhooks.md +0 -812
- package/docs/design/comprehensive-integrations.md +0 -238
- package/docs/design/e2b-sandbox-integration.md +0 -504
- package/docs/design/github-app-permissions.md +0 -264
- package/docs/guides/CLOUD.md +0 -236
- package/docs/guides/LOCAL.md +0 -535
- package/docs/guides/SELF-HOSTED.md +0 -494
- package/docs/local-testing.md +0 -428
- package/docs/proposals/continuous-claude-integration.md +0 -622
- package/docs/proposals/custom-commands.md +0 -368
- package/docs/proposals/shadow-as-subagent.md +0 -765
- package/docs/proposals/slack-bot-integration.md +0 -1457
- package/docs/tasks/global-skills-system.tasks.md +0 -230
- package/docs/tasks/webhook-integrations.tasks.md +0 -184
- package/docs/tasks/workspace-capabilities.tasks.md +0 -121
- package/docs/testing/RESILIENCY-TEST-PLAN-2026-01-01.md +0 -366
- package/scripts/cloud-setup.sh +0 -96
- package/scripts/dev/PUBLIC_RELEASE_PLAN.md +0 -88
- package/scripts/dev/dev-team-setup.sh +0 -431
- package/scripts/e2e-test.sh +0 -119
- package/scripts/games/game-protocol.md +0 -79
- package/scripts/games/hearts-setup.sh +0 -264
- package/scripts/manual-qa.sh +0 -293
- package/scripts/run-cloud-qa.sh +0 -220
- package/scripts/test-cli-auth/Dockerfile +0 -44
- package/scripts/test-cli-auth/Dockerfile.real +0 -79
- package/scripts/test-cli-auth/README.md +0 -286
- package/scripts/test-cli-auth/ci-test-real-clis.ts +0 -251
- package/scripts/test-cli-auth/ci-test-runner.ts +0 -263
- package/scripts/test-cli-auth/mock-cli.sh +0 -147
- package/scripts/test-cli-auth/package.json +0 -14
- package/scripts/test-cli-auth/test-oauth-flow.ts +0 -220
- package/scripts/test-pty-input-auto.js +0 -222
- package/scripts/test-pty-input.js +0 -150
- package/scripts/tictactoe-setup.sh +0 -181
- /package/dist/dashboard/out/_next/static/chunks/{117-b100311aff8d5c61.js → 117-f7b8ab0809342e77.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{648-a13d3c2b1be45466.js → 648-5cc6e1921389a58a.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{724-73c1ee5f60abe860.js → 724-2dae7627550ab88f.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/app/_not-found/{page-a4973f3e3c82fb67.js → page-53b8a69f76db17d0.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{fd9d1056-bf46c09eb57e019c.js → fd9d1056-609918ca7b6280bb.js} +0 -0
- /package/dist/dashboard/out/_next/static/{H5aWG0udPB4iOUIl_gytz → wPgKJtcOmTFLpUncDg16A}/_buildManifest.js +0 -0
- /package/dist/dashboard/out/_next/static/{H5aWG0udPB4iOUIl_gytz → wPgKJtcOmTFLpUncDg16A}/_ssgManifest.js +0 -0
|
@@ -8,9 +8,46 @@ import { getConfig } from '../config.js';
|
|
|
8
8
|
import { db } from '../db/index.js';
|
|
9
9
|
import { vault } from '../vault/index.js';
|
|
10
10
|
import { nangoService } from '../services/nango.js';
|
|
11
|
+
import { canAutoScale, canScaleToTier, getResourceTierForPlan, } from '../services/planLimits.js';
|
|
11
12
|
const WORKSPACE_PORT = 3888;
|
|
12
13
|
const FETCH_TIMEOUT_MS = 10_000;
|
|
13
14
|
const WORKSPACE_IMAGE = process.env.WORKSPACE_IMAGE || 'ghcr.io/agentworkforce/relay-workspace:latest';
|
|
15
|
+
// In-memory tracker for provisioning progress (workspace ID -> progress)
|
|
16
|
+
const provisioningProgress = new Map();
|
|
17
|
+
/**
|
|
18
|
+
* Update the provisioning stage for a workspace
|
|
19
|
+
*/
|
|
20
|
+
function updateProvisioningStage(workspaceId, stage) {
|
|
21
|
+
const existing = provisioningProgress.get(workspaceId);
|
|
22
|
+
provisioningProgress.set(workspaceId, {
|
|
23
|
+
stage,
|
|
24
|
+
startedAt: existing?.startedAt ?? Date.now(),
|
|
25
|
+
updatedAt: Date.now(),
|
|
26
|
+
});
|
|
27
|
+
console.log(`[provisioner] Workspace ${workspaceId.substring(0, 8)} stage: ${stage}`);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get the current provisioning stage for a workspace
|
|
31
|
+
*/
|
|
32
|
+
export function getProvisioningStage(workspaceId) {
|
|
33
|
+
return provisioningProgress.get(workspaceId) ?? null;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Clear provisioning progress (call when complete or failed)
|
|
37
|
+
*/
|
|
38
|
+
function clearProvisioningProgress(workspaceId) {
|
|
39
|
+
provisioningProgress.delete(workspaceId);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Schedule cleanup of provisioning progress after a delay
|
|
43
|
+
* This gives the frontend time to poll and see the 'complete' stage
|
|
44
|
+
*/
|
|
45
|
+
function scheduleProgressCleanup(workspaceId, delayMs = 30_000) {
|
|
46
|
+
setTimeout(() => {
|
|
47
|
+
clearProvisioningProgress(workspaceId);
|
|
48
|
+
console.log(`[provisioner] Cleaned up provisioning progress for ${workspaceId.substring(0, 8)}`);
|
|
49
|
+
}, delayMs);
|
|
50
|
+
}
|
|
14
51
|
/**
|
|
15
52
|
* Get a fresh GitHub App installation token from Nango.
|
|
16
53
|
* Looks up the user's connected repositories to find a valid Nango connection.
|
|
@@ -88,11 +125,95 @@ async function softHealthCheck(url) {
|
|
|
88
125
|
console.warn(`[health] Failed to reach ${url}/health`, error);
|
|
89
126
|
}
|
|
90
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Wait for machine to be in "started" state using Fly.io's /wait endpoint
|
|
130
|
+
* This is more efficient than polling - the API blocks until the state is reached
|
|
131
|
+
* @see https://fly.io/docs/machines/api/machines-resource/#wait-for-a-machine-to-reach-a-specific-state
|
|
132
|
+
*/
|
|
133
|
+
async function waitForMachineStarted(apiToken, appName, machineId, timeoutSeconds = 120) {
|
|
134
|
+
console.log(`[provisioner] Waiting for machine ${machineId} to start (timeout: ${timeoutSeconds}s)...`);
|
|
135
|
+
try {
|
|
136
|
+
// Use Fly.io's /wait endpoint - blocks until machine reaches target state
|
|
137
|
+
const res = await fetch(`https://api.machines.dev/v1/apps/${appName}/machines/${machineId}/wait?state=started&timeout=${timeoutSeconds}`, {
|
|
138
|
+
headers: { Authorization: `Bearer ${apiToken}` },
|
|
139
|
+
});
|
|
140
|
+
if (res.ok) {
|
|
141
|
+
console.log(`[provisioner] Machine ${machineId} is now started`);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
// 408 = timeout, machine didn't reach state in time
|
|
145
|
+
if (res.status === 408) {
|
|
146
|
+
// Get current state for error message
|
|
147
|
+
const stateRes = await fetch(`https://api.machines.dev/v1/apps/${appName}/machines/${machineId}`, { headers: { Authorization: `Bearer ${apiToken}` } });
|
|
148
|
+
const machine = stateRes.ok ? (await stateRes.json()) : { state: 'unknown' };
|
|
149
|
+
throw new Error(`Machine ${machineId} did not start within ${timeoutSeconds}s (last state: ${machine.state})`);
|
|
150
|
+
}
|
|
151
|
+
// Other error
|
|
152
|
+
const errorText = await res.text();
|
|
153
|
+
throw new Error(`Wait for machine failed: ${res.status} ${errorText}`);
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
if (error instanceof Error && error.message.includes('did not start')) {
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
console.warn(`[provisioner] Error waiting for machine:`, error);
|
|
160
|
+
throw new Error(`Failed to wait for machine ${machineId}: ${error.message}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Wait for health check to pass (with DNS propagation time)
|
|
165
|
+
* Tries internal Fly network first if available, then falls back to public URL
|
|
166
|
+
*/
|
|
167
|
+
async function waitForHealthy(url, appName, maxWaitMs = 90_000) {
|
|
168
|
+
const startTime = Date.now();
|
|
169
|
+
// Build list of URLs to try - internal first (faster, more reliable from inside Fly)
|
|
170
|
+
const urlsToTry = [];
|
|
171
|
+
// If running on Fly and app name provided, try internal network first
|
|
172
|
+
const isOnFly = !!process.env.FLY_APP_NAME;
|
|
173
|
+
if (isOnFly && appName) {
|
|
174
|
+
urlsToTry.push(`http://${appName}.internal:8080/health`);
|
|
175
|
+
}
|
|
176
|
+
// Always add the public URL as fallback
|
|
177
|
+
urlsToTry.push(`${url.replace(/\/$/, '')}/health`);
|
|
178
|
+
console.log(`[provisioner] Waiting for workspace to become healthy (trying: ${urlsToTry.join(', ')})...`);
|
|
179
|
+
while (Date.now() - startTime < maxWaitMs) {
|
|
180
|
+
// Try each URL in order
|
|
181
|
+
for (const healthUrl of urlsToTry) {
|
|
182
|
+
try {
|
|
183
|
+
const controller = new AbortController();
|
|
184
|
+
const timer = setTimeout(() => controller.abort(), 5_000);
|
|
185
|
+
const res = await fetch(healthUrl, {
|
|
186
|
+
method: 'GET',
|
|
187
|
+
signal: controller.signal,
|
|
188
|
+
});
|
|
189
|
+
clearTimeout(timer);
|
|
190
|
+
if (res.ok) {
|
|
191
|
+
console.log(`[provisioner] Health check passed via ${healthUrl}`);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
console.log(`[provisioner] Health check to ${healthUrl} returned ${res.status}`);
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
const elapsed = Math.round((Date.now() - startTime) / 1000);
|
|
198
|
+
const errMsg = error.message;
|
|
199
|
+
// Only log detailed error for last URL attempt
|
|
200
|
+
if (healthUrl === urlsToTry[urlsToTry.length - 1]) {
|
|
201
|
+
console.log(`[provisioner] Health check failed (${elapsed}s elapsed): ${errMsg}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
await wait(3000);
|
|
206
|
+
}
|
|
207
|
+
// Don't throw - workspace is provisioned, health check is best-effort
|
|
208
|
+
console.warn(`[provisioner] Health check did not pass within ${maxWaitMs}ms, continuing anyway`);
|
|
209
|
+
}
|
|
210
|
+
// Resource tiers sized for Claude Code agents (~1-2GB RAM per agent)
|
|
211
|
+
// cpuKind: 'shared' = cheaper but can be throttled, 'performance' = dedicated
|
|
91
212
|
export const RESOURCE_TIERS = {
|
|
92
|
-
small: { name: 'small', cpuCores:
|
|
93
|
-
medium: { name: 'medium', cpuCores: 2, memoryMb:
|
|
94
|
-
large: { name: 'large', cpuCores: 4, memoryMb:
|
|
95
|
-
xlarge: { name: 'xlarge', cpuCores: 8, memoryMb:
|
|
213
|
+
small: { name: 'small', cpuCores: 2, memoryMb: 2048, maxAgents: 2, cpuKind: 'shared' },
|
|
214
|
+
medium: { name: 'medium', cpuCores: 2, memoryMb: 4096, maxAgents: 5, cpuKind: 'shared' },
|
|
215
|
+
large: { name: 'large', cpuCores: 4, memoryMb: 8192, maxAgents: 10, cpuKind: 'performance' },
|
|
216
|
+
xlarge: { name: 'xlarge', cpuCores: 8, memoryMb: 16384, maxAgents: 20, cpuKind: 'performance' },
|
|
96
217
|
};
|
|
97
218
|
/**
|
|
98
219
|
* Fly.io provisioner
|
|
@@ -130,6 +251,8 @@ class FlyProvisioner {
|
|
|
130
251
|
}
|
|
131
252
|
async provision(workspace, credentials) {
|
|
132
253
|
const appName = `ar-${workspace.id.substring(0, 8)}`;
|
|
254
|
+
// Stage: Creating workspace
|
|
255
|
+
updateProvisioningStage(workspace.id, 'creating');
|
|
133
256
|
// Create Fly app
|
|
134
257
|
await fetchWithRetry('https://api.machines.dev/v1/apps', {
|
|
135
258
|
method: 'POST',
|
|
@@ -142,10 +265,82 @@ class FlyProvisioner {
|
|
|
142
265
|
org_slug: this.org,
|
|
143
266
|
}),
|
|
144
267
|
});
|
|
268
|
+
// Stage: Networking
|
|
269
|
+
updateProvisioningStage(workspace.id, 'networking');
|
|
270
|
+
// Allocate IPs for the app (required for public DNS)
|
|
271
|
+
// Must use GraphQL API - Machines REST API doesn't support IP allocation
|
|
272
|
+
// Shared IPv4 is free, IPv6 is free
|
|
273
|
+
console.log(`[fly] Allocating IPs for ${appName}...`);
|
|
274
|
+
const allocateIP = async (type) => {
|
|
275
|
+
try {
|
|
276
|
+
// Map our type to Fly GraphQL enum
|
|
277
|
+
const graphqlType = type === 'shared_v4' ? 'shared_v4' : 'v6';
|
|
278
|
+
const res = await fetchWithRetry('https://api.fly.io/graphql', {
|
|
279
|
+
method: 'POST',
|
|
280
|
+
headers: {
|
|
281
|
+
Authorization: `Bearer ${this.apiToken}`,
|
|
282
|
+
'Content-Type': 'application/json',
|
|
283
|
+
},
|
|
284
|
+
body: JSON.stringify({
|
|
285
|
+
query: `
|
|
286
|
+
mutation AllocateIPAddress($input: AllocateIPAddressInput!) {
|
|
287
|
+
allocateIpAddress(input: $input) {
|
|
288
|
+
ipAddress {
|
|
289
|
+
id
|
|
290
|
+
address
|
|
291
|
+
type
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
`,
|
|
296
|
+
variables: {
|
|
297
|
+
input: {
|
|
298
|
+
appId: appName,
|
|
299
|
+
type: graphqlType,
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
}),
|
|
303
|
+
});
|
|
304
|
+
if (!res.ok) {
|
|
305
|
+
const errorText = await res.text();
|
|
306
|
+
console.warn(`[fly] Failed to allocate ${type}: ${res.status} ${errorText}`);
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
const data = await res.json();
|
|
310
|
+
if (data.errors?.length) {
|
|
311
|
+
// Ignore "already allocated" errors
|
|
312
|
+
const alreadyAllocated = data.errors.some(e => e.message.includes('already') || e.message.includes('exists'));
|
|
313
|
+
if (!alreadyAllocated) {
|
|
314
|
+
console.warn(`[fly] GraphQL error allocating ${type}: ${data.errors[0].message}`);
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
console.log(`[fly] IP ${type} already allocated`);
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
const address = data.data?.allocateIpAddress?.ipAddress?.address;
|
|
321
|
+
console.log(`[fly] Allocated ${type}: ${address}`);
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
catch (err) {
|
|
325
|
+
console.warn(`[fly] Failed to allocate ${type}: ${err.message}`);
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
const [sharedV4Result, v6Result] = await Promise.all([
|
|
330
|
+
allocateIP('shared_v4'),
|
|
331
|
+
allocateIP('v6'),
|
|
332
|
+
]);
|
|
333
|
+
console.log(`[fly] IP allocation results: shared_v4=${sharedV4Result}, v6=${v6Result}`);
|
|
334
|
+
// Stage: Secrets
|
|
335
|
+
updateProvisioningStage(workspace.id, 'secrets');
|
|
145
336
|
// Set secrets (provider credentials)
|
|
146
337
|
const secrets = {};
|
|
147
338
|
for (const [provider, token] of credentials) {
|
|
148
339
|
secrets[`${provider.toUpperCase()}_TOKEN`] = token;
|
|
340
|
+
// Also set GH_TOKEN for gh CLI compatibility
|
|
341
|
+
if (provider === 'github') {
|
|
342
|
+
secrets['GH_TOKEN'] = token;
|
|
343
|
+
}
|
|
149
344
|
}
|
|
150
345
|
if (Object.keys(secrets).length > 0) {
|
|
151
346
|
await fetchWithRetry(`https://api.machines.dev/v1/apps/${appName}/secrets`, {
|
|
@@ -164,6 +359,8 @@ class FlyProvisioner {
|
|
|
164
359
|
if (customHostname) {
|
|
165
360
|
await this.allocateCertificate(appName, customHostname);
|
|
166
361
|
}
|
|
362
|
+
// Stage: Machine
|
|
363
|
+
updateProvisioningStage(workspace.id, 'machine');
|
|
167
364
|
// Create machine with auto-stop/start for cost optimization
|
|
168
365
|
const machineResponse = await fetchWithRetry(`https://api.machines.dev/v1/apps/${appName}/machines`, {
|
|
169
366
|
method: 'POST',
|
|
@@ -198,21 +395,49 @@ class FlyProvisioner {
|
|
|
198
395
|
services: [
|
|
199
396
|
{
|
|
200
397
|
ports: [
|
|
201
|
-
{
|
|
398
|
+
{
|
|
399
|
+
port: 443,
|
|
400
|
+
handlers: ['tls', 'http'],
|
|
401
|
+
// Force HTTP/1.1 to backend for WebSocket upgrade compatibility
|
|
402
|
+
// HTTP/2 doesn't support traditional WebSocket upgrade mechanism
|
|
403
|
+
http_options: {
|
|
404
|
+
h2_backend: false,
|
|
405
|
+
},
|
|
406
|
+
},
|
|
202
407
|
{ port: 80, handlers: ['http'] },
|
|
203
408
|
],
|
|
204
409
|
protocol: 'tcp',
|
|
205
410
|
internal_port: WORKSPACE_PORT,
|
|
206
|
-
// Auto-stop after
|
|
207
|
-
|
|
411
|
+
// Auto-stop after inactivity to reduce costs
|
|
412
|
+
// Fly Proxy automatically wakes machines on incoming requests
|
|
413
|
+
auto_stop_machines: 'stop', // stop (not suspend) for faster wake
|
|
208
414
|
auto_start_machines: true,
|
|
209
415
|
min_machines_running: 0,
|
|
416
|
+
// Idle timeout before auto-stop (in seconds)
|
|
417
|
+
// Longer timeout = better UX, shorter = lower costs
|
|
418
|
+
concurrency: {
|
|
419
|
+
type: 'requests',
|
|
420
|
+
soft_limit: 25,
|
|
421
|
+
hard_limit: 50,
|
|
422
|
+
},
|
|
210
423
|
},
|
|
211
424
|
],
|
|
425
|
+
checks: {
|
|
426
|
+
health: {
|
|
427
|
+
type: 'http',
|
|
428
|
+
port: WORKSPACE_PORT,
|
|
429
|
+
path: '/health',
|
|
430
|
+
interval: '30s',
|
|
431
|
+
timeout: '5s',
|
|
432
|
+
grace_period: '10s',
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
// Start with small tier (shared CPUs) - scales up based on plan
|
|
436
|
+
// Free tier uses shared CPUs for cost efficiency
|
|
212
437
|
guest: {
|
|
213
438
|
cpu_kind: 'shared',
|
|
214
|
-
cpus:
|
|
215
|
-
memory_mb:
|
|
439
|
+
cpus: 2,
|
|
440
|
+
memory_mb: 2048,
|
|
216
441
|
},
|
|
217
442
|
},
|
|
218
443
|
}),
|
|
@@ -226,7 +451,19 @@ class FlyProvisioner {
|
|
|
226
451
|
const publicUrl = customHostname
|
|
227
452
|
? `https://${customHostname}`
|
|
228
453
|
: `https://${appName}.fly.dev`;
|
|
229
|
-
|
|
454
|
+
// Stage: Booting
|
|
455
|
+
updateProvisioningStage(workspace.id, 'booting');
|
|
456
|
+
// Wait for machine to be in started state
|
|
457
|
+
await waitForMachineStarted(this.apiToken, appName, machine.id);
|
|
458
|
+
// Stage: Health check
|
|
459
|
+
updateProvisioningStage(workspace.id, 'health');
|
|
460
|
+
// Wait for health check to pass (includes DNS propagation time)
|
|
461
|
+
// Pass appName to enable internal Fly network health checks
|
|
462
|
+
await waitForHealthy(publicUrl, appName);
|
|
463
|
+
// Stage: Complete
|
|
464
|
+
updateProvisioningStage(workspace.id, 'complete');
|
|
465
|
+
// Schedule cleanup of provisioning progress after 30s (gives frontend time to see 'complete')
|
|
466
|
+
scheduleProgressCleanup(workspace.id);
|
|
230
467
|
return {
|
|
231
468
|
computeId: machine.id,
|
|
232
469
|
publicUrl,
|
|
@@ -313,7 +550,8 @@ class FlyProvisioner {
|
|
|
313
550
|
body: JSON.stringify({
|
|
314
551
|
config: {
|
|
315
552
|
guest: {
|
|
316
|
-
|
|
553
|
+
// Use tier-specific CPU type (shared for cost, performance for power)
|
|
554
|
+
cpu_kind: tier.cpuKind,
|
|
317
555
|
cpus: tier.cpuCores,
|
|
318
556
|
memory_mb: tier.memoryMb,
|
|
319
557
|
},
|
|
@@ -468,6 +706,10 @@ class RailwayProvisioner {
|
|
|
468
706
|
};
|
|
469
707
|
for (const [provider, token] of credentials) {
|
|
470
708
|
envVars[`${provider.toUpperCase()}_TOKEN`] = token;
|
|
709
|
+
// Also set GH_TOKEN for gh CLI compatibility
|
|
710
|
+
if (provider === 'github') {
|
|
711
|
+
envVars['GH_TOKEN'] = token;
|
|
712
|
+
}
|
|
471
713
|
}
|
|
472
714
|
await fetchWithRetry('https://backboard.railway.app/graphql/v2', {
|
|
473
715
|
method: 'POST',
|
|
@@ -682,6 +924,10 @@ class DockerProvisioner {
|
|
|
682
924
|
];
|
|
683
925
|
for (const [provider, token] of credentials) {
|
|
684
926
|
envArgs.push(`-e ${provider.toUpperCase()}_TOKEN=${token}`);
|
|
927
|
+
// Also set GH_TOKEN for gh CLI compatibility
|
|
928
|
+
if (provider === 'github') {
|
|
929
|
+
envArgs.push(`-e GH_TOKEN=${token}`);
|
|
930
|
+
}
|
|
685
931
|
}
|
|
686
932
|
// Run container
|
|
687
933
|
const { execSync } = await import('child_process');
|
|
@@ -791,6 +1037,7 @@ export class WorkspaceProvisioner {
|
|
|
791
1037
|
}
|
|
792
1038
|
/**
|
|
793
1039
|
* Provision a new workspace (one-click)
|
|
1040
|
+
* Returns immediately with 'provisioning' status and runs actual provisioning in background
|
|
794
1041
|
*/
|
|
795
1042
|
async provision(config) {
|
|
796
1043
|
// Create workspace record
|
|
@@ -814,6 +1061,22 @@ export class WorkspaceProvisioner {
|
|
|
814
1061
|
});
|
|
815
1062
|
// Auto-accept the creator's membership
|
|
816
1063
|
await db.workspaceMembers.acceptInvite(workspace.id, config.userId);
|
|
1064
|
+
// Initialize stage tracking immediately
|
|
1065
|
+
updateProvisioningStage(workspace.id, 'creating');
|
|
1066
|
+
// Run provisioning in the background so frontend can poll for stages
|
|
1067
|
+
this.runProvisioningAsync(workspace, config).catch((error) => {
|
|
1068
|
+
console.error(`[provisioner] Background provisioning failed for ${workspace.id}:`, error);
|
|
1069
|
+
});
|
|
1070
|
+
// Return immediately with 'provisioning' status
|
|
1071
|
+
return {
|
|
1072
|
+
workspaceId: workspace.id,
|
|
1073
|
+
status: 'provisioning',
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Run the actual provisioning work asynchronously
|
|
1078
|
+
*/
|
|
1079
|
+
async runProvisioningAsync(workspace, config) {
|
|
817
1080
|
// Get credentials
|
|
818
1081
|
const credentials = new Map();
|
|
819
1082
|
for (const provider of config.providers) {
|
|
@@ -848,22 +1111,21 @@ export class WorkspaceProvisioner {
|
|
|
848
1111
|
computeId,
|
|
849
1112
|
publicUrl,
|
|
850
1113
|
});
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
};
|
|
1114
|
+
// Schedule cleanup of provisioning progress after 30s (gives frontend time to see 'complete')
|
|
1115
|
+
setTimeout(() => {
|
|
1116
|
+
clearProvisioningProgress(workspace.id);
|
|
1117
|
+
console.log(`[provisioner] Cleaned up provisioning progress for ${workspace.id.substring(0, 8)}`);
|
|
1118
|
+
}, 30_000);
|
|
1119
|
+
console.log(`[provisioner] Workspace ${workspace.id} provisioned successfully at ${publicUrl}`);
|
|
856
1120
|
}
|
|
857
1121
|
catch (error) {
|
|
858
1122
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
859
1123
|
await db.workspaces.updateStatus(workspace.id, 'error', {
|
|
860
1124
|
errorMessage,
|
|
861
1125
|
});
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
error: errorMessage,
|
|
866
|
-
};
|
|
1126
|
+
// Clear provisioning progress on error
|
|
1127
|
+
clearProvisioningProgress(workspace.id);
|
|
1128
|
+
console.error(`[provisioner] Workspace ${workspace.id} provisioning failed:`, errorMessage);
|
|
867
1129
|
}
|
|
868
1130
|
}
|
|
869
1131
|
/**
|
|
@@ -885,6 +1147,11 @@ export class WorkspaceProvisioner {
|
|
|
885
1147
|
if (!workspace) {
|
|
886
1148
|
throw new Error('Workspace not found');
|
|
887
1149
|
}
|
|
1150
|
+
// During early provisioning, computeId isn't set yet
|
|
1151
|
+
// Return the database status instead of querying the provider
|
|
1152
|
+
if (!workspace.computeId && workspace.status === 'provisioning') {
|
|
1153
|
+
return 'provisioning';
|
|
1154
|
+
}
|
|
888
1155
|
const status = await this.provisioner.getStatus(workspace);
|
|
889
1156
|
// Update database if status changed
|
|
890
1157
|
if (status !== workspace.status) {
|
|
@@ -965,6 +1232,80 @@ export class WorkspaceProvisioner {
|
|
|
965
1232
|
const tierName = workspace.config.resourceTier || 'small';
|
|
966
1233
|
return RESOURCE_TIERS[tierName] || RESOURCE_TIERS.small;
|
|
967
1234
|
}
|
|
1235
|
+
/**
|
|
1236
|
+
* Get recommended tier based on agent count
|
|
1237
|
+
* Uses 1.5-2GB per agent as baseline for Claude Code
|
|
1238
|
+
*/
|
|
1239
|
+
getRecommendedTier(agentCount) {
|
|
1240
|
+
// Find the smallest tier that supports this agent count
|
|
1241
|
+
const tiers = Object.values(RESOURCE_TIERS).sort((a, b) => a.maxAgents - b.maxAgents);
|
|
1242
|
+
for (const tier of tiers) {
|
|
1243
|
+
if (tier.maxAgents >= agentCount) {
|
|
1244
|
+
return tier;
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
// If agent count exceeds all tiers, return the largest
|
|
1248
|
+
return RESOURCE_TIERS.xlarge;
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Auto-scale workspace based on current agent count
|
|
1252
|
+
* Respects plan limits - free tier cannot scale, others have max tier limits
|
|
1253
|
+
* Returns { scaled: boolean, reason?: string }
|
|
1254
|
+
*/
|
|
1255
|
+
async autoScale(workspaceId, currentAgentCount) {
|
|
1256
|
+
const workspace = await db.workspaces.findById(workspaceId);
|
|
1257
|
+
if (!workspace) {
|
|
1258
|
+
throw new Error('Workspace not found');
|
|
1259
|
+
}
|
|
1260
|
+
// Get user's plan
|
|
1261
|
+
const user = await db.users.findById(workspace.userId);
|
|
1262
|
+
const plan = user?.plan || 'free';
|
|
1263
|
+
// Check if plan allows auto-scaling
|
|
1264
|
+
if (!canAutoScale(plan)) {
|
|
1265
|
+
return {
|
|
1266
|
+
scaled: false,
|
|
1267
|
+
reason: 'Auto-scaling requires Pro plan or higher',
|
|
1268
|
+
};
|
|
1269
|
+
}
|
|
1270
|
+
const currentTier = await this.getCurrentTier(workspaceId);
|
|
1271
|
+
const recommendedTier = this.getRecommendedTier(currentAgentCount);
|
|
1272
|
+
// Only scale UP, never down (to avoid disruption)
|
|
1273
|
+
if (recommendedTier.memoryMb <= currentTier.memoryMb) {
|
|
1274
|
+
return {
|
|
1275
|
+
scaled: false,
|
|
1276
|
+
currentTier: currentTier.name,
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
// Check if plan allows scaling to the recommended tier
|
|
1280
|
+
if (!canScaleToTier(plan, recommendedTier.name)) {
|
|
1281
|
+
// Find the max tier allowed for this plan
|
|
1282
|
+
const maxTierName = getResourceTierForPlan(plan);
|
|
1283
|
+
const maxTier = RESOURCE_TIERS[maxTierName];
|
|
1284
|
+
if (maxTier.memoryMb <= currentTier.memoryMb) {
|
|
1285
|
+
return {
|
|
1286
|
+
scaled: false,
|
|
1287
|
+
reason: `Already at max tier (${currentTier.name}) for ${plan} plan`,
|
|
1288
|
+
currentTier: currentTier.name,
|
|
1289
|
+
};
|
|
1290
|
+
}
|
|
1291
|
+
// Scale to max allowed tier instead
|
|
1292
|
+
console.log(`[provisioner] Auto-scaling workspace ${workspaceId.substring(0, 8)} from ${currentTier.name} to ${maxTierName} (max for ${plan} plan)`);
|
|
1293
|
+
await this.resize(workspaceId, maxTier);
|
|
1294
|
+
return {
|
|
1295
|
+
scaled: true,
|
|
1296
|
+
currentTier: currentTier.name,
|
|
1297
|
+
targetTier: maxTierName,
|
|
1298
|
+
reason: `Scaled to max tier for ${plan} plan`,
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
console.log(`[provisioner] Auto-scaling workspace ${workspaceId.substring(0, 8)} from ${currentTier.name} to ${recommendedTier.name} (${currentAgentCount} agents)`);
|
|
1302
|
+
await this.resize(workspaceId, recommendedTier);
|
|
1303
|
+
return {
|
|
1304
|
+
scaled: true,
|
|
1305
|
+
currentTier: currentTier.name,
|
|
1306
|
+
targetTier: recommendedTier.name,
|
|
1307
|
+
};
|
|
1308
|
+
}
|
|
968
1309
|
}
|
|
969
1310
|
// Singleton instance
|
|
970
1311
|
let _provisioner = null;
|
package/dist/cloud/server.js
CHANGED
|
@@ -34,6 +34,7 @@ import { webhooksRouter } from './api/webhooks.js';
|
|
|
34
34
|
import { githubAppRouter } from './api/github-app.js';
|
|
35
35
|
import { nangoAuthRouter } from './api/nango-auth.js';
|
|
36
36
|
import { gitRouter } from './api/git.js';
|
|
37
|
+
import { codexAuthHelperRouter } from './api/codex-auth-helper.js';
|
|
37
38
|
import { db } from './db/index.js';
|
|
38
39
|
/**
|
|
39
40
|
* Proxy a request to the user's primary running workspace
|
|
@@ -98,7 +99,9 @@ export async function createServer() {
|
|
|
98
99
|
credentials: true,
|
|
99
100
|
}));
|
|
100
101
|
// Custom JSON parser that preserves raw body for webhook signature verification
|
|
102
|
+
// Increase limit to 10mb for base64 image uploads (screenshots)
|
|
101
103
|
app.use(express.json({
|
|
104
|
+
limit: '10mb',
|
|
102
105
|
verify: (req, _res, buf) => {
|
|
103
106
|
// Store raw body for webhook signature verification
|
|
104
107
|
req.rawBody = buf.toString();
|
|
@@ -168,10 +171,11 @@ export async function createServer() {
|
|
|
168
171
|
});
|
|
169
172
|
// Lightweight CSRF protection using session token
|
|
170
173
|
const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);
|
|
171
|
-
// Paths exempt from CSRF (webhooks from external services, workspace proxy)
|
|
174
|
+
// Paths exempt from CSRF (webhooks from external services, workspace proxy, local auth callbacks)
|
|
172
175
|
const CSRF_EXEMPT_PATHS = [
|
|
173
176
|
'/api/webhooks/',
|
|
174
177
|
'/api/auth/nango/webhook',
|
|
178
|
+
'/api/auth/codex-helper/callback',
|
|
175
179
|
];
|
|
176
180
|
// Additional pattern for workspace proxy routes (contains /proxy/)
|
|
177
181
|
const isWorkspaceProxyRoute = (path) => /^\/api\/workspaces\/[^/]+\/proxy\//.test(path);
|
|
@@ -236,6 +240,7 @@ export async function createServer() {
|
|
|
236
240
|
app.use('/api/webhooks', webhooksRouter);
|
|
237
241
|
app.use('/api/github-app', githubAppRouter);
|
|
238
242
|
app.use('/api/auth/nango', nangoAuthRouter);
|
|
243
|
+
app.use('/api/auth/codex-helper', codexAuthHelperRouter);
|
|
239
244
|
app.use('/api/git', gitRouter);
|
|
240
245
|
// Test helper routes (only available in non-production)
|
|
241
246
|
if (process.env.NODE_ENV !== 'production') {
|
|
@@ -33,6 +33,22 @@ declare class NangoService {
|
|
|
33
33
|
* For API calls, use the proxy methods instead.
|
|
34
34
|
*/
|
|
35
35
|
getGithubAppToken(connectionId: string): Promise<string>;
|
|
36
|
+
/**
|
|
37
|
+
* Retrieve the user's OAuth access token from a GitHub App OAuth connection.
|
|
38
|
+
* This is the user-level token (not the installation token).
|
|
39
|
+
* Use this for operations that require user context (e.g., gh CLI).
|
|
40
|
+
*
|
|
41
|
+
* The user token can be found in:
|
|
42
|
+
* 1. getToken() without installation flag
|
|
43
|
+
* 2. connection_config.access_token in github-app-oauth
|
|
44
|
+
* 3. Separate 'github' user connection
|
|
45
|
+
*/
|
|
46
|
+
getGithubUserOAuthToken(connectionId: string): Promise<string>;
|
|
47
|
+
/**
|
|
48
|
+
* Retrieve the user's OAuth token from a 'github' user connection.
|
|
49
|
+
* This is for the separate GitHub OAuth login (not the App connection).
|
|
50
|
+
*/
|
|
51
|
+
getGithubUserToken(connectionId: string): Promise<string>;
|
|
36
52
|
/**
|
|
37
53
|
* List repositories available to a GitHub App installation using the Nango Proxy.
|
|
38
54
|
* The proxy automatically handles token injection and refresh.
|
|
@@ -114,6 +130,50 @@ declare class NangoService {
|
|
|
114
130
|
};
|
|
115
131
|
metadata?: Record<string, unknown>;
|
|
116
132
|
}>;
|
|
133
|
+
/**
|
|
134
|
+
* Check if user has access to a specific GitHub repository.
|
|
135
|
+
* Uses the user's OAuth connection to query GitHub API.
|
|
136
|
+
* @param connectionId - User's Nango connection ID (github user OAuth)
|
|
137
|
+
* @param owner - Repository owner
|
|
138
|
+
* @param repo - Repository name
|
|
139
|
+
* @returns Access details or null if no access
|
|
140
|
+
*/
|
|
141
|
+
checkUserRepoAccess(connectionId: string, owner: string, repo: string): Promise<{
|
|
142
|
+
hasAccess: boolean;
|
|
143
|
+
permission?: 'admin' | 'write' | 'read' | 'none';
|
|
144
|
+
repository?: {
|
|
145
|
+
id: number;
|
|
146
|
+
fullName: string;
|
|
147
|
+
isPrivate: boolean;
|
|
148
|
+
defaultBranch: string;
|
|
149
|
+
};
|
|
150
|
+
}>;
|
|
151
|
+
/**
|
|
152
|
+
* List all repositories the user has access to via their OAuth connection.
|
|
153
|
+
* Uses the user's personal OAuth token (not the GitHub App).
|
|
154
|
+
* @param connectionId - User's Nango connection ID (github user OAuth)
|
|
155
|
+
* @param options - Pagination and filter options
|
|
156
|
+
* @returns List of accessible repositories
|
|
157
|
+
*/
|
|
158
|
+
listUserAccessibleRepos(connectionId: string, options?: {
|
|
159
|
+
page?: number;
|
|
160
|
+
perPage?: number;
|
|
161
|
+
type?: 'all' | 'owner' | 'public' | 'private' | 'member';
|
|
162
|
+
sort?: 'created' | 'updated' | 'pushed' | 'full_name';
|
|
163
|
+
}): Promise<{
|
|
164
|
+
repositories: Array<{
|
|
165
|
+
id: number;
|
|
166
|
+
fullName: string;
|
|
167
|
+
isPrivate: boolean;
|
|
168
|
+
defaultBranch: string;
|
|
169
|
+
permissions: {
|
|
170
|
+
admin: boolean;
|
|
171
|
+
push: boolean;
|
|
172
|
+
pull: boolean;
|
|
173
|
+
};
|
|
174
|
+
}>;
|
|
175
|
+
hasMore: boolean;
|
|
176
|
+
}>;
|
|
117
177
|
/**
|
|
118
178
|
* Verify webhook signature sent by Nango.
|
|
119
179
|
* Uses the new verifyIncomingWebhookRequest method.
|