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
package/dist/cloud/server.js
CHANGED
|
@@ -8,13 +8,14 @@ import helmet from 'helmet';
|
|
|
8
8
|
import crypto from 'crypto';
|
|
9
9
|
import path from 'node:path';
|
|
10
10
|
import http from 'node:http';
|
|
11
|
+
import fs from 'node:fs';
|
|
11
12
|
import { fileURLToPath } from 'node:url';
|
|
12
13
|
import { createClient } from 'redis';
|
|
13
14
|
import { RedisStore } from 'connect-redis';
|
|
14
15
|
import { WebSocketServer, WebSocket } from 'ws';
|
|
15
16
|
import { getConfig } from './config.js';
|
|
16
17
|
import { runMigrations } from './db/index.js';
|
|
17
|
-
import { getScalingOrchestrator } from './services/index.js';
|
|
18
|
+
import { getScalingOrchestrator, getComputeEnforcementService, getIntroExpirationService } from './services/index.js';
|
|
18
19
|
const __filename = fileURLToPath(import.meta.url);
|
|
19
20
|
const __dirname = path.dirname(__filename);
|
|
20
21
|
// API routers
|
|
@@ -34,7 +35,10 @@ import { webhooksRouter } from './api/webhooks.js';
|
|
|
34
35
|
import { githubAppRouter } from './api/github-app.js';
|
|
35
36
|
import { nangoAuthRouter } from './api/nango-auth.js';
|
|
36
37
|
import { gitRouter } from './api/git.js';
|
|
38
|
+
import { codexAuthHelperRouter } from './api/codex-auth-helper.js';
|
|
39
|
+
import { adminRouter } from './api/admin.js';
|
|
37
40
|
import { db } from './db/index.js';
|
|
41
|
+
import { validateSshSecurityConfig } from './services/ssh-security.js';
|
|
38
42
|
/**
|
|
39
43
|
* Proxy a request to the user's primary running workspace
|
|
40
44
|
*/
|
|
@@ -65,6 +69,8 @@ async function proxyToUserWorkspace(req, res, path) {
|
|
|
65
69
|
}
|
|
66
70
|
export async function createServer() {
|
|
67
71
|
const config = getConfig();
|
|
72
|
+
// Validate security configuration at startup
|
|
73
|
+
validateSshSecurityConfig();
|
|
68
74
|
const app = express();
|
|
69
75
|
app.set('trust proxy', 1);
|
|
70
76
|
// Redis client for sessions
|
|
@@ -98,7 +104,9 @@ export async function createServer() {
|
|
|
98
104
|
credentials: true,
|
|
99
105
|
}));
|
|
100
106
|
// Custom JSON parser that preserves raw body for webhook signature verification
|
|
107
|
+
// Increase limit to 10mb for base64 image uploads (screenshots)
|
|
101
108
|
app.use(express.json({
|
|
109
|
+
limit: '10mb',
|
|
102
110
|
verify: (req, _res, buf) => {
|
|
103
111
|
// Store raw body for webhook signature verification
|
|
104
112
|
req.rawBody = buf.toString();
|
|
@@ -168,10 +176,11 @@ export async function createServer() {
|
|
|
168
176
|
});
|
|
169
177
|
// Lightweight CSRF protection using session token
|
|
170
178
|
const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);
|
|
171
|
-
// Paths exempt from CSRF (webhooks from external services, workspace proxy)
|
|
179
|
+
// Paths exempt from CSRF (webhooks from external services, workspace proxy, local auth callbacks)
|
|
172
180
|
const CSRF_EXEMPT_PATHS = [
|
|
173
181
|
'/api/webhooks/',
|
|
174
182
|
'/api/auth/nango/webhook',
|
|
183
|
+
'/api/auth/codex-helper/callback',
|
|
175
184
|
];
|
|
176
185
|
// Additional pattern for workspace proxy routes (contains /proxy/)
|
|
177
186
|
const isWorkspaceProxyRoute = (path) => /^\/api\/workspaces\/[^/]+\/proxy\//.test(path);
|
|
@@ -222,26 +231,37 @@ export async function createServer() {
|
|
|
222
231
|
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
|
223
232
|
});
|
|
224
233
|
// API routes
|
|
225
|
-
|
|
234
|
+
//
|
|
235
|
+
// IMPORTANT: Route order matters! Routes with non-session auth (webhooks, API keys, tokens)
|
|
236
|
+
// must be mounted BEFORE teamsRouter, which catches all /api/* with requireAuth.
|
|
237
|
+
//
|
|
238
|
+
// --- Routes with alternative auth (must be before teamsRouter) ---
|
|
239
|
+
app.use('/api/auth', authRouter); // Login endpoints (public)
|
|
240
|
+
app.use('/api/auth/nango', nangoAuthRouter); // Nango webhook (signature verification)
|
|
241
|
+
app.use('/api/auth/codex-helper', codexAuthHelperRouter);
|
|
242
|
+
app.use('/api/git', gitRouter); // Workspace token auth
|
|
243
|
+
app.use('/api/webhooks', webhooksRouter); // GitHub webhooks (signature verification)
|
|
244
|
+
app.use('/api/monitoring', monitoringRouter); // Daemon API key auth endpoints
|
|
245
|
+
app.use('/api/daemons', daemonsRouter); // Daemon API key auth endpoints
|
|
246
|
+
app.use('/api/admin', adminRouter); // Admin API secret auth
|
|
247
|
+
// --- Routes with session auth ---
|
|
226
248
|
app.use('/api/providers', providersRouter);
|
|
227
249
|
app.use('/api/workspaces', workspacesRouter);
|
|
228
250
|
app.use('/api/repos', reposRouter);
|
|
229
251
|
app.use('/api/onboarding', onboardingRouter);
|
|
230
|
-
app.use('/api/teams', teamsRouter);
|
|
231
252
|
app.use('/api/billing', billingRouter);
|
|
232
253
|
app.use('/api/usage', usageRouter);
|
|
233
254
|
app.use('/api/project-groups', coordinatorsRouter);
|
|
234
|
-
app.use('/api/daemons', daemonsRouter);
|
|
235
|
-
app.use('/api/monitoring', monitoringRouter);
|
|
236
|
-
app.use('/api/webhooks', webhooksRouter);
|
|
237
255
|
app.use('/api/github-app', githubAppRouter);
|
|
238
|
-
app.use('/api/auth/nango', nangoAuthRouter);
|
|
239
|
-
app.use('/api/git', gitRouter);
|
|
240
256
|
// Test helper routes (only available in non-production)
|
|
257
|
+
// MUST be before teamsRouter to avoid auth interception
|
|
241
258
|
if (process.env.NODE_ENV !== 'production') {
|
|
242
259
|
app.use('/api/test', testHelpersRouter);
|
|
243
260
|
console.log('[cloud] Test helper routes enabled (non-production mode)');
|
|
244
261
|
}
|
|
262
|
+
// Teams router - MUST BE LAST among /api routes
|
|
263
|
+
// Handles /workspaces/:id/members and /invites with requireAuth on all routes
|
|
264
|
+
app.use('/api', teamsRouter);
|
|
245
265
|
// Trajectory proxy routes - auto-detect user's workspace and forward
|
|
246
266
|
// These are convenience routes so the dashboard doesn't need to know the workspace ID
|
|
247
267
|
app.get('/api/trajectory', requireAuth, async (req, res) => {
|
|
@@ -259,17 +279,29 @@ export async function createServer() {
|
|
|
259
279
|
// Serve static dashboard files (Next.js static export)
|
|
260
280
|
// Path: dist/cloud/server.js -> ../../src/dashboard/out
|
|
261
281
|
const dashboardPath = path.join(__dirname, '../../src/dashboard/out');
|
|
262
|
-
// Serve static files
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
//
|
|
266
|
-
//
|
|
282
|
+
// Serve static files (JS, CSS, images, etc.)
|
|
283
|
+
app.use(express.static(dashboardPath));
|
|
284
|
+
// Handle clean URLs for Next.js static export
|
|
285
|
+
// When a directory exists (e.g., /app/), express.static won't serve app.html
|
|
286
|
+
// So we need to explicitly check for .html files
|
|
267
287
|
app.get('/{*splat}', (req, res, next) => {
|
|
268
|
-
// Don't
|
|
288
|
+
// Don't handle API routes
|
|
269
289
|
if (req.path.startsWith('/api/')) {
|
|
270
290
|
return next();
|
|
271
291
|
}
|
|
272
|
-
|
|
292
|
+
// Clean the path (remove trailing slash)
|
|
293
|
+
const cleanPath = req.path.replace(/\/$/, '') || '/';
|
|
294
|
+
// Try to serve the corresponding .html file
|
|
295
|
+
const htmlFile = cleanPath === '/' ? 'index.html' : `${cleanPath}.html`;
|
|
296
|
+
const htmlPath = path.join(dashboardPath, htmlFile);
|
|
297
|
+
// Check if the HTML file exists
|
|
298
|
+
if (fs.existsSync(htmlPath)) {
|
|
299
|
+
res.sendFile(htmlPath);
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
// Fallback to index.html for SPA-style routing
|
|
303
|
+
res.sendFile(path.join(dashboardPath, 'index.html'));
|
|
304
|
+
}
|
|
273
305
|
});
|
|
274
306
|
// Error handler
|
|
275
307
|
app.use((err, req, res, _next) => {
|
|
@@ -282,6 +314,8 @@ export async function createServer() {
|
|
|
282
314
|
// Server lifecycle
|
|
283
315
|
let server = null;
|
|
284
316
|
let scalingOrchestrator = null;
|
|
317
|
+
let computeEnforcement = null;
|
|
318
|
+
let introExpiration = null;
|
|
285
319
|
// Create HTTP server for WebSocket upgrade handling
|
|
286
320
|
const httpServer = http.createServer(app);
|
|
287
321
|
// ===== Presence WebSocket =====
|
|
@@ -313,6 +347,77 @@ export async function createServer() {
|
|
|
313
347
|
return false;
|
|
314
348
|
}
|
|
315
349
|
};
|
|
350
|
+
// WebSocket server for agent logs (proxied to workspace daemon)
|
|
351
|
+
const wssLogs = new WebSocketServer({ noServer: true, perMessageDeflate: false });
|
|
352
|
+
// Handle agent logs WebSocket connections
|
|
353
|
+
wssLogs.on('connection', async (clientWs, workspaceId, agentName) => {
|
|
354
|
+
console.log(`[ws/logs] Client connected for workspace=${workspaceId} agent=${agentName}`);
|
|
355
|
+
let daemonWs = null;
|
|
356
|
+
try {
|
|
357
|
+
// Find the workspace
|
|
358
|
+
const workspace = await db.workspaces.findById(workspaceId);
|
|
359
|
+
if (!workspace || !workspace.publicUrl) {
|
|
360
|
+
clientWs.send(JSON.stringify({ type: 'error', message: 'Workspace not found or not running' }));
|
|
361
|
+
clientWs.close();
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
// Connect to workspace daemon WebSocket
|
|
365
|
+
// The workspace runs the dashboard server which expects /ws/logs path
|
|
366
|
+
const baseUrl = workspace.publicUrl.replace(/^http/, 'ws').replace(/\/$/, '');
|
|
367
|
+
const daemonWsUrl = `${baseUrl}/ws/logs/${encodeURIComponent(agentName)}`;
|
|
368
|
+
console.log(`[ws/logs] Connecting to daemon: ${daemonWsUrl}`);
|
|
369
|
+
daemonWs = new WebSocket(daemonWsUrl, { perMessageDeflate: false });
|
|
370
|
+
daemonWs.on('open', () => {
|
|
371
|
+
console.log(`[ws/logs] Connected to daemon for ${agentName}`);
|
|
372
|
+
// Note: No need to send subscribe message - the agent name in the URL path
|
|
373
|
+
// triggers auto-subscription in the dashboard server
|
|
374
|
+
});
|
|
375
|
+
daemonWs.on('message', (data) => {
|
|
376
|
+
// Forward daemon messages to client
|
|
377
|
+
if (clientWs.readyState === WebSocket.OPEN) {
|
|
378
|
+
clientWs.send(data.toString());
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
daemonWs.on('close', () => {
|
|
382
|
+
console.log(`[ws/logs] Daemon connection closed for ${agentName}`);
|
|
383
|
+
if (clientWs.readyState === WebSocket.OPEN) {
|
|
384
|
+
clientWs.close();
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
daemonWs.on('error', (err) => {
|
|
388
|
+
console.error(`[ws/logs] Daemon WebSocket error:`, err);
|
|
389
|
+
if (clientWs.readyState === WebSocket.OPEN) {
|
|
390
|
+
clientWs.send(JSON.stringify({ type: 'error', message: 'Daemon connection error' }));
|
|
391
|
+
clientWs.close();
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
// Forward client messages to daemon (for user input)
|
|
395
|
+
clientWs.on('message', (data) => {
|
|
396
|
+
if (daemonWs && daemonWs.readyState === WebSocket.OPEN) {
|
|
397
|
+
daemonWs.send(data.toString());
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
clientWs.on('close', () => {
|
|
401
|
+
console.log(`[ws/logs] Client disconnected for ${agentName}`);
|
|
402
|
+
if (daemonWs && daemonWs.readyState === WebSocket.OPEN) {
|
|
403
|
+
daemonWs.close();
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
clientWs.on('error', (err) => {
|
|
407
|
+
console.error(`[ws/logs] Client WebSocket error:`, err);
|
|
408
|
+
if (daemonWs && daemonWs.readyState === WebSocket.OPEN) {
|
|
409
|
+
daemonWs.close();
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
catch (err) {
|
|
414
|
+
console.error(`[ws/logs] Setup error:`, err);
|
|
415
|
+
if (clientWs.readyState === WebSocket.OPEN) {
|
|
416
|
+
clientWs.send(JSON.stringify({ type: 'error', message: 'Failed to connect to workspace' }));
|
|
417
|
+
clientWs.close();
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
});
|
|
316
421
|
// Handle HTTP upgrade for WebSocket
|
|
317
422
|
httpServer.on('upgrade', (request, socket, head) => {
|
|
318
423
|
const pathname = new URL(request.url || '', `http://${request.headers.host}`).pathname;
|
|
@@ -321,6 +426,20 @@ export async function createServer() {
|
|
|
321
426
|
wssPresence.emit('connection', ws, request);
|
|
322
427
|
});
|
|
323
428
|
}
|
|
429
|
+
else if (pathname.startsWith('/ws/logs/')) {
|
|
430
|
+
// Parse /ws/logs/:workspaceId/:agentName
|
|
431
|
+
const parts = pathname.split('/').filter(Boolean);
|
|
432
|
+
if (parts.length >= 4) {
|
|
433
|
+
const workspaceId = decodeURIComponent(parts[2]);
|
|
434
|
+
const agentName = decodeURIComponent(parts[3]);
|
|
435
|
+
wssLogs.handleUpgrade(request, socket, head, (ws) => {
|
|
436
|
+
wssLogs.emit('connection', ws, workspaceId, agentName);
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
socket.destroy();
|
|
441
|
+
}
|
|
442
|
+
}
|
|
324
443
|
else {
|
|
325
444
|
// Unknown WebSocket path - destroy socket
|
|
326
445
|
socket.destroy();
|
|
@@ -507,6 +626,24 @@ export async function createServer() {
|
|
|
507
626
|
console.warn('[cloud] Failed to initialize scaling orchestrator:', error);
|
|
508
627
|
// Non-fatal - server can run without auto-scaling
|
|
509
628
|
}
|
|
629
|
+
// Start compute enforcement service (checks every 15 min)
|
|
630
|
+
try {
|
|
631
|
+
computeEnforcement = getComputeEnforcementService();
|
|
632
|
+
computeEnforcement.start();
|
|
633
|
+
console.log('[cloud] Compute enforcement service started');
|
|
634
|
+
}
|
|
635
|
+
catch (error) {
|
|
636
|
+
console.warn('[cloud] Failed to start compute enforcement:', error);
|
|
637
|
+
}
|
|
638
|
+
// Start intro expiration service (checks every hour for expired intro periods)
|
|
639
|
+
try {
|
|
640
|
+
introExpiration = getIntroExpirationService();
|
|
641
|
+
introExpiration.start();
|
|
642
|
+
console.log('[cloud] Intro expiration service started');
|
|
643
|
+
}
|
|
644
|
+
catch (error) {
|
|
645
|
+
console.warn('[cloud] Failed to start intro expiration:', error);
|
|
646
|
+
}
|
|
510
647
|
}
|
|
511
648
|
return new Promise((resolve) => {
|
|
512
649
|
server = httpServer.listen(config.port, () => {
|
|
@@ -522,6 +659,14 @@ export async function createServer() {
|
|
|
522
659
|
if (scalingOrchestrator) {
|
|
523
660
|
await scalingOrchestrator.shutdown();
|
|
524
661
|
}
|
|
662
|
+
// Stop compute enforcement service
|
|
663
|
+
if (computeEnforcement) {
|
|
664
|
+
computeEnforcement.stop();
|
|
665
|
+
}
|
|
666
|
+
// Stop intro expiration service
|
|
667
|
+
if (introExpiration) {
|
|
668
|
+
introExpiration.stop();
|
|
669
|
+
}
|
|
525
670
|
// Close WebSocket server
|
|
526
671
|
wssPresence.close();
|
|
527
672
|
if (server) {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compute Enforcement Service
|
|
3
|
+
*
|
|
4
|
+
* Enforces compute hour limits for free tier users.
|
|
5
|
+
* Runs periodically to check usage and stop workspaces that have exceeded limits.
|
|
6
|
+
*/
|
|
7
|
+
import { PlanType } from '../db/index.js';
|
|
8
|
+
export interface ComputeEnforcementConfig {
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
checkIntervalMs: number;
|
|
11
|
+
warningThresholdPercent: number;
|
|
12
|
+
}
|
|
13
|
+
export interface EnforcementResult {
|
|
14
|
+
userId: string;
|
|
15
|
+
plan: PlanType;
|
|
16
|
+
computeHoursUsed: number;
|
|
17
|
+
computeHoursLimit: number;
|
|
18
|
+
action: 'none' | 'warning' | 'stopped';
|
|
19
|
+
workspacesStopped: string[];
|
|
20
|
+
}
|
|
21
|
+
export declare class ComputeEnforcementService {
|
|
22
|
+
private config;
|
|
23
|
+
private checkTimer;
|
|
24
|
+
private isRunning;
|
|
25
|
+
constructor(config?: Partial<ComputeEnforcementConfig>);
|
|
26
|
+
/**
|
|
27
|
+
* Start the enforcement service
|
|
28
|
+
*/
|
|
29
|
+
start(): void;
|
|
30
|
+
/**
|
|
31
|
+
* Stop the enforcement service
|
|
32
|
+
*/
|
|
33
|
+
stop(): void;
|
|
34
|
+
/**
|
|
35
|
+
* Run enforcement check for all free tier users
|
|
36
|
+
*/
|
|
37
|
+
runEnforcement(): Promise<EnforcementResult[]>;
|
|
38
|
+
/**
|
|
39
|
+
* Enforce limits for a specific user
|
|
40
|
+
*/
|
|
41
|
+
enforceUserLimits(userId: string): Promise<EnforcementResult>;
|
|
42
|
+
/**
|
|
43
|
+
* Manually trigger enforcement for a specific user
|
|
44
|
+
*/
|
|
45
|
+
enforceUser(userId: string): Promise<EnforcementResult>;
|
|
46
|
+
/**
|
|
47
|
+
* Get service status
|
|
48
|
+
*/
|
|
49
|
+
getStatus(): {
|
|
50
|
+
enabled: boolean;
|
|
51
|
+
isRunning: boolean;
|
|
52
|
+
checkIntervalMs: number;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
export declare function getComputeEnforcementService(): ComputeEnforcementService;
|
|
56
|
+
export declare function createComputeEnforcementService(config?: Partial<ComputeEnforcementConfig>): ComputeEnforcementService;
|
|
57
|
+
//# sourceMappingURL=compute-enforcement.d.ts.map
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compute Enforcement Service
|
|
3
|
+
*
|
|
4
|
+
* Enforces compute hour limits for free tier users.
|
|
5
|
+
* Runs periodically to check usage and stop workspaces that have exceeded limits.
|
|
6
|
+
*/
|
|
7
|
+
import { db } from '../db/index.js';
|
|
8
|
+
import { getProvisioner } from '../provisioner/index.js';
|
|
9
|
+
import { getUserUsage, PLAN_LIMITS } from './planLimits.js';
|
|
10
|
+
const DEFAULT_CONFIG = {
|
|
11
|
+
enabled: true,
|
|
12
|
+
checkIntervalMs: 15 * 60 * 1000, // 15 minutes
|
|
13
|
+
warningThresholdPercent: 80,
|
|
14
|
+
};
|
|
15
|
+
export class ComputeEnforcementService {
|
|
16
|
+
config;
|
|
17
|
+
checkTimer = null;
|
|
18
|
+
isRunning = false;
|
|
19
|
+
constructor(config = {}) {
|
|
20
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Start the enforcement service
|
|
24
|
+
*/
|
|
25
|
+
start() {
|
|
26
|
+
if (!this.config.enabled) {
|
|
27
|
+
console.log('[compute-enforcement] Service disabled');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (this.isRunning) {
|
|
31
|
+
console.warn('[compute-enforcement] Service already running');
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
this.isRunning = true;
|
|
35
|
+
console.log(`[compute-enforcement] Started (checking every ${this.config.checkIntervalMs / 1000}s)`);
|
|
36
|
+
// Run immediately on start
|
|
37
|
+
this.runEnforcement().catch((err) => {
|
|
38
|
+
console.error('[compute-enforcement] Initial run failed:', err);
|
|
39
|
+
});
|
|
40
|
+
// Then run periodically
|
|
41
|
+
this.checkTimer = setInterval(() => {
|
|
42
|
+
this.runEnforcement().catch((err) => {
|
|
43
|
+
console.error('[compute-enforcement] Periodic run failed:', err);
|
|
44
|
+
});
|
|
45
|
+
}, this.config.checkIntervalMs);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Stop the enforcement service
|
|
49
|
+
*/
|
|
50
|
+
stop() {
|
|
51
|
+
if (this.checkTimer) {
|
|
52
|
+
clearInterval(this.checkTimer);
|
|
53
|
+
this.checkTimer = null;
|
|
54
|
+
}
|
|
55
|
+
this.isRunning = false;
|
|
56
|
+
console.log('[compute-enforcement] Stopped');
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Run enforcement check for all free tier users
|
|
60
|
+
*/
|
|
61
|
+
async runEnforcement() {
|
|
62
|
+
const results = [];
|
|
63
|
+
try {
|
|
64
|
+
// Get all users on free tier
|
|
65
|
+
const freeUsers = await db.users.findByPlan('free');
|
|
66
|
+
console.log(`[compute-enforcement] Checking ${freeUsers.length} free tier users`);
|
|
67
|
+
for (const user of freeUsers) {
|
|
68
|
+
try {
|
|
69
|
+
const result = await this.enforceUserLimits(user.id);
|
|
70
|
+
results.push(result);
|
|
71
|
+
if (result.action !== 'none') {
|
|
72
|
+
console.log(`[compute-enforcement] User ${user.id.substring(0, 8)}: ${result.action} ` +
|
|
73
|
+
`(${result.computeHoursUsed.toFixed(2)}/${result.computeHoursLimit}h)`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
console.error(`[compute-enforcement] Error for user ${user.id}:`, err);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const stopped = results.filter((r) => r.action === 'stopped').length;
|
|
81
|
+
const warned = results.filter((r) => r.action === 'warning').length;
|
|
82
|
+
if (stopped > 0 || warned > 0) {
|
|
83
|
+
console.log(`[compute-enforcement] Summary: ${stopped} stopped, ${warned} warned, ` +
|
|
84
|
+
`${results.length - stopped - warned} ok`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
console.error('[compute-enforcement] Failed to run enforcement:', err);
|
|
89
|
+
}
|
|
90
|
+
return results;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Enforce limits for a specific user
|
|
94
|
+
*/
|
|
95
|
+
async enforceUserLimits(userId) {
|
|
96
|
+
const user = await db.users.findById(userId);
|
|
97
|
+
const plan = user?.plan || 'free';
|
|
98
|
+
const limits = PLAN_LIMITS[plan];
|
|
99
|
+
const usage = await getUserUsage(userId);
|
|
100
|
+
const result = {
|
|
101
|
+
userId,
|
|
102
|
+
plan,
|
|
103
|
+
computeHoursUsed: usage.computeHoursThisMonth,
|
|
104
|
+
computeHoursLimit: limits.maxComputeHoursPerMonth,
|
|
105
|
+
action: 'none',
|
|
106
|
+
workspacesStopped: [],
|
|
107
|
+
};
|
|
108
|
+
// Skip if user has unlimited compute (paid plans may have high limits)
|
|
109
|
+
if (limits.maxComputeHoursPerMonth === Infinity) {
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
// Check if user has exceeded limit
|
|
113
|
+
if (usage.computeHoursThisMonth >= limits.maxComputeHoursPerMonth) {
|
|
114
|
+
// Stop all running workspaces
|
|
115
|
+
const workspaces = await db.workspaces.findByUserId(userId);
|
|
116
|
+
const runningWorkspaces = workspaces.filter((w) => w.status === 'running');
|
|
117
|
+
if (runningWorkspaces.length > 0) {
|
|
118
|
+
const provisioner = getProvisioner();
|
|
119
|
+
for (const workspace of runningWorkspaces) {
|
|
120
|
+
try {
|
|
121
|
+
await provisioner.stop(workspace.id);
|
|
122
|
+
result.workspacesStopped.push(workspace.id);
|
|
123
|
+
console.log(`[compute-enforcement] Stopped workspace ${workspace.id.substring(0, 8)} ` +
|
|
124
|
+
`for user ${userId.substring(0, 8)} (limit exceeded)`);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
console.error(`[compute-enforcement] Failed to stop workspace ${workspace.id}:`, err);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
result.action = 'stopped';
|
|
131
|
+
// TODO: Send notification email to user
|
|
132
|
+
// await sendLimitReachedEmail(userId, usage.computeHoursThisMonth, limits.maxComputeHoursPerMonth);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
// Check if approaching limit (warning)
|
|
137
|
+
const usagePercent = (usage.computeHoursThisMonth / limits.maxComputeHoursPerMonth) * 100;
|
|
138
|
+
if (usagePercent >= this.config.warningThresholdPercent) {
|
|
139
|
+
result.action = 'warning';
|
|
140
|
+
// TODO: Send warning email to user (once per day)
|
|
141
|
+
// await sendLimitWarningEmail(userId, usage.computeHoursThisMonth, limits.maxComputeHoursPerMonth);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return result;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Manually trigger enforcement for a specific user
|
|
148
|
+
*/
|
|
149
|
+
async enforceUser(userId) {
|
|
150
|
+
return this.enforceUserLimits(userId);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Get service status
|
|
154
|
+
*/
|
|
155
|
+
getStatus() {
|
|
156
|
+
return {
|
|
157
|
+
enabled: this.config.enabled,
|
|
158
|
+
isRunning: this.isRunning,
|
|
159
|
+
checkIntervalMs: this.config.checkIntervalMs,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Singleton instance
|
|
164
|
+
let _computeEnforcement = null;
|
|
165
|
+
export function getComputeEnforcementService() {
|
|
166
|
+
if (!_computeEnforcement) {
|
|
167
|
+
_computeEnforcement = new ComputeEnforcementService();
|
|
168
|
+
}
|
|
169
|
+
return _computeEnforcement;
|
|
170
|
+
}
|
|
171
|
+
export function createComputeEnforcementService(config = {}) {
|
|
172
|
+
_computeEnforcement = new ComputeEnforcementService(config);
|
|
173
|
+
return _computeEnforcement;
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=compute-enforcement.js.map
|
|
@@ -9,4 +9,6 @@ export { CapacityManager, CapacityManagerConfig, WorkspaceCapacity, PlacementRec
|
|
|
9
9
|
export { ScalingOrchestrator, OrchestratorConfig, ScalingEvent, getScalingOrchestrator, createScalingOrchestrator, } from './scaling-orchestrator.js';
|
|
10
10
|
export { spawnCIFixAgent, notifyAgentOfCIFailure, completeFixAttempt, getFailureHistory, getPRFailureHistory, } from './ci-agent-spawner.js';
|
|
11
11
|
export { handleMention, handleIssueAssignment, getPendingMentions, getPendingIssueAssignments, processPendingMentions, processPendingIssueAssignments, KNOWN_AGENTS, isKnownAgent, } from './mention-handler.js';
|
|
12
|
+
export { ComputeEnforcementService, ComputeEnforcementConfig, EnforcementResult, getComputeEnforcementService, createComputeEnforcementService, } from './compute-enforcement.js';
|
|
13
|
+
export { IntroExpirationService, IntroExpirationConfig, IntroStatus, ExpirationResult as IntroExpirationResult, INTRO_PERIOD_DAYS, getIntroStatus, getIntroExpirationService, startIntroExpirationService, stopIntroExpirationService, } from './intro-expiration.js';
|
|
12
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -12,4 +12,8 @@ export { ScalingOrchestrator, getScalingOrchestrator, createScalingOrchestrator,
|
|
|
12
12
|
export { spawnCIFixAgent, notifyAgentOfCIFailure, completeFixAttempt, getFailureHistory, getPRFailureHistory, } from './ci-agent-spawner.js';
|
|
13
13
|
// Issue and mention handling
|
|
14
14
|
export { handleMention, handleIssueAssignment, getPendingMentions, getPendingIssueAssignments, processPendingMentions, processPendingIssueAssignments, KNOWN_AGENTS, isKnownAgent, } from './mention-handler.js';
|
|
15
|
+
// Compute enforcement (free tier limits)
|
|
16
|
+
export { ComputeEnforcementService, getComputeEnforcementService, createComputeEnforcementService, } from './compute-enforcement.js';
|
|
17
|
+
// Intro expiration (auto-resize after free tier intro period)
|
|
18
|
+
export { IntroExpirationService, INTRO_PERIOD_DAYS, getIntroStatus, getIntroExpirationService, startIntroExpirationService, stopIntroExpirationService, } from './intro-expiration.js';
|
|
15
19
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,55 @@
|
|
|
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
|
+
export declare const INTRO_PERIOD_DAYS = 14;
|
|
9
|
+
export interface IntroExpirationConfig {
|
|
10
|
+
enabled: boolean;
|
|
11
|
+
checkIntervalMs: number;
|
|
12
|
+
}
|
|
13
|
+
export interface IntroStatus {
|
|
14
|
+
isIntroPeriod: boolean;
|
|
15
|
+
daysRemaining: number;
|
|
16
|
+
introPeriodDays: number;
|
|
17
|
+
expiresAt: Date | null;
|
|
18
|
+
}
|
|
19
|
+
export interface ExpirationResult {
|
|
20
|
+
userId: string;
|
|
21
|
+
workspaceId: string;
|
|
22
|
+
workspaceName: string;
|
|
23
|
+
action: 'resized' | 'skipped' | 'error';
|
|
24
|
+
reason?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get intro period status for a user
|
|
28
|
+
*/
|
|
29
|
+
export declare function getIntroStatus(userCreatedAt: Date | string | null, plan: string): IntroStatus;
|
|
30
|
+
export declare class IntroExpirationService {
|
|
31
|
+
private config;
|
|
32
|
+
private checkTimer;
|
|
33
|
+
private isRunning;
|
|
34
|
+
constructor(config?: Partial<IntroExpirationConfig>);
|
|
35
|
+
/**
|
|
36
|
+
* Start the expiration service
|
|
37
|
+
*/
|
|
38
|
+
start(): void;
|
|
39
|
+
/**
|
|
40
|
+
* Stop the expiration service
|
|
41
|
+
*/
|
|
42
|
+
stop(): void;
|
|
43
|
+
/**
|
|
44
|
+
* Run expiration check for all free tier users with expired intro periods
|
|
45
|
+
*/
|
|
46
|
+
runExpirationCheck(): Promise<ExpirationResult[]>;
|
|
47
|
+
/**
|
|
48
|
+
* Check and resize workspaces for a user whose intro period has expired
|
|
49
|
+
*/
|
|
50
|
+
private checkAndResizeUserWorkspaces;
|
|
51
|
+
}
|
|
52
|
+
export declare function getIntroExpirationService(): IntroExpirationService;
|
|
53
|
+
export declare function startIntroExpirationService(): void;
|
|
54
|
+
export declare function stopIntroExpirationService(): void;
|
|
55
|
+
//# sourceMappingURL=intro-expiration.d.ts.map
|