agent-relay 1.1.0 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +3 -0
- package/.nvmrc +1 -0
- package/.trajectories/completed/2026-01/traj_1dviorhnkcb5.json +65 -0
- package/.trajectories/completed/2026-01/traj_1dviorhnkcb5.md +37 -0
- package/.trajectories/completed/2026-01/traj_1k5if5snst2e.json +65 -0
- package/.trajectories/completed/2026-01/traj_1k5if5snst2e.md +37 -0
- package/.trajectories/completed/2026-01/traj_1rp3rges5811.json +49 -0
- package/.trajectories/completed/2026-01/traj_1rp3rges5811.md +31 -0
- package/.trajectories/completed/2026-01/traj_22bhyulruouw.json +113 -0
- package/.trajectories/completed/2026-01/traj_22bhyulruouw.md +57 -0
- package/.trajectories/completed/2026-01/traj_2dao7ddgnta0.json +53 -0
- package/.trajectories/completed/2026-01/traj_2dao7ddgnta0.md +32 -0
- package/.trajectories/completed/2026-01/traj_3t0440mjeunc.json +26 -0
- package/.trajectories/completed/2026-01/traj_3t0440mjeunc.md +6 -0
- package/.trajectories/completed/2026-01/traj_45x9494d9xnr.json +47 -0
- package/.trajectories/completed/2026-01/traj_45x9494d9xnr.md +32 -0
- package/.trajectories/completed/2026-01/traj_4aa0bb77s4nh.json +53 -0
- package/.trajectories/completed/2026-01/traj_4aa0bb77s4nh.md +32 -0
- package/.trajectories/completed/2026-01/traj_5lhmzq8rxpqv.json +59 -0
- package/.trajectories/completed/2026-01/traj_5lhmzq8rxpqv.md +33 -0
- package/.trajectories/completed/2026-01/traj_5vr4e9erb1fs.json +53 -0
- package/.trajectories/completed/2026-01/traj_5vr4e9erb1fs.md +32 -0
- package/.trajectories/completed/2026-01/traj_6fgiwdoklvym.json +48 -0
- package/.trajectories/completed/2026-01/traj_6fgiwdoklvym.md +24 -0
- package/.trajectories/completed/2026-01/traj_7ludwvz45veh.json +209 -0
- package/.trajectories/completed/2026-01/traj_7ludwvz45veh.md +97 -0
- package/.trajectories/completed/2026-01/traj_9921cuhel0pj.json +48 -0
- package/.trajectories/completed/2026-01/traj_9921cuhel0pj.md +24 -0
- package/.trajectories/completed/2026-01/traj_ajs7zqfux4wc.json +49 -0
- package/.trajectories/completed/2026-01/traj_ajs7zqfux4wc.md +23 -0
- package/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.json +53 -0
- package/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.md +32 -0
- package/.trajectories/completed/2026-01/traj_cxofprm2m2en.json +49 -0
- package/.trajectories/completed/2026-01/traj_cxofprm2m2en.md +31 -0
- package/.trajectories/completed/2026-01/traj_d2hhz3k0vrhn.json +26 -0
- package/.trajectories/completed/2026-01/traj_d2hhz3k0vrhn.md +6 -0
- package/.trajectories/completed/2026-01/traj_dfuvww9pege5.json +59 -0
- package/.trajectories/completed/2026-01/traj_dfuvww9pege5.md +37 -0
- package/.trajectories/completed/2026-01/traj_g0fisy9h51mf.json +77 -0
- package/.trajectories/completed/2026-01/traj_g0fisy9h51mf.md +42 -0
- package/.trajectories/completed/2026-01/traj_gjdre5voouod.json +53 -0
- package/.trajectories/completed/2026-01/traj_gjdre5voouod.md +32 -0
- package/.trajectories/completed/2026-01/traj_gtlyqtta3x8l.json +25 -0
- package/.trajectories/completed/2026-01/traj_gtlyqtta3x8l.md +15 -0
- package/.trajectories/completed/2026-01/traj_h4xijiuip3w4.json +101 -0
- package/.trajectories/completed/2026-01/traj_h4xijiuip3w4.md +44 -0
- package/.trajectories/completed/2026-01/traj_hhxte7w4gjjx.json +22 -0
- package/.trajectories/completed/2026-01/traj_hhxte7w4gjjx.md +5 -0
- package/.trajectories/completed/2026-01/traj_hpungyhoj6v5.json +53 -0
- package/.trajectories/completed/2026-01/traj_hpungyhoj6v5.md +32 -0
- package/.trajectories/completed/2026-01/traj_m2xkjv0w2sq7.json +25 -0
- package/.trajectories/completed/2026-01/traj_m2xkjv0w2sq7.md +15 -0
- package/.trajectories/completed/2026-01/traj_noq5zbvnrdvz.json +53 -0
- package/.trajectories/completed/2026-01/traj_noq5zbvnrdvz.md +32 -0
- package/.trajectories/completed/2026-01/traj_ntbs6ppopf46.json +53 -0
- package/.trajectories/completed/2026-01/traj_ntbs6ppopf46.md +32 -0
- package/.trajectories/completed/2026-01/traj_ozd98si6a7ns.json +48 -0
- package/.trajectories/completed/2026-01/traj_ozd98si6a7ns.md +24 -0
- package/.trajectories/completed/2026-01/traj_prdza7a5cxp5.json +53 -0
- package/.trajectories/completed/2026-01/traj_prdza7a5cxp5.md +32 -0
- package/.trajectories/completed/2026-01/traj_qb3twvvywfwi.json +77 -0
- package/.trajectories/completed/2026-01/traj_qb3twvvywfwi.md +42 -0
- package/.trajectories/completed/2026-01/traj_qft54mi7nfor.json +53 -0
- package/.trajectories/completed/2026-01/traj_qft54mi7nfor.md +32 -0
- package/.trajectories/completed/2026-01/traj_qx9uhf8whhxo.json +83 -0
- package/.trajectories/completed/2026-01/traj_qx9uhf8whhxo.md +47 -0
- package/.trajectories/completed/2026-01/traj_rd9toccj18a0.json +59 -0
- package/.trajectories/completed/2026-01/traj_rd9toccj18a0.md +37 -0
- package/.trajectories/completed/2026-01/traj_rt4fiw3ecp50.json +48 -0
- package/.trajectories/completed/2026-01/traj_rt4fiw3ecp50.md +16 -0
- package/.trajectories/completed/2026-01/traj_st8j35b0hrlc.json +59 -0
- package/.trajectories/completed/2026-01/traj_st8j35b0hrlc.md +37 -0
- package/.trajectories/completed/2026-01/traj_t1yy8m7hbuxp.json +53 -0
- package/.trajectories/completed/2026-01/traj_t1yy8m7hbuxp.md +32 -0
- package/.trajectories/completed/2026-01/traj_tmux_orchestrator_analysis.json +84 -0
- package/.trajectories/completed/2026-01/traj_tmux_orchestrator_analysis.md +109 -0
- package/.trajectories/completed/2026-01/traj_u9n9eqasw16k.json +53 -0
- package/.trajectories/completed/2026-01/traj_u9n9eqasw16k.md +32 -0
- package/.trajectories/completed/2026-01/traj_v87hypnongqx.json +71 -0
- package/.trajectories/completed/2026-01/traj_v87hypnongqx.md +42 -0
- package/.trajectories/completed/2026-01/traj_wkp2fgzdyinb.json +53 -0
- package/.trajectories/completed/2026-01/traj_wkp2fgzdyinb.md +32 -0
- package/.trajectories/completed/2026-01/traj_x14t8w8rn7xg.json +20 -0
- package/.trajectories/completed/2026-01/traj_x14t8w8rn7xg.md +6 -0
- package/.trajectories/completed/2026-01/traj_xnwbznkvv8ua.json +175 -0
- package/.trajectories/completed/2026-01/traj_xnwbznkvv8ua.md +82 -0
- package/.trajectories/completed/2026-01/traj_ysjc8zaeqtd3.json +47 -0
- package/.trajectories/completed/2026-01/traj_ysjc8zaeqtd3.md +32 -0
- package/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.json +59 -0
- package/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.md +37 -0
- package/.trajectories/completed/2026-01/traj_z0vcw1wrzide.json +53 -0
- package/.trajectories/completed/2026-01/traj_z0vcw1wrzide.md +32 -0
- package/.trajectories/index.json +314 -0
- package/ARCHITECTURE.md +1245 -0
- package/README.md +1 -1
- package/TESTING.md +278 -0
- package/deploy/init-db.sql +5 -0
- package/deploy/scripts/setup-fly-workspaces.sh +69 -0
- package/deploy/scripts/setup-railway.sh +75 -0
- package/deploy/workspace/entrypoint-browser.sh +118 -0
- package/deploy/workspace/entrypoint.sh +348 -0
- package/deploy/workspace/git-credential-relay +111 -0
- package/dist/bridge/spawner.d.ts +53 -0
- package/dist/bridge/spawner.js +203 -19
- package/dist/bridge/types.d.ts +12 -0
- package/dist/cli/index.js +618 -5
- package/dist/cloud/api/auth.d.ts +3 -2
- package/dist/cloud/api/auth.js +10 -98
- package/dist/cloud/api/billing.js +30 -9
- package/dist/cloud/api/cli-pty-runner.d.ts +54 -0
- package/dist/cloud/api/cli-pty-runner.js +119 -0
- package/dist/cloud/api/codex-auth-helper.d.ts +15 -0
- package/dist/cloud/api/codex-auth-helper.js +100 -0
- package/dist/cloud/api/generic-webhooks.d.ts +8 -0
- package/dist/cloud/api/generic-webhooks.js +129 -0
- package/dist/cloud/api/git.d.ts +8 -0
- package/dist/cloud/api/git.js +152 -0
- package/dist/cloud/api/github-app.d.ts +11 -0
- package/dist/cloud/api/github-app.js +189 -0
- package/dist/cloud/api/middleware/planLimits.d.ts +7 -0
- package/dist/cloud/api/middleware/planLimits.js +39 -1
- package/dist/cloud/api/monitoring.d.ts +11 -0
- package/dist/cloud/api/monitoring.js +578 -0
- package/dist/cloud/api/nango-auth.d.ts +9 -0
- package/dist/cloud/api/nango-auth.js +377 -0
- package/dist/cloud/api/onboarding.d.ts +8 -1
- package/dist/cloud/api/onboarding.js +313 -119
- package/dist/cloud/api/policy.d.ts +8 -0
- package/dist/cloud/api/policy.js +229 -0
- package/dist/cloud/api/providers.js +114 -42
- package/dist/cloud/api/repos.d.ts +1 -0
- package/dist/cloud/api/repos.js +186 -0
- package/dist/cloud/api/test-helpers.d.ts +10 -0
- package/dist/cloud/api/test-helpers.js +575 -0
- package/dist/cloud/api/webhooks.d.ts +8 -0
- package/dist/cloud/api/webhooks.js +645 -0
- package/dist/cloud/api/workspaces.js +320 -12
- package/dist/cloud/billing/plans.js +32 -19
- package/dist/cloud/billing/types.d.ts +9 -3
- package/dist/cloud/config.d.ts +9 -2
- package/dist/cloud/config.js +13 -4
- package/dist/cloud/db/drizzle.d.ts +84 -1
- package/dist/cloud/db/drizzle.js +470 -0
- package/dist/cloud/db/index.d.ts +9 -4
- package/dist/cloud/db/index.js +11 -3
- package/dist/cloud/db/schema.d.ts +3283 -556
- package/dist/cloud/db/schema.js +314 -1
- package/dist/cloud/index.d.ts +1 -0
- package/dist/cloud/index.js +2 -0
- package/dist/cloud/provisioner/index.d.ts +56 -0
- package/dist/cloud/provisioner/index.js +676 -34
- package/dist/cloud/server.d.ts +1 -0
- package/dist/cloud/server.js +362 -13
- package/dist/cloud/services/auto-scaler.d.ts +152 -0
- package/dist/cloud/services/auto-scaler.js +439 -0
- package/dist/cloud/services/capacity-manager.d.ts +148 -0
- package/dist/cloud/services/capacity-manager.js +449 -0
- package/dist/cloud/services/ci-agent-spawner.d.ts +49 -0
- package/dist/cloud/services/ci-agent-spawner.js +373 -0
- package/dist/cloud/services/index.d.ts +12 -0
- package/dist/cloud/services/index.js +15 -0
- package/dist/cloud/services/mention-handler.d.ts +65 -0
- package/dist/cloud/services/mention-handler.js +405 -0
- package/dist/cloud/services/nango.d.ts +186 -0
- package/dist/cloud/services/nango.js +344 -0
- package/dist/cloud/services/persistence.d.ts +131 -0
- package/dist/cloud/services/persistence.js +200 -0
- package/dist/cloud/services/planLimits.d.ts +37 -0
- package/dist/cloud/services/planLimits.js +86 -5
- package/dist/cloud/services/scaling-orchestrator.d.ts +159 -0
- package/dist/cloud/services/scaling-orchestrator.js +502 -0
- package/dist/cloud/services/scaling-policy.d.ts +121 -0
- package/dist/cloud/services/scaling-policy.js +415 -0
- package/dist/cloud/vault/index.js +1 -1
- package/dist/cloud/webhooks/index.d.ts +24 -0
- package/dist/cloud/webhooks/index.js +29 -0
- package/dist/cloud/webhooks/parsers/github.d.ts +8 -0
- package/dist/cloud/webhooks/parsers/github.js +234 -0
- package/dist/cloud/webhooks/parsers/index.d.ts +23 -0
- package/dist/cloud/webhooks/parsers/index.js +30 -0
- package/dist/cloud/webhooks/parsers/linear.d.ts +9 -0
- package/dist/cloud/webhooks/parsers/linear.js +258 -0
- package/dist/cloud/webhooks/parsers/slack.d.ts +9 -0
- package/dist/cloud/webhooks/parsers/slack.js +214 -0
- package/dist/cloud/webhooks/responders/github.d.ts +8 -0
- package/dist/cloud/webhooks/responders/github.js +73 -0
- package/dist/cloud/webhooks/responders/index.d.ts +23 -0
- package/dist/cloud/webhooks/responders/index.js +30 -0
- package/dist/cloud/webhooks/responders/linear.d.ts +9 -0
- package/dist/cloud/webhooks/responders/linear.js +149 -0
- package/dist/cloud/webhooks/responders/slack.d.ts +20 -0
- package/dist/cloud/webhooks/responders/slack.js +178 -0
- package/dist/cloud/webhooks/router.d.ts +25 -0
- package/dist/cloud/webhooks/router.js +504 -0
- package/dist/cloud/webhooks/rules-engine.d.ts +24 -0
- package/dist/cloud/webhooks/rules-engine.js +287 -0
- package/dist/cloud/webhooks/types.d.ts +186 -0
- package/dist/cloud/webhooks/types.js +8 -0
- package/dist/continuity/formatter.d.ts +51 -0
- package/dist/continuity/formatter.js +313 -0
- package/dist/continuity/handoff-store.d.ts +67 -0
- package/dist/continuity/handoff-store.js +472 -0
- package/dist/continuity/index.d.ts +45 -0
- package/dist/continuity/index.js +48 -0
- package/dist/continuity/ledger-store.d.ts +110 -0
- package/dist/continuity/ledger-store.js +500 -0
- package/dist/continuity/manager.d.ts +178 -0
- package/dist/continuity/manager.js +562 -0
- package/dist/continuity/parser.d.ts +76 -0
- package/dist/continuity/parser.js +579 -0
- package/dist/continuity/types.d.ts +180 -0
- package/dist/continuity/types.js +9 -0
- package/dist/daemon/agent-manager.d.ts +27 -0
- package/dist/daemon/agent-manager.js +107 -6
- package/dist/daemon/agent-registry.d.ts +32 -0
- package/dist/daemon/agent-registry.js +42 -2
- package/dist/daemon/api.d.ts +12 -0
- package/dist/daemon/api.js +131 -2
- package/dist/daemon/cli-auth.d.ts +67 -0
- package/dist/daemon/cli-auth.js +537 -0
- package/dist/daemon/cloud-sync.js +9 -7
- package/dist/daemon/orchestrator.js +30 -0
- package/dist/daemon/router.d.ts +5 -0
- package/dist/daemon/router.js +78 -26
- package/dist/daemon/server.d.ts +5 -0
- package/dist/daemon/server.js +9 -1
- package/dist/daemon/services/browser-testing.d.ts +88 -0
- package/dist/daemon/services/browser-testing.js +244 -0
- package/dist/daemon/services/container-spawner.d.ts +135 -0
- package/dist/daemon/services/container-spawner.js +313 -0
- package/dist/daemon/types.d.ts +5 -1
- package/dist/dashboard/out/404.html +1 -1
- package/dist/dashboard/out/_next/static/chunks/116-2502180def231162.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/282-980c2eb8fff20123.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/699-3b1cd6618a45d259.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/724-2dae7627550ab88f.js +9 -0
- package/dist/dashboard/out/_next/static/chunks/766-1f2dd8cb7f766b0b.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/onboarding/page-3fdfa60e53f2810d.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/page-e6381e5a6e1fbcfd.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/connect-repos/page-3538dfe0ffe984b8.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/history/{page-b6edd4dde8d08194.js → page-abb9ab2d329f56e9.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/app/layout-c0d118c0f92d969c.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/login/page-c22d080201cbd9fb.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/metrics/page-67a3e98d9a43a6ed.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/page-77e9c65420a06cfb.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/pricing/page-b08ed1c34d14434a.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/providers/page-e88bc117ef7671c3.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/signup/page-68d34f50baa8ab6b.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/e868780c-48e5f147c90a3a41.js +18 -0
- package/dist/dashboard/out/_next/static/chunks/{main-app-5d692157a8eb1fd9.js → main-app-6e8e8d3ef4e0192a.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/{main-c2f423b9c9f4591b.js → main-ed4e1fb6f29c34cf.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/webpack-1cdd8ed57114d5e1.js +1 -0
- package/dist/dashboard/out/_next/static/css/29852f26181969a0.css +1 -0
- package/dist/dashboard/out/_next/static/css/7c3ae9e8617d42a5.css +1 -0
- package/dist/dashboard/out/app/onboarding.html +1 -0
- package/dist/dashboard/out/app/onboarding.txt +7 -0
- package/dist/dashboard/out/app.html +1 -14
- package/dist/dashboard/out/app.txt +2 -2
- package/dist/dashboard/out/connect-repos.html +1 -0
- package/dist/dashboard/out/connect-repos.txt +7 -0
- package/dist/dashboard/out/history.html +1 -1
- package/dist/dashboard/out/history.txt +2 -2
- package/dist/dashboard/out/index.html +1 -1
- package/dist/dashboard/out/index.txt +2 -2
- package/dist/dashboard/out/login.html +6 -0
- package/dist/dashboard/out/login.txt +7 -0
- package/dist/dashboard/out/metrics.html +1 -1
- package/dist/dashboard/out/metrics.txt +2 -2
- package/dist/dashboard/out/pricing.html +3 -3
- package/dist/dashboard/out/pricing.txt +2 -2
- package/dist/dashboard/out/providers.html +1 -0
- package/dist/dashboard/out/providers.txt +7 -0
- package/dist/dashboard/out/signup.html +6 -0
- package/dist/dashboard/out/signup.txt +7 -0
- package/dist/dashboard-server/server.js +1308 -8
- package/dist/hooks/emitter.d.ts +40 -0
- package/dist/hooks/emitter.js +63 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/registry.d.ts +173 -0
- package/dist/hooks/registry.js +476 -0
- package/dist/hooks/trajectory-hooks.d.ts +52 -0
- package/dist/hooks/trajectory-hooks.js +183 -0
- package/dist/hooks/types.d.ts +141 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/memory/adapters/index.d.ts +8 -0
- package/dist/memory/adapters/index.js +8 -0
- package/dist/memory/adapters/inmemory.d.ts +59 -0
- package/dist/memory/adapters/inmemory.js +195 -0
- package/dist/memory/adapters/supermemory.d.ts +71 -0
- package/dist/memory/adapters/supermemory.js +338 -0
- package/dist/memory/factory.d.ts +48 -0
- package/dist/memory/factory.js +143 -0
- package/dist/memory/index.d.ts +32 -0
- package/dist/memory/index.js +32 -0
- package/dist/memory/memory-hooks.d.ts +60 -0
- package/dist/memory/memory-hooks.js +313 -0
- package/dist/memory/service.d.ts +49 -0
- package/dist/memory/service.js +146 -0
- package/dist/memory/types.d.ts +195 -0
- package/dist/memory/types.js +8 -0
- package/dist/policy/agent-policy.d.ts +225 -0
- package/dist/policy/agent-policy.js +665 -0
- package/dist/policy/cloud-policy-fetcher.d.ts +12 -0
- package/dist/policy/cloud-policy-fetcher.js +64 -0
- package/dist/resiliency/crash-insights.d.ts +156 -0
- package/dist/resiliency/crash-insights.js +492 -0
- package/dist/resiliency/gossip-health.d.ts +137 -0
- package/dist/resiliency/gossip-health.js +241 -0
- package/dist/resiliency/index.d.ts +5 -0
- package/dist/resiliency/index.js +5 -0
- package/dist/resiliency/leader-watchdog.d.ts +109 -0
- package/dist/resiliency/leader-watchdog.js +189 -0
- package/dist/resiliency/memory-monitor.d.ts +172 -0
- package/dist/resiliency/memory-monitor.js +593 -0
- package/dist/resiliency/stateless-lead.d.ts +149 -0
- package/dist/resiliency/stateless-lead.js +308 -0
- package/dist/resiliency/supervisor.d.ts +38 -0
- package/dist/resiliency/supervisor.js +122 -0
- package/dist/shared/cli-auth-config.d.ts +91 -0
- package/dist/shared/cli-auth-config.js +264 -0
- package/dist/storage/adapter.d.ts +1 -1
- package/dist/trajectory/config.d.ts +84 -0
- package/dist/trajectory/config.js +163 -0
- package/dist/trajectory/index.d.ts +8 -0
- package/dist/trajectory/index.js +8 -0
- package/dist/trajectory/integration.d.ts +292 -0
- package/dist/trajectory/integration.js +834 -0
- package/dist/utils/logger.js +1 -1
- package/dist/utils/project-namespace.d.ts +24 -0
- package/dist/utils/project-namespace.js +84 -0
- package/dist/wrapper/parser.d.ts +10 -0
- package/dist/wrapper/parser.js +100 -33
- package/dist/wrapper/pty-wrapper.d.ts +197 -16
- package/dist/wrapper/pty-wrapper.js +943 -106
- package/dist/wrapper/shared.d.ts +165 -0
- package/dist/wrapper/shared.js +270 -0
- package/dist/wrapper/tmux-wrapper.d.ts +73 -11
- package/dist/wrapper/tmux-wrapper.js +541 -120
- package/package.json +16 -16
- package/scripts/postinstall.js +60 -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/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/middleware/planLimits.d.ts.map +0 -1
- package/dist/cloud/api/middleware/planLimits.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/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/usage.d.ts.map +0 -1
- package/dist/cloud/api/usage.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/coordinator.d.ts.map +0 -1
- package/dist/cloud/services/coordinator.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/vault/index.d.ts.map +0 -1
- package/dist/cloud/vault/index.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/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/types.d.ts.map +0 -1
- package/dist/daemon/types.js.map +0 -1
- package/dist/daemon/workspace-manager.d.ts.map +0 -1
- package/dist/daemon/workspace-manager.js.map +0 -1
- package/dist/dashboard/out/_next/static/chunks/693-7b3301d8f6bc5014.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/713-f78477eb185f1f4d.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/766-e53e1cfe39b0b5b5.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/900-037c64bfd797fb2a.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/app/page-e3d9e1f4466b9bae.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/layout-2433bb48965f4333.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/metrics/page-e68825a81db67ba1.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/page-cc108bf68c8a657f.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/pricing/page-d80e03a5297f95b6.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/webpack-a5acc2831d094776.js +0 -1
- package/dist/dashboard/out/_next/static/css/79b80143647a07d7.css +0 -1
- package/dist/dashboard/out/_next/static/css/8cf277370ad48cfe.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/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/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/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/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/logger.d.ts.map +0 -1
- package/dist/resiliency/logger.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/supervisor.d.ts.map +0 -1
- package/dist/resiliency/supervisor.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/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/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/CHANGELOG.md +0 -11
- package/docs/CLI-SIMPLIFICATION-COMPLETE.md +0 -48
- package/docs/CLOUD-ARCHITECTURE.md +0 -652
- package/docs/CLOUD-ONBOARDING-DESIGN.md +0 -1983
- package/docs/COMPETITIVE_ANALYSIS.md +0 -897
- package/docs/CONTRIBUTING.md +0 -151
- package/docs/DESIGN_BRIDGE_STAFFING.md +0 -878
- package/docs/DESIGN_V2.md +0 -1079
- package/docs/INTEGRATION-GUIDE.md +0 -926
- package/docs/MONETIZATION.md +0 -1679
- package/docs/PROPOSAL-trajectories.md +0 -1582
- package/docs/PROTOCOL.md +0 -325
- package/docs/SCALING_ANALYSIS.md +0 -280
- package/docs/TESTING_PRESENCE_FEATURES.md +0 -327
- package/docs/TMUX_IMPLEMENTATION_NOTES.md +0 -364
- package/docs/TMUX_IMPROVEMENTS.md +0 -968
- package/docs/agent-relay-snippet.md +0 -168
- package/docs/competitive-analysis-mcp-agent-mail.md +0 -389
- package/docs/dashboard-v2-plan.md +0 -179
- package/docs/guides/CLOUD.md +0 -236
- package/docs/guides/LOCAL.md +0 -535
- package/docs/guides/SELF-HOSTED.md +0 -494
- package/docs/proposals/shadow-as-subagent.md +0 -765
- package/docs/proposals/slack-bot-integration.md +0 -1457
- package/docs/removable-code-analysis.md +0 -24
- 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/tictactoe-setup.sh +0 -181
- /package/dist/dashboard/out/_next/static/chunks/{117-b2cd8d6485aacf2b.js → 117-f7b8ab0809342e77.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{648-8f3f26864ce515e5.js → 648-5cc6e1921389a58a.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/app/_not-found/{page-0b990dbb71d72a98.js → page-53b8a69f76db17d0.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{fd9d1056-bf46c09eb57e019c.js → fd9d1056-609918ca7b6280bb.js} +0 -0
- /package/dist/dashboard/out/_next/static/{6HHWb2ZmnJ4OSm0zUP7h4 → wPgKJtcOmTFLpUncDg16A}/_buildManifest.js +0 -0
- /package/dist/dashboard/out/_next/static/{6HHWb2ZmnJ4OSm0zUP7h4 → wPgKJtcOmTFLpUncDg16A}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-Scaler Service
|
|
3
|
+
*
|
|
4
|
+
* Monitors workspace metrics and automatically scales instances based on
|
|
5
|
+
* defined policies. Uses Redis pub/sub for cross-server coordination to
|
|
6
|
+
* ensure only one scaling operation happens at a time.
|
|
7
|
+
*
|
|
8
|
+
* Key responsibilities:
|
|
9
|
+
* - Subscribe to metrics updates from monitoring service
|
|
10
|
+
* - Evaluate scaling policies periodically
|
|
11
|
+
* - Coordinate scaling decisions across multiple cloud servers
|
|
12
|
+
* - Execute scaling actions via workspace provisioner
|
|
13
|
+
* - Track scaling history and pending operations
|
|
14
|
+
*/
|
|
15
|
+
import { EventEmitter } from 'events';
|
|
16
|
+
import { createClient } from 'redis';
|
|
17
|
+
import { getScalingPolicyService, } from './scaling-policy.js';
|
|
18
|
+
const DEFAULT_CONFIG = {
|
|
19
|
+
enabled: true,
|
|
20
|
+
evaluationIntervalMs: 30000, // 30 seconds
|
|
21
|
+
lockTimeoutMs: 60000, // 1 minute
|
|
22
|
+
maxConcurrentOperations: 5,
|
|
23
|
+
redisKeyPrefix: 'autoscaler:',
|
|
24
|
+
};
|
|
25
|
+
// Redis pub/sub channels
|
|
26
|
+
const CHANNELS = {
|
|
27
|
+
METRICS_UPDATE: 'autoscaler:metrics',
|
|
28
|
+
SCALING_REQUEST: 'autoscaler:scale',
|
|
29
|
+
SCALING_COMPLETE: 'autoscaler:complete',
|
|
30
|
+
LOCK_ACQUIRED: 'autoscaler:lock',
|
|
31
|
+
};
|
|
32
|
+
export class AutoScaler extends EventEmitter {
|
|
33
|
+
config;
|
|
34
|
+
policyService;
|
|
35
|
+
redis = null;
|
|
36
|
+
subscriber = null;
|
|
37
|
+
evaluationTimer = null;
|
|
38
|
+
pendingOperations = new Map();
|
|
39
|
+
metricsCache = new Map();
|
|
40
|
+
isLeader = false;
|
|
41
|
+
serverId;
|
|
42
|
+
lastScalingActions = new Map(); // userId -> lastAction
|
|
43
|
+
constructor(config = {}) {
|
|
44
|
+
super();
|
|
45
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
46
|
+
this.policyService = getScalingPolicyService();
|
|
47
|
+
this.serverId = `server-${process.pid}-${Date.now()}`;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Initialize with Redis connection for cross-server coordination
|
|
51
|
+
*/
|
|
52
|
+
async initialize(redisUrl) {
|
|
53
|
+
if (!this.config.enabled) {
|
|
54
|
+
this.emit('disabled');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
// Main Redis client for commands
|
|
59
|
+
this.redis = createClient({ url: redisUrl });
|
|
60
|
+
this.redis.on('error', (err) => this.emit('error', { context: 'redis', error: err }));
|
|
61
|
+
// Separate client for subscriptions
|
|
62
|
+
this.subscriber = createClient({ url: redisUrl });
|
|
63
|
+
this.subscriber.on('error', (err) => this.emit('error', { context: 'subscriber', error: err }));
|
|
64
|
+
await Promise.all([this.redis.connect(), this.subscriber.connect()]);
|
|
65
|
+
// Set up pub/sub subscriptions
|
|
66
|
+
await this.setupSubscriptions();
|
|
67
|
+
// Start evaluation loop
|
|
68
|
+
this.startEvaluationLoop();
|
|
69
|
+
// Attempt to become leader
|
|
70
|
+
await this.attemptLeadership();
|
|
71
|
+
this.emit('initialized', { serverId: this.serverId, isLeader: this.isLeader });
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
this.emit('error', error);
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Set up Redis pub/sub subscriptions
|
|
80
|
+
*/
|
|
81
|
+
async setupSubscriptions() {
|
|
82
|
+
if (!this.subscriber)
|
|
83
|
+
return;
|
|
84
|
+
// Subscribe to all channels
|
|
85
|
+
await this.subscriber.subscribe(CHANNELS.METRICS_UPDATE, (message) => {
|
|
86
|
+
this.handleChannelMessage(CHANNELS.METRICS_UPDATE, message);
|
|
87
|
+
});
|
|
88
|
+
await this.subscriber.subscribe(CHANNELS.SCALING_REQUEST, (message) => {
|
|
89
|
+
this.handleChannelMessage(CHANNELS.SCALING_REQUEST, message);
|
|
90
|
+
});
|
|
91
|
+
await this.subscriber.subscribe(CHANNELS.SCALING_COMPLETE, (message) => {
|
|
92
|
+
this.handleChannelMessage(CHANNELS.SCALING_COMPLETE, message);
|
|
93
|
+
});
|
|
94
|
+
await this.subscriber.subscribe(CHANNELS.LOCK_ACQUIRED, (message) => {
|
|
95
|
+
this.handleChannelMessage(CHANNELS.LOCK_ACQUIRED, message);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Handle channel message
|
|
100
|
+
*/
|
|
101
|
+
handleChannelMessage(channel, message) {
|
|
102
|
+
try {
|
|
103
|
+
const data = JSON.parse(message);
|
|
104
|
+
this.handlePubSubMessage(channel, data).catch((err) => {
|
|
105
|
+
this.emit('error', { context: 'message_handler', error: err });
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
this.emit('error', { context: 'pubsub_parse', error });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Handle incoming pub/sub messages
|
|
114
|
+
*/
|
|
115
|
+
async handlePubSubMessage(channel, data) {
|
|
116
|
+
switch (channel) {
|
|
117
|
+
case CHANNELS.METRICS_UPDATE:
|
|
118
|
+
await this.handleMetricsUpdate(data);
|
|
119
|
+
break;
|
|
120
|
+
case CHANNELS.SCALING_REQUEST:
|
|
121
|
+
await this.handleScalingRequest(data);
|
|
122
|
+
break;
|
|
123
|
+
case CHANNELS.SCALING_COMPLETE:
|
|
124
|
+
await this.handleScalingComplete(data);
|
|
125
|
+
break;
|
|
126
|
+
case CHANNELS.LOCK_ACQUIRED:
|
|
127
|
+
this.handleLeadershipChange(data);
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Handle metrics update from monitoring service
|
|
133
|
+
*/
|
|
134
|
+
async handleMetricsUpdate(snapshot) {
|
|
135
|
+
this.metricsCache.set(snapshot.userId, snapshot);
|
|
136
|
+
this.emit('metrics_received', snapshot);
|
|
137
|
+
// If we're the leader, evaluate immediately for this user
|
|
138
|
+
if (this.isLeader) {
|
|
139
|
+
await this.evaluateUserScaling(snapshot.userId);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Handle scaling request (from any server)
|
|
144
|
+
*/
|
|
145
|
+
async handleScalingRequest(operation) {
|
|
146
|
+
// Track the operation
|
|
147
|
+
this.pendingOperations.set(operation.id, operation);
|
|
148
|
+
this.emit('scaling_started', operation);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Handle scaling completion
|
|
152
|
+
*/
|
|
153
|
+
async handleScalingComplete(operation) {
|
|
154
|
+
const pending = this.pendingOperations.get(operation.id);
|
|
155
|
+
if (pending) {
|
|
156
|
+
this.pendingOperations.delete(operation.id);
|
|
157
|
+
this.lastScalingActions.set(operation.userId, new Date());
|
|
158
|
+
}
|
|
159
|
+
this.emit('scaling_completed', operation);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Handle leadership change
|
|
163
|
+
*/
|
|
164
|
+
handleLeadershipChange(data) {
|
|
165
|
+
if (data.serverId !== this.serverId) {
|
|
166
|
+
this.isLeader = false;
|
|
167
|
+
this.emit('leadership_lost');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Attempt to become the leader (only leader evaluates scaling)
|
|
172
|
+
*/
|
|
173
|
+
async attemptLeadership() {
|
|
174
|
+
if (!this.redis)
|
|
175
|
+
return false;
|
|
176
|
+
const lockKey = `${this.config.redisKeyPrefix}leader`;
|
|
177
|
+
const result = await this.redis.set(lockKey, this.serverId, {
|
|
178
|
+
PX: this.config.lockTimeoutMs,
|
|
179
|
+
NX: true,
|
|
180
|
+
});
|
|
181
|
+
if (result === 'OK') {
|
|
182
|
+
this.isLeader = true;
|
|
183
|
+
await this.redis.publish(CHANNELS.LOCK_ACQUIRED, JSON.stringify({ serverId: this.serverId }));
|
|
184
|
+
this.emit('became_leader');
|
|
185
|
+
// Renew leadership periodically
|
|
186
|
+
this.scheduleLeadershipRenewal();
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Schedule leadership lock renewal
|
|
193
|
+
*/
|
|
194
|
+
scheduleLeadershipRenewal() {
|
|
195
|
+
const renewInterval = this.config.lockTimeoutMs / 2;
|
|
196
|
+
setInterval(async () => {
|
|
197
|
+
if (this.isLeader && this.redis) {
|
|
198
|
+
const lockKey = `${this.config.redisKeyPrefix}leader`;
|
|
199
|
+
const currentHolder = await this.redis.get(lockKey);
|
|
200
|
+
if (currentHolder === this.serverId) {
|
|
201
|
+
await this.redis.pExpire(lockKey, this.config.lockTimeoutMs);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
this.isLeader = false;
|
|
205
|
+
this.emit('leadership_lost');
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}, renewInterval);
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Start the periodic evaluation loop
|
|
212
|
+
*/
|
|
213
|
+
startEvaluationLoop() {
|
|
214
|
+
if (this.evaluationTimer) {
|
|
215
|
+
clearInterval(this.evaluationTimer);
|
|
216
|
+
}
|
|
217
|
+
this.evaluationTimer = setInterval(async () => {
|
|
218
|
+
if (this.isLeader) {
|
|
219
|
+
await this.evaluateAllUsers();
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
// Try to become leader if current leader is gone
|
|
223
|
+
await this.attemptLeadership();
|
|
224
|
+
}
|
|
225
|
+
}, this.config.evaluationIntervalMs);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Evaluate scaling for all cached users
|
|
229
|
+
*/
|
|
230
|
+
async evaluateAllUsers() {
|
|
231
|
+
const evaluations = [];
|
|
232
|
+
for (const userId of this.metricsCache.keys()) {
|
|
233
|
+
evaluations.push(this.evaluateUserScaling(userId));
|
|
234
|
+
}
|
|
235
|
+
await Promise.allSettled(evaluations);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Evaluate scaling for a specific user
|
|
239
|
+
*/
|
|
240
|
+
async evaluateUserScaling(userId) {
|
|
241
|
+
const snapshot = this.metricsCache.get(userId);
|
|
242
|
+
if (!snapshot)
|
|
243
|
+
return;
|
|
244
|
+
// Check if we have too many pending operations
|
|
245
|
+
const userPendingOps = Array.from(this.pendingOperations.values()).filter((op) => op.userId === userId && op.status === 'in_progress').length;
|
|
246
|
+
if (userPendingOps >= this.config.maxConcurrentOperations) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
// Build context for policy evaluation
|
|
250
|
+
const context = await this.buildUserContext(userId, snapshot);
|
|
251
|
+
if (!context)
|
|
252
|
+
return;
|
|
253
|
+
// Evaluate policies
|
|
254
|
+
const decision = this.policyService.evaluate(context);
|
|
255
|
+
if (decision.shouldScale && decision.action) {
|
|
256
|
+
await this.requestScaling(userId, decision);
|
|
257
|
+
}
|
|
258
|
+
this.emit('evaluation_complete', { userId, decision });
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Build user context for policy evaluation
|
|
262
|
+
*/
|
|
263
|
+
async buildUserContext(userId, snapshot) {
|
|
264
|
+
if (!this.redis)
|
|
265
|
+
return null;
|
|
266
|
+
// Get user plan from Redis cache or database
|
|
267
|
+
const userPlanKey = `${this.config.redisKeyPrefix}user:${userId}:plan`;
|
|
268
|
+
let plan = (await this.redis.get(userPlanKey));
|
|
269
|
+
if (!plan) {
|
|
270
|
+
plan = 'free'; // Default, should be fetched from database
|
|
271
|
+
}
|
|
272
|
+
const maxWorkspaces = this.policyService.getMaxWorkspaces(plan);
|
|
273
|
+
const lastScalingAction = this.lastScalingActions.get(userId);
|
|
274
|
+
return {
|
|
275
|
+
userId,
|
|
276
|
+
plan,
|
|
277
|
+
currentWorkspaceCount: snapshot.workspaces.length,
|
|
278
|
+
maxWorkspaces,
|
|
279
|
+
workspaceMetrics: snapshot.workspaces,
|
|
280
|
+
lastScalingAction,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Request a scaling operation
|
|
285
|
+
*/
|
|
286
|
+
async requestScaling(userId, decision) {
|
|
287
|
+
if (!this.redis || !decision.action)
|
|
288
|
+
return;
|
|
289
|
+
const operation = {
|
|
290
|
+
id: `scale-${userId}-${Date.now()}`,
|
|
291
|
+
userId,
|
|
292
|
+
action: decision.action.type,
|
|
293
|
+
targetWorkspaceId: decision.action.targetWorkspaceId,
|
|
294
|
+
targetResourceTier: decision.action.resourceTier,
|
|
295
|
+
targetAgentLimit: decision.action.newAgentLimit,
|
|
296
|
+
status: 'pending',
|
|
297
|
+
startedAt: new Date(),
|
|
298
|
+
triggeredBy: decision.triggeredPolicy || 'manual',
|
|
299
|
+
metrics: decision.metrics,
|
|
300
|
+
};
|
|
301
|
+
// Acquire distributed lock for this user's scaling
|
|
302
|
+
const lockKey = `${this.config.redisKeyPrefix}scaling:${userId}`;
|
|
303
|
+
const lockAcquired = await this.redis.set(lockKey, operation.id, {
|
|
304
|
+
PX: 60000,
|
|
305
|
+
NX: true,
|
|
306
|
+
});
|
|
307
|
+
if (lockAcquired !== 'OK') {
|
|
308
|
+
// Another scaling operation is in progress
|
|
309
|
+
this.emit('scaling_skipped', { reason: 'lock_held', userId });
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
try {
|
|
313
|
+
// Publish scaling request
|
|
314
|
+
await this.redis.publish(CHANNELS.SCALING_REQUEST, JSON.stringify(operation));
|
|
315
|
+
// Execute the scaling operation
|
|
316
|
+
operation.status = 'in_progress';
|
|
317
|
+
await this.executeScaling(operation, decision);
|
|
318
|
+
}
|
|
319
|
+
catch (error) {
|
|
320
|
+
operation.status = 'failed';
|
|
321
|
+
operation.error = error instanceof Error ? error.message : 'Unknown error';
|
|
322
|
+
this.emit('scaling_error', { operation, error });
|
|
323
|
+
}
|
|
324
|
+
finally {
|
|
325
|
+
// Release lock
|
|
326
|
+
await this.redis.del(lockKey);
|
|
327
|
+
// Publish completion
|
|
328
|
+
operation.completedAt = new Date();
|
|
329
|
+
await this.redis.publish(CHANNELS.SCALING_COMPLETE, JSON.stringify(operation));
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Execute the actual scaling operation
|
|
334
|
+
*/
|
|
335
|
+
async executeScaling(operation, decision) {
|
|
336
|
+
// This will be integrated with the workspace provisioner
|
|
337
|
+
// For now, emit event for external handling
|
|
338
|
+
this.emit('execute_scaling', { operation, decision });
|
|
339
|
+
// The actual implementation would:
|
|
340
|
+
// 1. Call workspaceProvisioner.provisionWorkspace() for scale_up
|
|
341
|
+
// 2. Call workspaceProvisioner.terminateWorkspace() for scale_down
|
|
342
|
+
// 3. Call coordinator.rebalanceAgents() for rebalance
|
|
343
|
+
operation.status = 'completed';
|
|
344
|
+
this.emit('scaling_executed', operation);
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Report metrics from monitoring service
|
|
348
|
+
*/
|
|
349
|
+
async reportMetrics(userId, workspaces) {
|
|
350
|
+
if (!this.redis)
|
|
351
|
+
return;
|
|
352
|
+
const snapshot = {
|
|
353
|
+
userId,
|
|
354
|
+
workspaces,
|
|
355
|
+
timestamp: new Date(),
|
|
356
|
+
};
|
|
357
|
+
// Cache locally
|
|
358
|
+
this.metricsCache.set(userId, snapshot);
|
|
359
|
+
// Publish to all servers
|
|
360
|
+
await this.redis.publish(CHANNELS.METRICS_UPDATE, JSON.stringify(snapshot));
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Manually trigger scaling evaluation for a user
|
|
364
|
+
*/
|
|
365
|
+
async triggerEvaluation(userId) {
|
|
366
|
+
const snapshot = this.metricsCache.get(userId);
|
|
367
|
+
if (!snapshot)
|
|
368
|
+
return null;
|
|
369
|
+
const context = await this.buildUserContext(userId, snapshot);
|
|
370
|
+
if (!context)
|
|
371
|
+
return null;
|
|
372
|
+
return this.policyService.evaluate(context);
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Get current scaling status
|
|
376
|
+
*/
|
|
377
|
+
getStatus() {
|
|
378
|
+
return {
|
|
379
|
+
enabled: this.config.enabled,
|
|
380
|
+
isLeader: this.isLeader,
|
|
381
|
+
serverId: this.serverId,
|
|
382
|
+
pendingOperations: this.pendingOperations.size,
|
|
383
|
+
cachedUsers: this.metricsCache.size,
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Get pending operations for a user
|
|
388
|
+
*/
|
|
389
|
+
getPendingOperations(userId) {
|
|
390
|
+
const ops = Array.from(this.pendingOperations.values());
|
|
391
|
+
return userId ? ops.filter((op) => op.userId === userId) : ops;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Update user plan in cache
|
|
395
|
+
*/
|
|
396
|
+
async setUserPlan(userId, plan) {
|
|
397
|
+
if (!this.redis)
|
|
398
|
+
return;
|
|
399
|
+
const key = `${this.config.redisKeyPrefix}user:${userId}:plan`;
|
|
400
|
+
await this.redis.set(key, plan, { EX: 3600 }); // 1 hour TTL
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Clean shutdown
|
|
404
|
+
*/
|
|
405
|
+
async shutdown() {
|
|
406
|
+
if (this.evaluationTimer) {
|
|
407
|
+
clearInterval(this.evaluationTimer);
|
|
408
|
+
this.evaluationTimer = null;
|
|
409
|
+
}
|
|
410
|
+
if (this.subscriber) {
|
|
411
|
+
await this.subscriber.unsubscribe();
|
|
412
|
+
await this.subscriber.quit();
|
|
413
|
+
this.subscriber = null;
|
|
414
|
+
}
|
|
415
|
+
if (this.redis) {
|
|
416
|
+
// Release leadership if we have it
|
|
417
|
+
if (this.isLeader) {
|
|
418
|
+
const lockKey = `${this.config.redisKeyPrefix}leader`;
|
|
419
|
+
await this.redis.del(lockKey);
|
|
420
|
+
}
|
|
421
|
+
await this.redis.quit();
|
|
422
|
+
this.redis = null;
|
|
423
|
+
}
|
|
424
|
+
this.emit('shutdown');
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
// Singleton instance
|
|
428
|
+
let _autoScaler = null;
|
|
429
|
+
export function getAutoScaler() {
|
|
430
|
+
if (!_autoScaler) {
|
|
431
|
+
_autoScaler = new AutoScaler();
|
|
432
|
+
}
|
|
433
|
+
return _autoScaler;
|
|
434
|
+
}
|
|
435
|
+
export function createAutoScaler(config = {}) {
|
|
436
|
+
_autoScaler = new AutoScaler(config);
|
|
437
|
+
return _autoScaler;
|
|
438
|
+
}
|
|
439
|
+
//# sourceMappingURL=auto-scaler.js.map
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capacity Manager
|
|
3
|
+
*
|
|
4
|
+
* Tracks workspace capacity across the fleet and provides:
|
|
5
|
+
* - Real-time capacity metrics
|
|
6
|
+
* - Optimal agent placement recommendations
|
|
7
|
+
* - Load balancing decisions
|
|
8
|
+
* - Capacity forecasting based on trends
|
|
9
|
+
*
|
|
10
|
+
* Works with AutoScaler to determine when to provision new instances
|
|
11
|
+
* and with Coordinator to place agents optimally.
|
|
12
|
+
*/
|
|
13
|
+
import { EventEmitter } from 'events';
|
|
14
|
+
import { WorkspaceMetrics } from './scaling-policy.js';
|
|
15
|
+
export interface WorkspaceCapacity {
|
|
16
|
+
workspaceId: string;
|
|
17
|
+
userId: string;
|
|
18
|
+
provider: string;
|
|
19
|
+
region: string;
|
|
20
|
+
currentAgents: number;
|
|
21
|
+
maxAgents: number;
|
|
22
|
+
memoryUsedBytes: number;
|
|
23
|
+
memoryLimitBytes: number;
|
|
24
|
+
cpuPercent: number;
|
|
25
|
+
agentCapacityPercent: number;
|
|
26
|
+
memoryCapacityPercent: number;
|
|
27
|
+
overallHealthScore: number;
|
|
28
|
+
lastHeartbeat: Date;
|
|
29
|
+
lastMetricsUpdate: Date;
|
|
30
|
+
}
|
|
31
|
+
export interface PlacementRecommendation {
|
|
32
|
+
workspaceId: string;
|
|
33
|
+
score: number;
|
|
34
|
+
reason: string;
|
|
35
|
+
estimatedCapacityAfter: number;
|
|
36
|
+
}
|
|
37
|
+
export interface CapacitySnapshot {
|
|
38
|
+
userId: string;
|
|
39
|
+
totalWorkspaces: number;
|
|
40
|
+
totalAgents: number;
|
|
41
|
+
totalMaxAgents: number;
|
|
42
|
+
totalMemoryBytes: number;
|
|
43
|
+
totalMemoryLimitBytes: number;
|
|
44
|
+
averageHealthScore: number;
|
|
45
|
+
workspaces: WorkspaceCapacity[];
|
|
46
|
+
timestamp: Date;
|
|
47
|
+
}
|
|
48
|
+
export interface CapacityForecast {
|
|
49
|
+
userId: string;
|
|
50
|
+
currentAgents: number;
|
|
51
|
+
projectedAgents15Min: number;
|
|
52
|
+
projectedAgents60Min: number;
|
|
53
|
+
memoryTrendPerMinute: number;
|
|
54
|
+
willExceedCapacity: boolean;
|
|
55
|
+
timeToCapacityExhaustion?: number;
|
|
56
|
+
recommendation: 'none' | 'scale_soon' | 'scale_now' | 'critical';
|
|
57
|
+
}
|
|
58
|
+
export interface CapacityManagerConfig {
|
|
59
|
+
healthCheckIntervalMs: number;
|
|
60
|
+
staleThresholdMs: number;
|
|
61
|
+
memoryWeightFactor: number;
|
|
62
|
+
agentWeightFactor: number;
|
|
63
|
+
cpuWeightFactor: number;
|
|
64
|
+
redisKeyPrefix: string;
|
|
65
|
+
}
|
|
66
|
+
export declare class CapacityManager extends EventEmitter {
|
|
67
|
+
private config;
|
|
68
|
+
private redis;
|
|
69
|
+
private subscriber;
|
|
70
|
+
private capacityMap;
|
|
71
|
+
private userWorkspaces;
|
|
72
|
+
private trendHistory;
|
|
73
|
+
private healthCheckTimer;
|
|
74
|
+
constructor(config?: Partial<CapacityManagerConfig>);
|
|
75
|
+
/**
|
|
76
|
+
* Initialize with Redis for cross-server sync
|
|
77
|
+
*/
|
|
78
|
+
initialize(redisUrl: string): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Load capacity data from Redis
|
|
81
|
+
*/
|
|
82
|
+
private loadFromRedis;
|
|
83
|
+
/**
|
|
84
|
+
* Update local capacity map
|
|
85
|
+
*/
|
|
86
|
+
private updateLocalCapacity;
|
|
87
|
+
/**
|
|
88
|
+
* Update trend history for forecasting
|
|
89
|
+
*/
|
|
90
|
+
private updateTrendHistory;
|
|
91
|
+
/**
|
|
92
|
+
* Report capacity from a workspace
|
|
93
|
+
*/
|
|
94
|
+
reportCapacity(workspaceId: string, userId: string, metrics: Partial<WorkspaceCapacity>): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Calculate health score for a workspace (lower is healthier/better for placement)
|
|
97
|
+
*/
|
|
98
|
+
private calculateHealthScore;
|
|
99
|
+
/**
|
|
100
|
+
* Get best workspace for placing a new agent
|
|
101
|
+
*/
|
|
102
|
+
recommendPlacement(userId: string, agentCount?: number): PlacementRecommendation[];
|
|
103
|
+
/**
|
|
104
|
+
* Generate human-readable placement reason
|
|
105
|
+
*/
|
|
106
|
+
private getPlacementReason;
|
|
107
|
+
/**
|
|
108
|
+
* Get capacity snapshot for a user
|
|
109
|
+
*/
|
|
110
|
+
getCapacitySnapshot(userId: string): CapacitySnapshot | null;
|
|
111
|
+
/**
|
|
112
|
+
* Forecast capacity needs based on trends
|
|
113
|
+
*/
|
|
114
|
+
getCapacityForecast(userId: string): CapacityForecast | null;
|
|
115
|
+
/**
|
|
116
|
+
* Convert workspace metrics to capacity format
|
|
117
|
+
*/
|
|
118
|
+
fromWorkspaceMetrics(userId: string, metrics: WorkspaceMetrics): Partial<WorkspaceCapacity>;
|
|
119
|
+
/**
|
|
120
|
+
* Health check loop - detect stale workspaces
|
|
121
|
+
*/
|
|
122
|
+
private startHealthCheckLoop;
|
|
123
|
+
/**
|
|
124
|
+
* Remove a workspace from tracking
|
|
125
|
+
*/
|
|
126
|
+
removeWorkspace(workspaceId: string): Promise<void>;
|
|
127
|
+
/**
|
|
128
|
+
* Get all workspaces for a user
|
|
129
|
+
*/
|
|
130
|
+
getUserWorkspaces(userId: string): WorkspaceCapacity[];
|
|
131
|
+
/**
|
|
132
|
+
* Get global capacity metrics
|
|
133
|
+
*/
|
|
134
|
+
getGlobalMetrics(): {
|
|
135
|
+
totalWorkspaces: number;
|
|
136
|
+
totalAgents: number;
|
|
137
|
+
totalMaxAgents: number;
|
|
138
|
+
averageUtilization: number;
|
|
139
|
+
staleWorkspaces: number;
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Clean shutdown
|
|
143
|
+
*/
|
|
144
|
+
shutdown(): Promise<void>;
|
|
145
|
+
}
|
|
146
|
+
export declare function getCapacityManager(): CapacityManager;
|
|
147
|
+
export declare function createCapacityManager(config?: Partial<CapacityManagerConfig>): CapacityManager;
|
|
148
|
+
//# sourceMappingURL=capacity-manager.d.ts.map
|