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,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stateless Lead Coordinator
|
|
3
|
+
*
|
|
4
|
+
* Implements P0: Lead reads from Beads, no in-memory task queue.
|
|
5
|
+
* All task state lives in Beads. If lead crashes, new lead picks up.
|
|
6
|
+
*
|
|
7
|
+
* Key principles:
|
|
8
|
+
* - Lead is a coordinator, not a state holder
|
|
9
|
+
* - Beads is the single source of truth for task state
|
|
10
|
+
* - Any agent can become lead by reading from Beads
|
|
11
|
+
* - Tasks are assigned by updating Beads, not in-memory
|
|
12
|
+
*/
|
|
13
|
+
import { EventEmitter } from 'events';
|
|
14
|
+
/**
|
|
15
|
+
* Task from Beads
|
|
16
|
+
*/
|
|
17
|
+
export interface BeadsTask {
|
|
18
|
+
id: string;
|
|
19
|
+
title: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
status: 'open' | 'in_progress' | 'blocked' | 'closed';
|
|
22
|
+
priority: number;
|
|
23
|
+
assignee?: string;
|
|
24
|
+
leaseExpires?: number;
|
|
25
|
+
tags?: string[];
|
|
26
|
+
created_at: string;
|
|
27
|
+
updated_at: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Lead heartbeat (P2)
|
|
31
|
+
*/
|
|
32
|
+
export interface LeadHeartbeat {
|
|
33
|
+
leadName: string;
|
|
34
|
+
leadId: string;
|
|
35
|
+
timestamp: number;
|
|
36
|
+
activeTaskCount: number;
|
|
37
|
+
assignedAgents: string[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Configuration for stateless lead
|
|
41
|
+
*/
|
|
42
|
+
export interface StatelessLeadConfig {
|
|
43
|
+
/** Path to .beads directory */
|
|
44
|
+
beadsDir: string;
|
|
45
|
+
/** Agent name for this lead */
|
|
46
|
+
agentName: string;
|
|
47
|
+
/** Unique agent ID */
|
|
48
|
+
agentId: string;
|
|
49
|
+
/** How often to poll Beads for ready tasks (ms) */
|
|
50
|
+
pollIntervalMs: number;
|
|
51
|
+
/** Heartbeat interval (ms) */
|
|
52
|
+
heartbeatIntervalMs: number;
|
|
53
|
+
/** Lease duration for assigned tasks (ms) - P1 */
|
|
54
|
+
leaseDurationMs: number;
|
|
55
|
+
/** Callback to send relay messages */
|
|
56
|
+
sendRelay: (to: string, message: string) => Promise<void>;
|
|
57
|
+
/** Callback to get available workers */
|
|
58
|
+
getAvailableWorkers: () => Promise<string[]>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Stateless Lead Coordinator
|
|
62
|
+
*
|
|
63
|
+
* Reads tasks from Beads JSONL, assigns to workers, tracks via Beads updates.
|
|
64
|
+
* No in-memory task queue - all state persisted to Beads.
|
|
65
|
+
*/
|
|
66
|
+
export declare class StatelessLeadCoordinator extends EventEmitter {
|
|
67
|
+
private config;
|
|
68
|
+
private issuesPath;
|
|
69
|
+
private heartbeatPath;
|
|
70
|
+
private pollInterval?;
|
|
71
|
+
private heartbeatInterval?;
|
|
72
|
+
private isRunning;
|
|
73
|
+
constructor(config: StatelessLeadConfig);
|
|
74
|
+
/**
|
|
75
|
+
* Start the lead coordinator loop
|
|
76
|
+
*/
|
|
77
|
+
start(): Promise<void>;
|
|
78
|
+
/**
|
|
79
|
+
* Stop the lead coordinator
|
|
80
|
+
*/
|
|
81
|
+
stop(): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* Read all tasks from Beads JSONL
|
|
84
|
+
*/
|
|
85
|
+
private readTasks;
|
|
86
|
+
/**
|
|
87
|
+
* Update a task in Beads JSONL
|
|
88
|
+
*/
|
|
89
|
+
private updateTask;
|
|
90
|
+
/**
|
|
91
|
+
* Get tasks that are ready to be assigned
|
|
92
|
+
* Ready = open status, not assigned, not blocked, sorted by priority
|
|
93
|
+
*/
|
|
94
|
+
private getReadyTasks;
|
|
95
|
+
/**
|
|
96
|
+
* Get tasks currently assigned to agents
|
|
97
|
+
*/
|
|
98
|
+
private getAssignedTasks;
|
|
99
|
+
/**
|
|
100
|
+
* Poll for ready tasks and assign to available workers
|
|
101
|
+
*/
|
|
102
|
+
private pollAndAssign;
|
|
103
|
+
/**
|
|
104
|
+
* Assign a task to a worker
|
|
105
|
+
*/
|
|
106
|
+
private assignTask;
|
|
107
|
+
/**
|
|
108
|
+
* Handle task completion from worker
|
|
109
|
+
*/
|
|
110
|
+
completeTask(taskId: string, worker: string, reason?: string): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Handle task blocked by worker
|
|
113
|
+
*/
|
|
114
|
+
blockTask(taskId: string, worker: string, reason: string): Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* Renew lease for a task (worker signals still working)
|
|
117
|
+
*/
|
|
118
|
+
renewLease(taskId: string, worker: string): Promise<void>;
|
|
119
|
+
/**
|
|
120
|
+
* Write leader heartbeat to file (P2)
|
|
121
|
+
*/
|
|
122
|
+
private writeHeartbeat;
|
|
123
|
+
/**
|
|
124
|
+
* Read current leader heartbeat (for watchdog - P3)
|
|
125
|
+
*/
|
|
126
|
+
static readHeartbeat(beadsDir: string): Promise<LeadHeartbeat | null>;
|
|
127
|
+
/**
|
|
128
|
+
* Check if leader is stale (for watchdog - P3)
|
|
129
|
+
*/
|
|
130
|
+
static isLeaderStale(beadsDir: string, staleThresholdMs?: number): Promise<boolean>;
|
|
131
|
+
/**
|
|
132
|
+
* Get current status
|
|
133
|
+
*/
|
|
134
|
+
getStatus(): Promise<{
|
|
135
|
+
isRunning: boolean;
|
|
136
|
+
leadName: string;
|
|
137
|
+
readyTasks: number;
|
|
138
|
+
assignedTasks: number;
|
|
139
|
+
lastHeartbeat: number | null;
|
|
140
|
+
}>;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Create a stateless lead coordinator with defaults
|
|
144
|
+
*/
|
|
145
|
+
export declare function createStatelessLead(beadsDir: string, agentName: string, agentId: string, callbacks: {
|
|
146
|
+
sendRelay: (to: string, message: string) => Promise<void>;
|
|
147
|
+
getAvailableWorkers: () => Promise<string[]>;
|
|
148
|
+
}): StatelessLeadCoordinator;
|
|
149
|
+
//# sourceMappingURL=stateless-lead.d.ts.map
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stateless Lead Coordinator
|
|
3
|
+
*
|
|
4
|
+
* Implements P0: Lead reads from Beads, no in-memory task queue.
|
|
5
|
+
* All task state lives in Beads. If lead crashes, new lead picks up.
|
|
6
|
+
*
|
|
7
|
+
* Key principles:
|
|
8
|
+
* - Lead is a coordinator, not a state holder
|
|
9
|
+
* - Beads is the single source of truth for task state
|
|
10
|
+
* - Any agent can become lead by reading from Beads
|
|
11
|
+
* - Tasks are assigned by updating Beads, not in-memory
|
|
12
|
+
*/
|
|
13
|
+
import * as fs from 'fs';
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
import { EventEmitter } from 'events';
|
|
16
|
+
const DEFAULT_CONFIG = {
|
|
17
|
+
pollIntervalMs: 5000,
|
|
18
|
+
heartbeatIntervalMs: 10000,
|
|
19
|
+
leaseDurationMs: 300000, // 5 minutes
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Stateless Lead Coordinator
|
|
23
|
+
*
|
|
24
|
+
* Reads tasks from Beads JSONL, assigns to workers, tracks via Beads updates.
|
|
25
|
+
* No in-memory task queue - all state persisted to Beads.
|
|
26
|
+
*/
|
|
27
|
+
export class StatelessLeadCoordinator extends EventEmitter {
|
|
28
|
+
config;
|
|
29
|
+
issuesPath;
|
|
30
|
+
heartbeatPath;
|
|
31
|
+
pollInterval;
|
|
32
|
+
heartbeatInterval;
|
|
33
|
+
isRunning = false;
|
|
34
|
+
constructor(config) {
|
|
35
|
+
super();
|
|
36
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
37
|
+
this.issuesPath = path.join(this.config.beadsDir, 'issues.jsonl');
|
|
38
|
+
this.heartbeatPath = path.join(this.config.beadsDir, 'leader-heartbeat.json');
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Start the lead coordinator loop
|
|
42
|
+
*/
|
|
43
|
+
async start() {
|
|
44
|
+
if (this.isRunning)
|
|
45
|
+
return;
|
|
46
|
+
this.isRunning = true;
|
|
47
|
+
console.log(`[stateless-lead] Starting lead coordinator: ${this.config.agentName}`);
|
|
48
|
+
// Write initial heartbeat
|
|
49
|
+
await this.writeHeartbeat();
|
|
50
|
+
// Start polling for ready tasks
|
|
51
|
+
this.pollInterval = setInterval(async () => {
|
|
52
|
+
try {
|
|
53
|
+
await this.pollAndAssign();
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
console.error('[stateless-lead] Poll error:', err);
|
|
57
|
+
this.emit('error', err);
|
|
58
|
+
}
|
|
59
|
+
}, this.config.pollIntervalMs);
|
|
60
|
+
// Start heartbeat
|
|
61
|
+
this.heartbeatInterval = setInterval(async () => {
|
|
62
|
+
try {
|
|
63
|
+
await this.writeHeartbeat();
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
console.error('[stateless-lead] Heartbeat error:', err);
|
|
67
|
+
}
|
|
68
|
+
}, this.config.heartbeatIntervalMs);
|
|
69
|
+
// Initial poll
|
|
70
|
+
await this.pollAndAssign();
|
|
71
|
+
this.emit('started', { leadName: this.config.agentName });
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Stop the lead coordinator
|
|
75
|
+
*/
|
|
76
|
+
async stop() {
|
|
77
|
+
if (!this.isRunning)
|
|
78
|
+
return;
|
|
79
|
+
this.isRunning = false;
|
|
80
|
+
if (this.pollInterval) {
|
|
81
|
+
clearInterval(this.pollInterval);
|
|
82
|
+
this.pollInterval = undefined;
|
|
83
|
+
}
|
|
84
|
+
if (this.heartbeatInterval) {
|
|
85
|
+
clearInterval(this.heartbeatInterval);
|
|
86
|
+
this.heartbeatInterval = undefined;
|
|
87
|
+
}
|
|
88
|
+
console.log(`[stateless-lead] Stopped lead coordinator: ${this.config.agentName}`);
|
|
89
|
+
this.emit('stopped', { leadName: this.config.agentName });
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Read all tasks from Beads JSONL
|
|
93
|
+
*/
|
|
94
|
+
async readTasks() {
|
|
95
|
+
if (!fs.existsSync(this.issuesPath)) {
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
const content = await fs.promises.readFile(this.issuesPath, 'utf-8');
|
|
99
|
+
const tasks = [];
|
|
100
|
+
for (const line of content.split('\n')) {
|
|
101
|
+
if (!line.trim())
|
|
102
|
+
continue;
|
|
103
|
+
try {
|
|
104
|
+
tasks.push(JSON.parse(line));
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// Skip malformed lines
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return tasks;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Update a task in Beads JSONL
|
|
114
|
+
*/
|
|
115
|
+
async updateTask(taskId, updates) {
|
|
116
|
+
const tasks = await this.readTasks();
|
|
117
|
+
const updated = tasks.map((task) => {
|
|
118
|
+
if (task.id === taskId) {
|
|
119
|
+
return {
|
|
120
|
+
...task,
|
|
121
|
+
...updates,
|
|
122
|
+
updated_at: new Date().toISOString(),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return task;
|
|
126
|
+
});
|
|
127
|
+
const content = updated.map((t) => JSON.stringify(t)).join('\n') + '\n';
|
|
128
|
+
await fs.promises.writeFile(this.issuesPath, content, 'utf-8');
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get tasks that are ready to be assigned
|
|
132
|
+
* Ready = open status, not assigned, not blocked, sorted by priority
|
|
133
|
+
*/
|
|
134
|
+
async getReadyTasks() {
|
|
135
|
+
const tasks = await this.readTasks();
|
|
136
|
+
const now = Date.now();
|
|
137
|
+
return tasks
|
|
138
|
+
.filter((task) => {
|
|
139
|
+
// Must be open
|
|
140
|
+
if (task.status !== 'open')
|
|
141
|
+
return false;
|
|
142
|
+
// Not assigned, or lease expired (P1)
|
|
143
|
+
if (task.assignee) {
|
|
144
|
+
if (task.leaseExpires && task.leaseExpires > now) {
|
|
145
|
+
return false; // Still leased
|
|
146
|
+
}
|
|
147
|
+
// Lease expired - task is available again
|
|
148
|
+
}
|
|
149
|
+
return true;
|
|
150
|
+
})
|
|
151
|
+
.sort((a, b) => a.priority - b.priority); // Lower priority number = higher priority
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Get tasks currently assigned to agents
|
|
155
|
+
*/
|
|
156
|
+
async getAssignedTasks() {
|
|
157
|
+
const tasks = await this.readTasks();
|
|
158
|
+
const now = Date.now();
|
|
159
|
+
return tasks.filter((task) => {
|
|
160
|
+
if (task.status !== 'in_progress')
|
|
161
|
+
return false;
|
|
162
|
+
if (!task.assignee)
|
|
163
|
+
return false;
|
|
164
|
+
// Check lease not expired
|
|
165
|
+
if (task.leaseExpires && task.leaseExpires <= now)
|
|
166
|
+
return false;
|
|
167
|
+
return true;
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Poll for ready tasks and assign to available workers
|
|
172
|
+
*/
|
|
173
|
+
async pollAndAssign() {
|
|
174
|
+
const readyTasks = await this.getReadyTasks();
|
|
175
|
+
if (readyTasks.length === 0)
|
|
176
|
+
return;
|
|
177
|
+
const workers = await this.config.getAvailableWorkers();
|
|
178
|
+
if (workers.length === 0) {
|
|
179
|
+
console.log('[stateless-lead] No available workers');
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
// Assign one task per available worker
|
|
183
|
+
for (const worker of workers) {
|
|
184
|
+
const task = readyTasks.shift();
|
|
185
|
+
if (!task)
|
|
186
|
+
break;
|
|
187
|
+
await this.assignTask(task, worker);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Assign a task to a worker
|
|
192
|
+
*/
|
|
193
|
+
async assignTask(task, worker) {
|
|
194
|
+
const leaseExpires = Date.now() + this.config.leaseDurationMs;
|
|
195
|
+
// Update Beads first (source of truth)
|
|
196
|
+
await this.updateTask(task.id, {
|
|
197
|
+
status: 'in_progress',
|
|
198
|
+
assignee: worker,
|
|
199
|
+
leaseExpires,
|
|
200
|
+
});
|
|
201
|
+
// Send task to worker via relay
|
|
202
|
+
const message = `TASK [${task.id}]: ${task.title}${task.description ? '\n\n' + task.description : ''}`;
|
|
203
|
+
await this.config.sendRelay(worker, message);
|
|
204
|
+
console.log(`[stateless-lead] Assigned ${task.id} to ${worker} (lease expires in ${this.config.leaseDurationMs / 1000}s)`);
|
|
205
|
+
this.emit('assigned', { taskId: task.id, worker, leaseExpires });
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Handle task completion from worker
|
|
209
|
+
*/
|
|
210
|
+
async completeTask(taskId, worker, reason) {
|
|
211
|
+
await this.updateTask(taskId, {
|
|
212
|
+
status: 'closed',
|
|
213
|
+
assignee: worker,
|
|
214
|
+
});
|
|
215
|
+
console.log(`[stateless-lead] Task ${taskId} completed by ${worker}${reason ? ': ' + reason : ''}`);
|
|
216
|
+
this.emit('completed', { taskId, worker, reason });
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Handle task blocked by worker
|
|
220
|
+
*/
|
|
221
|
+
async blockTask(taskId, worker, reason) {
|
|
222
|
+
await this.updateTask(taskId, {
|
|
223
|
+
status: 'blocked',
|
|
224
|
+
assignee: worker,
|
|
225
|
+
});
|
|
226
|
+
console.log(`[stateless-lead] Task ${taskId} blocked by ${worker}: ${reason}`);
|
|
227
|
+
this.emit('blocked', { taskId, worker, reason });
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Renew lease for a task (worker signals still working)
|
|
231
|
+
*/
|
|
232
|
+
async renewLease(taskId, worker) {
|
|
233
|
+
const leaseExpires = Date.now() + this.config.leaseDurationMs;
|
|
234
|
+
await this.updateTask(taskId, { leaseExpires });
|
|
235
|
+
console.log(`[stateless-lead] Renewed lease for ${taskId} (${worker})`);
|
|
236
|
+
this.emit('leaseRenewed', { taskId, worker, leaseExpires });
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Write leader heartbeat to file (P2)
|
|
240
|
+
*/
|
|
241
|
+
async writeHeartbeat() {
|
|
242
|
+
const assignedTasks = await this.getAssignedTasks();
|
|
243
|
+
const assignedAgents = [...new Set(assignedTasks.map((t) => t.assignee).filter(Boolean))];
|
|
244
|
+
const heartbeat = {
|
|
245
|
+
leadName: this.config.agentName,
|
|
246
|
+
leadId: this.config.agentId,
|
|
247
|
+
timestamp: Date.now(),
|
|
248
|
+
activeTaskCount: assignedTasks.length,
|
|
249
|
+
assignedAgents,
|
|
250
|
+
};
|
|
251
|
+
await fs.promises.writeFile(this.heartbeatPath, JSON.stringify(heartbeat, null, 2), 'utf-8');
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Read current leader heartbeat (for watchdog - P3)
|
|
255
|
+
*/
|
|
256
|
+
static async readHeartbeat(beadsDir) {
|
|
257
|
+
const heartbeatPath = path.join(beadsDir, 'leader-heartbeat.json');
|
|
258
|
+
if (!fs.existsSync(heartbeatPath)) {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
try {
|
|
262
|
+
const content = await fs.promises.readFile(heartbeatPath, 'utf-8');
|
|
263
|
+
return JSON.parse(content);
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Check if leader is stale (for watchdog - P3)
|
|
271
|
+
*/
|
|
272
|
+
static async isLeaderStale(beadsDir, staleThresholdMs = 30000) {
|
|
273
|
+
const heartbeat = await StatelessLeadCoordinator.readHeartbeat(beadsDir);
|
|
274
|
+
if (!heartbeat)
|
|
275
|
+
return true;
|
|
276
|
+
return Date.now() - heartbeat.timestamp > staleThresholdMs;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Get current status
|
|
280
|
+
*/
|
|
281
|
+
async getStatus() {
|
|
282
|
+
const readyTasks = await this.getReadyTasks();
|
|
283
|
+
const assignedTasks = await this.getAssignedTasks();
|
|
284
|
+
const heartbeat = await StatelessLeadCoordinator.readHeartbeat(this.config.beadsDir);
|
|
285
|
+
return {
|
|
286
|
+
isRunning: this.isRunning,
|
|
287
|
+
leadName: this.config.agentName,
|
|
288
|
+
readyTasks: readyTasks.length,
|
|
289
|
+
assignedTasks: assignedTasks.length,
|
|
290
|
+
lastHeartbeat: heartbeat?.timestamp ?? null,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Create a stateless lead coordinator with defaults
|
|
296
|
+
*/
|
|
297
|
+
export function createStatelessLead(beadsDir, agentName, agentId, callbacks) {
|
|
298
|
+
return new StatelessLeadCoordinator({
|
|
299
|
+
beadsDir,
|
|
300
|
+
agentName,
|
|
301
|
+
agentId,
|
|
302
|
+
...callbacks,
|
|
303
|
+
pollIntervalMs: 5000,
|
|
304
|
+
heartbeatIntervalMs: 10000,
|
|
305
|
+
leaseDurationMs: 300000,
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
//# sourceMappingURL=stateless-lead.js.map
|
|
@@ -9,6 +9,7 @@ import { AgentHealthMonitor, HealthMonitorConfig } from './health-monitor.js';
|
|
|
9
9
|
import { LogLevel } from './logger.js';
|
|
10
10
|
import { metrics } from './metrics.js';
|
|
11
11
|
import { ProviderType } from './provider-context.js';
|
|
12
|
+
import { LeadHeartbeat } from './stateless-lead.js';
|
|
12
13
|
export interface SupervisedAgent {
|
|
13
14
|
name: string;
|
|
14
15
|
cli: string;
|
|
@@ -33,6 +34,14 @@ export interface SupervisorConfig {
|
|
|
33
34
|
baseDir?: string;
|
|
34
35
|
autoInjectOnRestart: boolean;
|
|
35
36
|
};
|
|
37
|
+
/** Leader coordination (P0-P3) */
|
|
38
|
+
leaderCoordination?: {
|
|
39
|
+
enabled: boolean;
|
|
40
|
+
/** Path to .beads directory */
|
|
41
|
+
beadsDir: string;
|
|
42
|
+
/** Callback to send relay messages */
|
|
43
|
+
sendRelay?: (to: string, message: string) => Promise<void>;
|
|
44
|
+
};
|
|
36
45
|
}
|
|
37
46
|
export declare class AgentSupervisor extends EventEmitter {
|
|
38
47
|
private config;
|
|
@@ -42,6 +51,9 @@ export declare class AgentSupervisor extends EventEmitter {
|
|
|
42
51
|
private restarters;
|
|
43
52
|
private contextPersistence?;
|
|
44
53
|
private contextHandlers;
|
|
54
|
+
private leaderWatchdog?;
|
|
55
|
+
private leadCoordinator?;
|
|
56
|
+
private supervisorAgentId;
|
|
45
57
|
constructor(config?: Partial<SupervisorConfig>);
|
|
46
58
|
/**
|
|
47
59
|
* Start supervising agents
|
|
@@ -51,6 +63,32 @@ export declare class AgentSupervisor extends EventEmitter {
|
|
|
51
63
|
* Stop supervising agents
|
|
52
64
|
*/
|
|
53
65
|
stop(): void;
|
|
66
|
+
/**
|
|
67
|
+
* Enable leader coordination with watchdog
|
|
68
|
+
* This allows this supervisor to participate in leader election and
|
|
69
|
+
* potentially become the lead coordinator for task distribution.
|
|
70
|
+
*/
|
|
71
|
+
enableLeaderCoordination(beadsDir: string, sendRelay: (to: string, message: string) => Promise<void>): void;
|
|
72
|
+
/**
|
|
73
|
+
* Called when this supervisor wins leader election
|
|
74
|
+
*/
|
|
75
|
+
private becomeLeader;
|
|
76
|
+
/**
|
|
77
|
+
* Get healthy agents for leader election
|
|
78
|
+
*/
|
|
79
|
+
private getHealthyAgents;
|
|
80
|
+
/**
|
|
81
|
+
* Get available worker names (healthy agents not currently busy)
|
|
82
|
+
*/
|
|
83
|
+
private getAvailableWorkerNames;
|
|
84
|
+
/**
|
|
85
|
+
* Check if this supervisor is currently the leader
|
|
86
|
+
*/
|
|
87
|
+
isLeader(): boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Get current leader info
|
|
90
|
+
*/
|
|
91
|
+
getCurrentLeader(): LeadHeartbeat | null;
|
|
54
92
|
/**
|
|
55
93
|
* Add an agent to supervision
|
|
56
94
|
*/
|
|
@@ -10,6 +10,8 @@ import { createLogger } from './logger.js';
|
|
|
10
10
|
import { metrics } from './metrics.js';
|
|
11
11
|
import { getContextPersistence } from './context-persistence.js';
|
|
12
12
|
import { createContextHandler, detectProvider } from './provider-context.js';
|
|
13
|
+
import { LeaderWatchdog } from './leader-watchdog.js';
|
|
14
|
+
import { StatelessLeadCoordinator } from './stateless-lead.js';
|
|
13
15
|
const DEFAULT_CONFIG = {
|
|
14
16
|
healthCheck: {
|
|
15
17
|
checkIntervalMs: 5000,
|
|
@@ -34,9 +36,13 @@ export class AgentSupervisor extends EventEmitter {
|
|
|
34
36
|
restarters = new Map();
|
|
35
37
|
contextPersistence;
|
|
36
38
|
contextHandlers = new Map();
|
|
39
|
+
leaderWatchdog;
|
|
40
|
+
leadCoordinator;
|
|
41
|
+
supervisorAgentId;
|
|
37
42
|
constructor(config = {}) {
|
|
38
43
|
super();
|
|
39
44
|
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
45
|
+
this.supervisorAgentId = `supervisor-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
40
46
|
this.logger = createLogger('supervisor', {
|
|
41
47
|
level: this.config.logging.level,
|
|
42
48
|
file: this.config.logging.file,
|
|
@@ -66,6 +72,15 @@ export class AgentSupervisor extends EventEmitter {
|
|
|
66
72
|
stop() {
|
|
67
73
|
this.logger.info('Agent supervisor stopping');
|
|
68
74
|
this.healthMonitor.stop();
|
|
75
|
+
// Stop leader coordination
|
|
76
|
+
if (this.leaderWatchdog) {
|
|
77
|
+
this.leaderWatchdog.stop();
|
|
78
|
+
}
|
|
79
|
+
if (this.leadCoordinator) {
|
|
80
|
+
this.leadCoordinator.stop().catch((err) => {
|
|
81
|
+
this.logger.error('Error stopping lead coordinator', { error: String(err) });
|
|
82
|
+
});
|
|
83
|
+
}
|
|
69
84
|
// Stop context persistence
|
|
70
85
|
if (this.contextPersistence) {
|
|
71
86
|
this.contextPersistence.stopAutoSave();
|
|
@@ -77,6 +92,113 @@ export class AgentSupervisor extends EventEmitter {
|
|
|
77
92
|
});
|
|
78
93
|
});
|
|
79
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Enable leader coordination with watchdog
|
|
97
|
+
* This allows this supervisor to participate in leader election and
|
|
98
|
+
* potentially become the lead coordinator for task distribution.
|
|
99
|
+
*/
|
|
100
|
+
enableLeaderCoordination(beadsDir, sendRelay) {
|
|
101
|
+
if (this.leaderWatchdog) {
|
|
102
|
+
this.logger.warn('Leader coordination already enabled');
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
this.logger.info('Enabling leader coordination', { beadsDir });
|
|
106
|
+
// Create watchdog to monitor leader health
|
|
107
|
+
this.leaderWatchdog = new LeaderWatchdog({
|
|
108
|
+
beadsDir,
|
|
109
|
+
agentName: 'supervisor',
|
|
110
|
+
agentId: this.supervisorAgentId,
|
|
111
|
+
checkIntervalMs: 5000,
|
|
112
|
+
staleThresholdMs: 30000,
|
|
113
|
+
onBecomeLeader: async () => {
|
|
114
|
+
await this.becomeLeader(beadsDir, sendRelay);
|
|
115
|
+
},
|
|
116
|
+
getHealthyAgents: async () => {
|
|
117
|
+
return this.getHealthyAgents();
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
// Forward watchdog events
|
|
121
|
+
this.leaderWatchdog.on('electionStarted', (data) => this.emit('electionStarted', data));
|
|
122
|
+
this.leaderWatchdog.on('electionComplete', (data) => this.emit('electionComplete', data));
|
|
123
|
+
this.leaderWatchdog.on('becameLeader', () => this.emit('becameLeader'));
|
|
124
|
+
this.leaderWatchdog.on('leaderStale', (data) => this.emit('leaderStale', data));
|
|
125
|
+
this.leaderWatchdog.start();
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Called when this supervisor wins leader election
|
|
129
|
+
*/
|
|
130
|
+
async becomeLeader(beadsDir, sendRelay) {
|
|
131
|
+
this.logger.info('This supervisor is becoming the lead coordinator');
|
|
132
|
+
// Stop existing coordinator if any
|
|
133
|
+
if (this.leadCoordinator) {
|
|
134
|
+
await this.leadCoordinator.stop();
|
|
135
|
+
}
|
|
136
|
+
// Create stateless lead coordinator
|
|
137
|
+
this.leadCoordinator = new StatelessLeadCoordinator({
|
|
138
|
+
beadsDir,
|
|
139
|
+
agentName: 'supervisor',
|
|
140
|
+
agentId: this.supervisorAgentId,
|
|
141
|
+
pollIntervalMs: 5000,
|
|
142
|
+
heartbeatIntervalMs: 10000,
|
|
143
|
+
leaseDurationMs: 300000,
|
|
144
|
+
sendRelay,
|
|
145
|
+
getAvailableWorkers: async () => {
|
|
146
|
+
return this.getAvailableWorkerNames();
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
// Forward coordinator events
|
|
150
|
+
this.leadCoordinator.on('assigned', (data) => this.emit('taskAssigned', data));
|
|
151
|
+
this.leadCoordinator.on('completed', (data) => this.emit('taskCompleted', data));
|
|
152
|
+
await this.leadCoordinator.start();
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get healthy agents for leader election
|
|
156
|
+
*/
|
|
157
|
+
getHealthyAgents() {
|
|
158
|
+
const healthyAgents = [];
|
|
159
|
+
for (const [name, agent] of this.agents) {
|
|
160
|
+
const health = this.healthMonitor.get(name);
|
|
161
|
+
if (health && health.status === 'healthy') {
|
|
162
|
+
healthyAgents.push({
|
|
163
|
+
name: agent.name,
|
|
164
|
+
id: `${agent.name}-${agent.pid}`,
|
|
165
|
+
spawnedAt: agent.spawnedAt,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Include supervisor itself as a candidate
|
|
170
|
+
healthyAgents.push({
|
|
171
|
+
name: 'supervisor',
|
|
172
|
+
id: this.supervisorAgentId,
|
|
173
|
+
spawnedAt: new Date(0), // Supervisor is always oldest
|
|
174
|
+
});
|
|
175
|
+
return healthyAgents;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Get available worker names (healthy agents not currently busy)
|
|
179
|
+
*/
|
|
180
|
+
getAvailableWorkerNames() {
|
|
181
|
+
const available = [];
|
|
182
|
+
for (const [name, agent] of this.agents) {
|
|
183
|
+
const health = this.healthMonitor.get(name);
|
|
184
|
+
if (health && health.status === 'healthy') {
|
|
185
|
+
available.push(agent.name);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return available;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Check if this supervisor is currently the leader
|
|
192
|
+
*/
|
|
193
|
+
isLeader() {
|
|
194
|
+
return this.leaderWatchdog?.isCurrentLeader() ?? false;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Get current leader info
|
|
198
|
+
*/
|
|
199
|
+
getCurrentLeader() {
|
|
200
|
+
return this.leaderWatchdog?.getCurrentLeader() ?? null;
|
|
201
|
+
}
|
|
80
202
|
/**
|
|
81
203
|
* Add an agent to supervision
|
|
82
204
|
*/
|