agent-relay 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +3 -0
- package/.nvmrc +1 -0
- package/.trajectories/agent-relay-322-324.md +17 -0
- package/.trajectories/completed/2026-01/traj_03zupyv1s7b9.json +49 -0
- package/.trajectories/completed/2026-01/traj_03zupyv1s7b9.md +31 -0
- package/.trajectories/completed/2026-01/traj_0zacdjl1g4ht.json +125 -0
- package/.trajectories/completed/2026-01/traj_0zacdjl1g4ht.md +62 -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_33iuy72sezbk.json +49 -0
- package/.trajectories/completed/2026-01/traj_33iuy72sezbk.md +31 -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_5ammh5qtvklq.json +77 -0
- package/.trajectories/completed/2026-01/traj_5ammh5qtvklq.md +42 -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_6mieijqyvaag.json +77 -0
- package/.trajectories/completed/2026-01/traj_6mieijqyvaag.md +42 -0
- package/.trajectories/completed/2026-01/traj_78ffm31jn3uk.json +77 -0
- package/.trajectories/completed/2026-01/traj_78ffm31jn3uk.md +42 -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_94gnp3k30goq.json +66 -0
- package/.trajectories/completed/2026-01/traj_94gnp3k30goq.md +36 -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_avqeghu6pz5a.json +40 -0
- package/.trajectories/completed/2026-01/traj_avqeghu6pz5a.md +22 -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_dcsp9s8y01ra.json +121 -0
- package/.trajectories/completed/2026-01/traj_dcsp9s8y01ra.md +29 -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_fhx9irlckht6.json +53 -0
- package/.trajectories/completed/2026-01/traj_fhx9irlckht6.md +32 -0
- package/.trajectories/completed/2026-01/traj_fqduidx3xbtp.json +101 -0
- package/.trajectories/completed/2026-01/traj_fqduidx3xbtp.md +52 -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_hf81ey93uz6t.json +49 -0
- package/.trajectories/completed/2026-01/traj_hf81ey93uz6t.md +31 -0
- package/.trajectories/completed/2026-01/traj_hfmki2jr9d4r.json +65 -0
- package/.trajectories/completed/2026-01/traj_hfmki2jr9d4r.md +37 -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_lq450ly148uw.json +49 -0
- package/.trajectories/completed/2026-01/traj_lq450ly148uw.md +31 -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_multi_server_arch.md +101 -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_psd9ob0j2ru3.json +27 -0
- package/.trajectories/completed/2026-01/traj_psd9ob0j2ru3.md +14 -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_ub8csuv3lcv4.json +53 -0
- package/.trajectories/completed/2026-01/traj_ub8csuv3lcv4.md +32 -0
- package/.trajectories/completed/2026-01/traj_uc29tlso8i9s.json +186 -0
- package/.trajectories/completed/2026-01/traj_uc29tlso8i9s.md +86 -0
- package/.trajectories/completed/2026-01/traj_ui9b4tqxoa7j.json +77 -0
- package/.trajectories/completed/2026-01/traj_ui9b4tqxoa7j.md +42 -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_v9dkdoxylyid.json +89 -0
- package/.trajectories/completed/2026-01/traj_v9dkdoxylyid.md +47 -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_xy9vifpqet80.json +65 -0
- package/.trajectories/completed/2026-01/traj_xy9vifpqet80.md +37 -0
- package/.trajectories/completed/2026-01/traj_y7aiwijyfmmv.json +49 -0
- package/.trajectories/completed/2026-01/traj_y7aiwijyfmmv.md +31 -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/consolidate-settings-panel.md +24 -0
- package/.trajectories/gh-cli-user-token.md +26 -0
- package/.trajectories/index.json +468 -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/codex.config.toml +15 -0
- package/deploy/workspace/entrypoint-browser.sh +118 -0
- package/deploy/workspace/entrypoint.sh +508 -0
- package/deploy/workspace/git-credential-relay +126 -0
- package/dist/bridge/spawner.d.ts +7 -0
- package/dist/bridge/spawner.js +40 -9
- package/dist/bridge/types.d.ts +2 -0
- package/dist/cli/index.js +260 -1
- package/dist/cloud/api/admin.d.ts +8 -0
- package/dist/cloud/api/admin.js +212 -0
- package/dist/cloud/api/auth.js +8 -0
- package/dist/cloud/api/billing.d.ts +0 -10
- package/dist/cloud/api/billing.js +278 -67
- package/dist/cloud/api/codex-auth-helper.d.ts +21 -0
- package/dist/cloud/api/codex-auth-helper.js +307 -0
- package/dist/cloud/api/coordinators.js +402 -0
- package/dist/cloud/api/daemons.js +15 -11
- package/dist/cloud/api/git.js +127 -19
- package/dist/cloud/api/github-app.js +42 -8
- package/dist/cloud/api/nango-auth.js +297 -16
- package/dist/cloud/api/onboarding.js +112 -35
- package/dist/cloud/api/providers.js +12 -16
- package/dist/cloud/api/repos.d.ts +1 -0
- package/dist/cloud/api/repos.js +311 -49
- package/dist/cloud/api/test-helpers.js +40 -0
- package/dist/cloud/api/usage.js +13 -0
- package/dist/cloud/api/webhooks.d.ts +1 -0
- package/dist/cloud/api/webhooks.js +149 -0
- package/dist/cloud/api/workspaces.d.ts +18 -0
- package/dist/cloud/api/workspaces.js +1042 -21
- package/dist/cloud/billing/plans.js +19 -19
- package/dist/cloud/config.d.ts +8 -0
- package/dist/cloud/config.js +15 -0
- package/dist/cloud/db/drizzle.d.ts +5 -2
- package/dist/cloud/db/drizzle.js +27 -20
- package/dist/cloud/db/schema.d.ts +19 -51
- package/dist/cloud/db/schema.js +5 -4
- package/dist/cloud/index.d.ts +0 -1
- package/dist/cloud/index.js +0 -1
- package/dist/cloud/provisioner/index.d.ts +125 -1
- package/dist/cloud/provisioner/index.js +939 -53
- package/dist/cloud/server.js +161 -16
- package/dist/cloud/services/compute-enforcement.d.ts +57 -0
- package/dist/cloud/services/compute-enforcement.js +175 -0
- package/dist/cloud/services/index.d.ts +2 -0
- package/dist/cloud/services/index.js +4 -0
- package/dist/cloud/services/intro-expiration.d.ts +55 -0
- package/dist/cloud/services/intro-expiration.js +211 -0
- package/dist/cloud/services/nango.d.ts +74 -0
- package/dist/cloud/services/nango.js +218 -5
- package/dist/cloud/services/planLimits.d.ts +22 -0
- package/dist/cloud/services/planLimits.js +58 -5
- package/dist/cloud/services/ssh-security.d.ts +31 -0
- package/dist/cloud/services/ssh-security.js +63 -0
- package/dist/continuity/manager.d.ts +5 -0
- package/dist/continuity/manager.js +56 -2
- package/dist/daemon/api.d.ts +2 -0
- package/dist/daemon/api.js +214 -5
- package/dist/daemon/cli-auth.d.ts +13 -1
- package/dist/daemon/cli-auth.js +166 -47
- package/dist/daemon/connection.d.ts +7 -1
- package/dist/daemon/connection.js +15 -0
- package/dist/daemon/orchestrator.d.ts +2 -0
- package/dist/daemon/orchestrator.js +26 -0
- package/dist/daemon/repo-manager.d.ts +116 -0
- package/dist/daemon/repo-manager.js +384 -0
- package/dist/daemon/router.d.ts +60 -1
- package/dist/daemon/router.js +281 -20
- package/dist/daemon/user-directory.d.ts +111 -0
- package/dist/daemon/user-directory.js +233 -0
- package/dist/dashboard/out/404.html +1 -1
- package/dist/dashboard/out/_next/static/T1tgCqVWHFIkV7ClEtzD7/_ssgManifest.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/532-bace199897eeab37.js +9 -0
- package/dist/dashboard/out/_next/static/chunks/766-b54f0853794b78c3.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/83-b51836037078006c.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/891-6cd50de1224f70bb.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/899-bb19a9b3d9b39ea6.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/onboarding/page-8939b0fc700f7eca.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/page-5af1b6b439858aa6.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/metrics/page-ac39dc0cc3c26fa7.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/{page-daf87e86f783f980.js → page-4a5938c18a11a654.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/app/providers/page-ac3a6ac433fd6001.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/providers/setup/[provider]/page-09f9caae98a18c09.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/{main-97850e03d723ea8c.js → main-2ee6beb2ae96d210.js} +1 -1
- package/dist/dashboard/out/_next/static/css/85d2af9c7ac74d62.css +1 -0
- package/dist/dashboard/out/_next/static/css/fe4b28883eeff359.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 +3 -3
- package/dist/dashboard/out/apple-icon.png +0 -0
- package/dist/dashboard/out/connect-repos.html +1 -1
- package/dist/dashboard/out/connect-repos.txt +3 -3
- package/dist/dashboard/out/history.html +1 -1
- package/dist/dashboard/out/history.txt +3 -3
- package/dist/dashboard/out/index.html +1 -1
- package/dist/dashboard/out/index.txt +3 -3
- package/dist/dashboard/out/login.html +2 -2
- package/dist/dashboard/out/login.txt +3 -3
- package/dist/dashboard/out/metrics.html +1 -1
- package/dist/dashboard/out/metrics.txt +3 -3
- package/dist/dashboard/out/pricing.html +3 -3
- package/dist/dashboard/out/pricing.txt +3 -3
- package/dist/dashboard/out/providers/setup/claude.html +1 -0
- package/dist/dashboard/out/providers/setup/claude.txt +8 -0
- package/dist/dashboard/out/providers/setup/codex.html +1 -0
- package/dist/dashboard/out/providers/setup/codex.txt +8 -0
- package/dist/dashboard/out/providers.html +1 -1
- package/dist/dashboard/out/providers.txt +3 -3
- package/dist/dashboard/out/signup.html +2 -2
- package/dist/dashboard/out/signup.txt +3 -3
- package/dist/dashboard-server/server.js +316 -12
- package/dist/dashboard-server/user-bridge.d.ts +103 -0
- package/dist/dashboard-server/user-bridge.js +189 -0
- package/dist/protocol/channels.d.ts +205 -0
- package/dist/protocol/channels.js +154 -0
- package/dist/protocol/types.d.ts +13 -1
- package/dist/resiliency/provider-context.js +2 -0
- package/dist/shared/cli-auth-config.d.ts +19 -0
- package/dist/shared/cli-auth-config.js +58 -2
- package/dist/utils/agent-config.js +1 -1
- package/dist/wrapper/auth-detection.d.ts +49 -0
- package/dist/wrapper/auth-detection.js +192 -0
- package/dist/wrapper/base-wrapper.d.ts +153 -0
- package/dist/wrapper/base-wrapper.js +393 -0
- package/dist/wrapper/client.d.ts +7 -1
- package/dist/wrapper/client.js +3 -0
- package/dist/wrapper/index.d.ts +1 -0
- package/dist/wrapper/index.js +4 -3
- package/dist/wrapper/pty-wrapper.d.ts +62 -84
- package/dist/wrapper/pty-wrapper.js +154 -180
- package/dist/wrapper/tmux-wrapper.d.ts +41 -66
- package/dist/wrapper/tmux-wrapper.js +90 -134
- package/package.json +5 -12
- package/scripts/postinstall.js +11 -155
- package/scripts/test-interactive-terminal.sh +248 -0
- 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 +0 -76
- package/dist/cloud/vault/index.d.ts.map +0 -1
- package/dist/cloud/vault/index.js +0 -219
- 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/H5aWG0udPB4iOUIl_gytz/_ssgManifest.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/480-2d4111711d4e473c.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/724-73c1ee5f60abe860.js +0 -9
- 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/metrics/page-1081dd190a331a91.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/providers/page-b68a681526eb145e.js +0 -1
- package/dist/dashboard/out/_next/static/css/29852f26181969a0.css +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/{H5aWG0udPB4iOUIl_gytz → T1tgCqVWHFIkV7ClEtzD7}/_buildManifest.js +0 -0
- /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/app/_not-found/{page-a4973f3e3c82fb67.js → page-53b8a69f76db17d0.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/app/connect-repos/{page-dc2e3a1a22478efc.js → page-f45ecbc3e06134fc.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/app/history/{page-56a8b4616a90dc43.js → page-8c8bed33beb2bf1c.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/app/login/{page-3eac37ea6f5dd153.js → page-16f3b49e55b1e0ed.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/app/pricing/{page-4d72d5a5d8a9b618.js → page-982a7000fee44014.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/app/signup/{page-fee4ed1709070bcd.js → page-547dd0ca55ecd0ba.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{fd9d1056-bf46c09eb57e019c.js → fd9d1056-609918ca7b6280bb.js} +0 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intro Expiration Service
|
|
3
|
+
*
|
|
4
|
+
* Handles auto-resize of workspaces when the free tier introductory period expires.
|
|
5
|
+
* Free users get Pro-level resources (2 CPU / 4GB) for the first 14 days,
|
|
6
|
+
* then get automatically downsized to standard free tier (1 CPU / 2GB).
|
|
7
|
+
*/
|
|
8
|
+
import { db } from '../db/index.js';
|
|
9
|
+
import { getProvisioner } from '../provisioner/index.js';
|
|
10
|
+
export const INTRO_PERIOD_DAYS = 14;
|
|
11
|
+
const DEFAULT_CONFIG = {
|
|
12
|
+
enabled: true,
|
|
13
|
+
checkIntervalMs: 60 * 60 * 1000, // 1 hour
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Get intro period status for a user
|
|
17
|
+
*/
|
|
18
|
+
export function getIntroStatus(userCreatedAt, plan) {
|
|
19
|
+
const introPeriodDays = INTRO_PERIOD_DAYS;
|
|
20
|
+
// Only free tier users get intro bonus
|
|
21
|
+
if (plan !== 'free' || !userCreatedAt) {
|
|
22
|
+
return {
|
|
23
|
+
isIntroPeriod: false,
|
|
24
|
+
daysRemaining: 0,
|
|
25
|
+
introPeriodDays,
|
|
26
|
+
expiresAt: null,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const createdAt = typeof userCreatedAt === 'string' ? new Date(userCreatedAt) : userCreatedAt;
|
|
30
|
+
const daysSinceSignup = (Date.now() - createdAt.getTime()) / (1000 * 60 * 60 * 24);
|
|
31
|
+
const isIntroPeriod = daysSinceSignup < introPeriodDays;
|
|
32
|
+
const daysRemaining = Math.max(0, Math.ceil(introPeriodDays - daysSinceSignup));
|
|
33
|
+
const expiresAt = new Date(createdAt.getTime() + introPeriodDays * 24 * 60 * 60 * 1000);
|
|
34
|
+
return {
|
|
35
|
+
isIntroPeriod,
|
|
36
|
+
daysRemaining,
|
|
37
|
+
introPeriodDays,
|
|
38
|
+
expiresAt,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export class IntroExpirationService {
|
|
42
|
+
config;
|
|
43
|
+
checkTimer = null;
|
|
44
|
+
isRunning = false;
|
|
45
|
+
constructor(config = {}) {
|
|
46
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Start the expiration service
|
|
50
|
+
*/
|
|
51
|
+
start() {
|
|
52
|
+
if (!this.config.enabled) {
|
|
53
|
+
console.log('[intro-expiration] Service disabled');
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (this.isRunning) {
|
|
57
|
+
console.warn('[intro-expiration] Service already running');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
this.isRunning = true;
|
|
61
|
+
console.log(`[intro-expiration] Started (checking every ${this.config.checkIntervalMs / 1000 / 60} minutes)`);
|
|
62
|
+
// Run immediately on start
|
|
63
|
+
this.runExpirationCheck().catch((err) => {
|
|
64
|
+
console.error('[intro-expiration] Initial run failed:', err);
|
|
65
|
+
});
|
|
66
|
+
// Then run periodically
|
|
67
|
+
this.checkTimer = setInterval(() => {
|
|
68
|
+
this.runExpirationCheck().catch((err) => {
|
|
69
|
+
console.error('[intro-expiration] Periodic run failed:', err);
|
|
70
|
+
});
|
|
71
|
+
}, this.config.checkIntervalMs);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Stop the expiration service
|
|
75
|
+
*/
|
|
76
|
+
stop() {
|
|
77
|
+
if (this.checkTimer) {
|
|
78
|
+
clearInterval(this.checkTimer);
|
|
79
|
+
this.checkTimer = null;
|
|
80
|
+
}
|
|
81
|
+
this.isRunning = false;
|
|
82
|
+
console.log('[intro-expiration] Stopped');
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Run expiration check for all free tier users with expired intro periods
|
|
86
|
+
*/
|
|
87
|
+
async runExpirationCheck() {
|
|
88
|
+
const results = [];
|
|
89
|
+
try {
|
|
90
|
+
// Get all users on free tier
|
|
91
|
+
const freeUsers = await db.users.findByPlan('free');
|
|
92
|
+
// Filter to users whose intro period has expired
|
|
93
|
+
const expiredUsers = freeUsers.filter((user) => {
|
|
94
|
+
const status = getIntroStatus(user.createdAt, user.plan || 'free');
|
|
95
|
+
return !status.isIntroPeriod && status.expiresAt !== null;
|
|
96
|
+
});
|
|
97
|
+
if (expiredUsers.length === 0) {
|
|
98
|
+
return results;
|
|
99
|
+
}
|
|
100
|
+
console.log(`[intro-expiration] Checking ${expiredUsers.length} users with expired intro periods`);
|
|
101
|
+
for (const user of expiredUsers) {
|
|
102
|
+
try {
|
|
103
|
+
const userResults = await this.checkAndResizeUserWorkspaces(user.id);
|
|
104
|
+
results.push(...userResults);
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
console.error(`[intro-expiration] Error checking user ${user.id}:`, err);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Summary
|
|
111
|
+
const resized = results.filter((r) => r.action === 'resized').length;
|
|
112
|
+
const skipped = results.filter((r) => r.action === 'skipped').length;
|
|
113
|
+
const errors = results.filter((r) => r.action === 'error').length;
|
|
114
|
+
if (resized > 0 || errors > 0) {
|
|
115
|
+
console.log(`[intro-expiration] Results: ${resized} resized, ${skipped} skipped, ${errors} errors`);
|
|
116
|
+
}
|
|
117
|
+
return results;
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
console.error('[intro-expiration] Run failed:', err);
|
|
121
|
+
return results;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Check and resize workspaces for a user whose intro period has expired
|
|
126
|
+
*/
|
|
127
|
+
async checkAndResizeUserWorkspaces(userId) {
|
|
128
|
+
const results = [];
|
|
129
|
+
const provisioner = getProvisioner();
|
|
130
|
+
// Get user's workspaces
|
|
131
|
+
const workspaces = await db.workspaces.findByUserId(userId);
|
|
132
|
+
for (const workspace of workspaces) {
|
|
133
|
+
try {
|
|
134
|
+
// Check if workspace has intro-sized resources
|
|
135
|
+
// We detect this by checking if it has 4GB memory (intro size) vs 2GB (standard)
|
|
136
|
+
const config = workspace.config;
|
|
137
|
+
const resourceTier = config?.resourceTier;
|
|
138
|
+
// Skip if already resized to standard free tier
|
|
139
|
+
// Intro workspaces would have been provisioned with medium tier (4GB)
|
|
140
|
+
// Standard free tier is small (2GB)
|
|
141
|
+
if (resourceTier === 'small') {
|
|
142
|
+
results.push({
|
|
143
|
+
userId,
|
|
144
|
+
workspaceId: workspace.id,
|
|
145
|
+
workspaceName: workspace.name,
|
|
146
|
+
action: 'skipped',
|
|
147
|
+
reason: 'Already at standard free tier size',
|
|
148
|
+
});
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
// Skip if workspace is not running (resize happens on next start)
|
|
152
|
+
if (workspace.status !== 'running') {
|
|
153
|
+
results.push({
|
|
154
|
+
userId,
|
|
155
|
+
workspaceId: workspace.id,
|
|
156
|
+
workspaceName: workspace.name,
|
|
157
|
+
action: 'skipped',
|
|
158
|
+
reason: `Workspace status is ${workspace.status}`,
|
|
159
|
+
});
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
// Resize to standard free tier (small: 1 CPU / 2GB)
|
|
163
|
+
// Use skipRestart=true to not disrupt running agents
|
|
164
|
+
// The config is saved and will apply on next restart
|
|
165
|
+
console.log(`[intro-expiration] Resizing workspace ${workspace.name} to standard free tier`);
|
|
166
|
+
await provisioner.resize(workspace.id, {
|
|
167
|
+
name: 'small',
|
|
168
|
+
cpuCores: 1,
|
|
169
|
+
cpuKind: 'shared',
|
|
170
|
+
memoryMb: 2048,
|
|
171
|
+
maxAgents: 2,
|
|
172
|
+
}, true); // skipRestart = true for graceful resize
|
|
173
|
+
results.push({
|
|
174
|
+
userId,
|
|
175
|
+
workspaceId: workspace.id,
|
|
176
|
+
workspaceName: workspace.name,
|
|
177
|
+
action: 'resized',
|
|
178
|
+
reason: 'Intro period expired, downsized to standard free tier (applies on next restart)',
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
console.error(`[intro-expiration] Failed to resize workspace ${workspace.id}:`, err);
|
|
183
|
+
results.push({
|
|
184
|
+
userId,
|
|
185
|
+
workspaceId: workspace.id,
|
|
186
|
+
workspaceName: workspace.name,
|
|
187
|
+
action: 'error',
|
|
188
|
+
reason: err instanceof Error ? err.message : 'Unknown error',
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return results;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Singleton instance
|
|
196
|
+
let _service = null;
|
|
197
|
+
export function getIntroExpirationService() {
|
|
198
|
+
if (!_service) {
|
|
199
|
+
_service = new IntroExpirationService();
|
|
200
|
+
}
|
|
201
|
+
return _service;
|
|
202
|
+
}
|
|
203
|
+
export function startIntroExpirationService() {
|
|
204
|
+
getIntroExpirationService().start();
|
|
205
|
+
}
|
|
206
|
+
export function stopIntroExpirationService() {
|
|
207
|
+
if (_service) {
|
|
208
|
+
_service.stop();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=intro-expiration.js.map
|
|
@@ -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,64 @@ 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
|
+
}>;
|
|
177
|
+
/**
|
|
178
|
+
* List collaborators for a repository via Nango Proxy.
|
|
179
|
+
* Uses the GitHub App connection to access repository collaborators.
|
|
180
|
+
* @param connectionId - GitHub App connection ID
|
|
181
|
+
* @param owner - Repository owner
|
|
182
|
+
* @param repo - Repository name
|
|
183
|
+
* @returns List of collaborators with their permissions
|
|
184
|
+
*/
|
|
185
|
+
listRepoCollaborators(connectionId: string, owner: string, repo: string): Promise<Array<{
|
|
186
|
+
id: number;
|
|
187
|
+
login: string;
|
|
188
|
+
avatarUrl: string;
|
|
189
|
+
permission: 'admin' | 'write' | 'read' | 'none';
|
|
190
|
+
}>>;
|
|
117
191
|
/**
|
|
118
192
|
* Verify webhook signature sent by Nango.
|
|
119
193
|
* Uses the new verifyIncomingWebhookRequest method.
|
|
@@ -46,12 +46,93 @@ class NangoService {
|
|
|
46
46
|
* For API calls, use the proxy methods instead.
|
|
47
47
|
*/
|
|
48
48
|
async getGithubAppToken(connectionId) {
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
try {
|
|
50
|
+
const token = await this.client.getToken(NANGO_INTEGRATIONS.GITHUB_APP, connectionId, false, true);
|
|
51
|
+
// Handle different return formats from Nango
|
|
52
|
+
if (typeof token === 'string') {
|
|
53
|
+
return token;
|
|
54
|
+
}
|
|
55
|
+
// Nango may return an object with access_token
|
|
56
|
+
if (token && typeof token === 'object') {
|
|
57
|
+
const tokenObj = token;
|
|
58
|
+
if (tokenObj.access_token) {
|
|
59
|
+
return tokenObj.access_token;
|
|
60
|
+
}
|
|
61
|
+
if (tokenObj.token) {
|
|
62
|
+
return tokenObj.token;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
console.error('[nango] Unexpected token format:', typeof token, token);
|
|
66
|
+
throw new Error('Expected GitHub App token to be a string');
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
// Handle 404 (connection not found) gracefully
|
|
70
|
+
const error = err;
|
|
71
|
+
const status = error.response?.status || error.status;
|
|
72
|
+
if (status === 404) {
|
|
73
|
+
throw new Error(`GitHub App connection not found: ${connectionId} (may have been disconnected)`);
|
|
74
|
+
}
|
|
75
|
+
// Re-throw with cleaner message
|
|
76
|
+
throw new Error(`Failed to get GitHub App token: ${err.message || 'Unknown error'}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Retrieve the user's OAuth access token from a GitHub App OAuth connection.
|
|
81
|
+
* This is the user-level token (not the installation token).
|
|
82
|
+
* Use this for operations that require user context (e.g., gh CLI).
|
|
83
|
+
*
|
|
84
|
+
* The user token can be found in:
|
|
85
|
+
* 1. getToken() without installation flag
|
|
86
|
+
* 2. connection_config.access_token in github-app-oauth
|
|
87
|
+
* 3. Separate 'github' user connection
|
|
88
|
+
*/
|
|
89
|
+
async getGithubUserOAuthToken(connectionId) {
|
|
90
|
+
// First try: Get token from github-app-oauth connection credentials
|
|
91
|
+
try {
|
|
92
|
+
const token = await this.client.getToken(NANGO_INTEGRATIONS.GITHUB_APP, connectionId);
|
|
93
|
+
if (typeof token === 'string' && token.length > 0) {
|
|
94
|
+
return token;
|
|
95
|
+
}
|
|
96
|
+
if (token && typeof token === 'object') {
|
|
97
|
+
const tokenObj = token;
|
|
98
|
+
if (tokenObj.access_token) {
|
|
99
|
+
return tokenObj.access_token;
|
|
100
|
+
}
|
|
101
|
+
if (tokenObj.token) {
|
|
102
|
+
return tokenObj.token;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
console.log('[nango] getToken for user OAuth failed, trying connection_config:', err);
|
|
108
|
+
}
|
|
109
|
+
// Second try: Check connection_config for user token
|
|
110
|
+
try {
|
|
111
|
+
const connection = await this.client.getConnection(NANGO_INTEGRATIONS.GITHUB_APP, connectionId);
|
|
112
|
+
const connConfig = connection.connection_config;
|
|
113
|
+
if (connConfig?.access_token && typeof connConfig.access_token === 'string') {
|
|
114
|
+
return connConfig.access_token;
|
|
115
|
+
}
|
|
116
|
+
// Also check credentials object
|
|
117
|
+
const credentials = connection.credentials;
|
|
118
|
+
if (credentials?.access_token) {
|
|
119
|
+
return credentials.access_token;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
console.log('[nango] connection_config check failed:', err);
|
|
124
|
+
}
|
|
125
|
+
throw new Error('Could not retrieve GitHub user OAuth token');
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Retrieve the user's OAuth token from a 'github' user connection.
|
|
129
|
+
* This is for the separate GitHub OAuth login (not the App connection).
|
|
130
|
+
*/
|
|
131
|
+
async getGithubUserToken(connectionId) {
|
|
132
|
+
const token = await this.client.getToken(NANGO_INTEGRATIONS.GITHUB_USER, connectionId);
|
|
51
133
|
if (typeof token === 'string') {
|
|
52
134
|
return token;
|
|
53
135
|
}
|
|
54
|
-
// Nango may return an object with access_token
|
|
55
136
|
if (token && typeof token === 'object') {
|
|
56
137
|
const tokenObj = token;
|
|
57
138
|
if (tokenObj.access_token) {
|
|
@@ -61,8 +142,7 @@ class NangoService {
|
|
|
61
142
|
return tokenObj.token;
|
|
62
143
|
}
|
|
63
144
|
}
|
|
64
|
-
|
|
65
|
-
throw new Error('Expected GitHub App token to be a string');
|
|
145
|
+
throw new Error('Could not retrieve GitHub user token');
|
|
66
146
|
}
|
|
67
147
|
/**
|
|
68
148
|
* List repositories available to a GitHub App installation using the Nango Proxy.
|
|
@@ -162,6 +242,139 @@ class NangoService {
|
|
|
162
242
|
const connection = await this.client.getConnection(providerConfigKey, connectionId);
|
|
163
243
|
return connection;
|
|
164
244
|
}
|
|
245
|
+
/**
|
|
246
|
+
* Check if user has access to a specific GitHub repository.
|
|
247
|
+
* Uses the user's OAuth connection to query GitHub API.
|
|
248
|
+
* @param connectionId - User's Nango connection ID (github user OAuth)
|
|
249
|
+
* @param owner - Repository owner
|
|
250
|
+
* @param repo - Repository name
|
|
251
|
+
* @returns Access details or null if no access
|
|
252
|
+
*/
|
|
253
|
+
async checkUserRepoAccess(connectionId, owner, repo) {
|
|
254
|
+
try {
|
|
255
|
+
const response = await this.client.get({
|
|
256
|
+
connectionId,
|
|
257
|
+
providerConfigKey: NANGO_INTEGRATIONS.GITHUB_USER,
|
|
258
|
+
endpoint: `/repos/${owner}/${repo}`,
|
|
259
|
+
});
|
|
260
|
+
const data = response.data;
|
|
261
|
+
let permission = 'none';
|
|
262
|
+
if (data.permissions) {
|
|
263
|
+
if (data.permissions.admin) {
|
|
264
|
+
permission = 'admin';
|
|
265
|
+
}
|
|
266
|
+
else if (data.permissions.push) {
|
|
267
|
+
permission = 'write';
|
|
268
|
+
}
|
|
269
|
+
else if (data.permissions.pull) {
|
|
270
|
+
permission = 'read';
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
hasAccess: true,
|
|
275
|
+
permission,
|
|
276
|
+
repository: {
|
|
277
|
+
id: data.id,
|
|
278
|
+
fullName: data.full_name,
|
|
279
|
+
isPrivate: data.private,
|
|
280
|
+
defaultBranch: data.default_branch,
|
|
281
|
+
},
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
catch (err) {
|
|
285
|
+
// 404 = no access or repo doesn't exist
|
|
286
|
+
const error = err;
|
|
287
|
+
if (error.response?.status === 404 || error.response?.status === 403) {
|
|
288
|
+
return { hasAccess: false };
|
|
289
|
+
}
|
|
290
|
+
console.error('[nango] checkUserRepoAccess error:', err);
|
|
291
|
+
throw err;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* List all repositories the user has access to via their OAuth connection.
|
|
296
|
+
* Uses the user's personal OAuth token (not the GitHub App).
|
|
297
|
+
* @param connectionId - User's Nango connection ID (github user OAuth)
|
|
298
|
+
* @param options - Pagination and filter options
|
|
299
|
+
* @returns List of accessible repositories
|
|
300
|
+
*/
|
|
301
|
+
async listUserAccessibleRepos(connectionId, options) {
|
|
302
|
+
const page = options?.page ?? 1;
|
|
303
|
+
const perPage = options?.perPage ?? 100;
|
|
304
|
+
const type = options?.type ?? 'all';
|
|
305
|
+
const sort = options?.sort ?? 'updated';
|
|
306
|
+
const response = await this.client.get({
|
|
307
|
+
connectionId,
|
|
308
|
+
providerConfigKey: NANGO_INTEGRATIONS.GITHUB_USER,
|
|
309
|
+
endpoint: '/user/repos',
|
|
310
|
+
params: {
|
|
311
|
+
page: String(page),
|
|
312
|
+
per_page: String(perPage),
|
|
313
|
+
type,
|
|
314
|
+
sort,
|
|
315
|
+
direction: 'desc',
|
|
316
|
+
},
|
|
317
|
+
});
|
|
318
|
+
const repos = response.data || [];
|
|
319
|
+
return {
|
|
320
|
+
repositories: repos.map(r => ({
|
|
321
|
+
id: r.id,
|
|
322
|
+
fullName: r.full_name,
|
|
323
|
+
isPrivate: r.private,
|
|
324
|
+
defaultBranch: r.default_branch,
|
|
325
|
+
permissions: r.permissions || { admin: false, push: false, pull: false },
|
|
326
|
+
})),
|
|
327
|
+
hasMore: repos.length === perPage,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* List collaborators for a repository via Nango Proxy.
|
|
332
|
+
* Uses the GitHub App connection to access repository collaborators.
|
|
333
|
+
* @param connectionId - GitHub App connection ID
|
|
334
|
+
* @param owner - Repository owner
|
|
335
|
+
* @param repo - Repository name
|
|
336
|
+
* @returns List of collaborators with their permissions
|
|
337
|
+
*/
|
|
338
|
+
async listRepoCollaborators(connectionId, owner, repo) {
|
|
339
|
+
try {
|
|
340
|
+
const response = await this.client.get({
|
|
341
|
+
connectionId,
|
|
342
|
+
providerConfigKey: NANGO_INTEGRATIONS.GITHUB_APP,
|
|
343
|
+
endpoint: `/repos/${owner}/${repo}/collaborators`,
|
|
344
|
+
params: { per_page: '100' },
|
|
345
|
+
});
|
|
346
|
+
return (response.data || []).map(collab => {
|
|
347
|
+
let permission = 'none';
|
|
348
|
+
if (collab.permissions) {
|
|
349
|
+
if (collab.permissions.admin) {
|
|
350
|
+
permission = 'admin';
|
|
351
|
+
}
|
|
352
|
+
else if (collab.permissions.push) {
|
|
353
|
+
permission = 'write';
|
|
354
|
+
}
|
|
355
|
+
else if (collab.permissions.pull) {
|
|
356
|
+
permission = 'read';
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return {
|
|
360
|
+
id: collab.id,
|
|
361
|
+
login: collab.login,
|
|
362
|
+
avatarUrl: collab.avatar_url,
|
|
363
|
+
permission,
|
|
364
|
+
};
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
catch (err) {
|
|
368
|
+
const error = err;
|
|
369
|
+
// 403 = no permission to view collaborators, 404 = repo not found
|
|
370
|
+
if (error.response?.status === 403 || error.response?.status === 404) {
|
|
371
|
+
console.warn(`[nango] Cannot list collaborators for ${owner}/${repo}: status ${error.response.status}`);
|
|
372
|
+
return [];
|
|
373
|
+
}
|
|
374
|
+
console.error('[nango] listRepoCollaborators error:', err);
|
|
375
|
+
throw err;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
165
378
|
/**
|
|
166
379
|
* Verify webhook signature sent by Nango.
|
|
167
380
|
* Uses the new verifyIncomingWebhookRequest method.
|
|
@@ -122,4 +122,26 @@ export declare function recordComputeUsage(userId: string, workspaceId: string,
|
|
|
122
122
|
* Update active agent count for a user
|
|
123
123
|
*/
|
|
124
124
|
export declare function updateActiveAgentCount(userId: string, workspaceId: string, count: number): Promise<void>;
|
|
125
|
+
/**
|
|
126
|
+
* Resource tier name type
|
|
127
|
+
*/
|
|
128
|
+
export type ResourceTierName = 'small' | 'medium' | 'large' | 'xlarge';
|
|
129
|
+
/**
|
|
130
|
+
* Get the default resource tier for a plan
|
|
131
|
+
* Maps plans to appropriate compute resources
|
|
132
|
+
*/
|
|
133
|
+
export declare function getResourceTierForPlan(plan: PlanType): ResourceTierName;
|
|
134
|
+
/**
|
|
135
|
+
* Get the maximum resource tier a plan can scale to
|
|
136
|
+
* Prevents over-scaling beyond plan entitlements
|
|
137
|
+
*/
|
|
138
|
+
export declare function getMaxResourceTierForPlan(plan: PlanType): ResourceTierName;
|
|
139
|
+
/**
|
|
140
|
+
* Check if user's plan allows auto-scaling
|
|
141
|
+
*/
|
|
142
|
+
export declare function canAutoScale(plan: PlanType): boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Check if auto-scale to a specific tier is allowed for a plan
|
|
145
|
+
*/
|
|
146
|
+
export declare function canScaleToTier(plan: PlanType, targetTier: ResourceTierName): boolean;
|
|
125
147
|
//# sourceMappingURL=planLimits.d.ts.map
|
|
@@ -18,17 +18,17 @@ import { getDb } from '../db/drizzle.js';
|
|
|
18
18
|
export const PLAN_LIMITS = {
|
|
19
19
|
free: {
|
|
20
20
|
maxWorkspaces: 1,
|
|
21
|
-
maxRepos:
|
|
21
|
+
maxRepos: 2,
|
|
22
22
|
maxConcurrentAgents: 2,
|
|
23
|
-
maxComputeHoursPerMonth:
|
|
23
|
+
maxComputeHoursPerMonth: 5, // Limited free tier
|
|
24
24
|
coordinatorsEnabled: false,
|
|
25
25
|
sessionPersistence: false,
|
|
26
26
|
},
|
|
27
27
|
pro: {
|
|
28
28
|
maxWorkspaces: 5,
|
|
29
|
-
maxRepos:
|
|
30
|
-
maxConcurrentAgents:
|
|
31
|
-
maxComputeHoursPerMonth:
|
|
29
|
+
maxRepos: 10,
|
|
30
|
+
maxConcurrentAgents: 5,
|
|
31
|
+
maxComputeHoursPerMonth: 50,
|
|
32
32
|
coordinatorsEnabled: true,
|
|
33
33
|
sessionPersistence: true,
|
|
34
34
|
},
|
|
@@ -279,4 +279,57 @@ export async function updateActiveAgentCount(userId, workspaceId, count) {
|
|
|
279
279
|
recordedAt: new Date(),
|
|
280
280
|
});
|
|
281
281
|
}
|
|
282
|
+
/**
|
|
283
|
+
* Get the default resource tier for a plan
|
|
284
|
+
* Maps plans to appropriate compute resources
|
|
285
|
+
*/
|
|
286
|
+
export function getResourceTierForPlan(plan) {
|
|
287
|
+
switch (plan) {
|
|
288
|
+
case 'free':
|
|
289
|
+
return 'small'; // 2GB, 2 CPUs - suitable for 2 agents
|
|
290
|
+
case 'pro':
|
|
291
|
+
return 'medium'; // 4GB, 4 CPUs - suitable for 5 agents
|
|
292
|
+
case 'team':
|
|
293
|
+
return 'large'; // 8GB, 4 CPUs - suitable for 10 agents
|
|
294
|
+
case 'enterprise':
|
|
295
|
+
return 'xlarge'; // 16GB, 8 CPUs - suitable for 20 agents
|
|
296
|
+
default:
|
|
297
|
+
return 'small';
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Get the maximum resource tier a plan can scale to
|
|
302
|
+
* Prevents over-scaling beyond plan entitlements
|
|
303
|
+
*/
|
|
304
|
+
export function getMaxResourceTierForPlan(plan) {
|
|
305
|
+
switch (plan) {
|
|
306
|
+
case 'free':
|
|
307
|
+
return 'small'; // Free tier cannot scale up
|
|
308
|
+
case 'pro':
|
|
309
|
+
return 'medium'; // Pro can scale to medium
|
|
310
|
+
case 'team':
|
|
311
|
+
return 'large'; // Team can scale to large
|
|
312
|
+
case 'enterprise':
|
|
313
|
+
return 'xlarge'; // Enterprise can use any tier
|
|
314
|
+
default:
|
|
315
|
+
return 'small';
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Check if user's plan allows auto-scaling
|
|
320
|
+
*/
|
|
321
|
+
export function canAutoScale(plan) {
|
|
322
|
+
// Only Pro and above can auto-scale
|
|
323
|
+
return plan !== 'free';
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Check if auto-scale to a specific tier is allowed for a plan
|
|
327
|
+
*/
|
|
328
|
+
export function canScaleToTier(plan, targetTier) {
|
|
329
|
+
const tierOrder = ['small', 'medium', 'large', 'xlarge'];
|
|
330
|
+
const maxTier = getMaxResourceTierForPlan(plan);
|
|
331
|
+
const targetIndex = tierOrder.indexOf(targetTier);
|
|
332
|
+
const maxIndex = tierOrder.indexOf(maxTier);
|
|
333
|
+
return targetIndex <= maxIndex;
|
|
334
|
+
}
|
|
282
335
|
//# sourceMappingURL=planLimits.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSH Security Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides secure SSH password derivation for workspace containers.
|
|
5
|
+
* Uses a deterministic approach based on workspace ID + secret salt,
|
|
6
|
+
* ensuring each workspace has a unique password without storage.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Derive a unique SSH password for a workspace.
|
|
10
|
+
*
|
|
11
|
+
* Uses SHA-256 hash of (workspaceId + salt) to generate a deterministic
|
|
12
|
+
* but unique password for each workspace. This approach:
|
|
13
|
+
* - Ensures each workspace has a unique password
|
|
14
|
+
* - Requires no database storage
|
|
15
|
+
* - Produces consistent results across cloud server and container
|
|
16
|
+
*
|
|
17
|
+
* SECURITY: Set SSH_PASSWORD_SALT environment variable in production!
|
|
18
|
+
* The default salt is insecure and should never be used in production.
|
|
19
|
+
*
|
|
20
|
+
* @param workspaceId - The workspace UUID
|
|
21
|
+
* @returns A 24-character hex password (96 bits of entropy)
|
|
22
|
+
*/
|
|
23
|
+
export declare function deriveSshPassword(workspaceId: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Validate that SSH security is properly configured.
|
|
26
|
+
* Call this at server startup to catch configuration issues early.
|
|
27
|
+
*
|
|
28
|
+
* @returns true if properly configured, false otherwise
|
|
29
|
+
*/
|
|
30
|
+
export declare function validateSshSecurityConfig(): boolean;
|
|
31
|
+
//# sourceMappingURL=ssh-security.d.ts.map
|