agent-relay 1.3.2 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -158
- package/bin/relay-pty +0 -0
- package/bin/relay-pty-darwin-arm64 +0 -0
- package/bin/relay-pty-darwin-x64 +0 -0
- package/bin/relay-pty-linux-x64 +0 -0
- package/deploy/workspace/entrypoint.sh +9 -0
- package/dist/bridge/spawner.d.ts +4 -4
- package/dist/bridge/spawner.js +58 -92
- package/dist/cli/index.d.ts +8 -6
- package/dist/cli/index.js +282 -47
- package/dist/cloud/api/daemons.js +13 -32
- package/dist/cloud/api/onboarding.js +2 -4
- package/dist/cloud/api/providers.js +6 -0
- package/dist/cloud/config.d.ts +1 -0
- package/dist/cloud/config.js +2 -0
- package/dist/cloud/db/bulk-ingest.d.ts +2 -1
- package/dist/cloud/db/drizzle.d.ts +21 -26
- package/dist/cloud/db/drizzle.js +87 -100
- package/dist/cloud/db/index.d.ts +6 -5
- package/dist/cloud/db/index.js +9 -8
- package/dist/cloud/db/schema.d.ts +1049 -1076
- package/dist/cloud/db/schema.js +59 -71
- package/dist/cloud/server.js +854 -18
- package/dist/cloud/services/persistence.d.ts +15 -15
- package/dist/cloud/services/persistence.js +14 -14
- package/dist/daemon/agent-manager.d.ts +6 -5
- package/dist/daemon/agent-manager.js +12 -8
- package/dist/daemon/channel-membership-store.d.ts +48 -0
- package/dist/daemon/channel-membership-store.js +149 -0
- package/dist/daemon/cloud-sync.d.ts +2 -0
- package/dist/daemon/cloud-sync.js +4 -0
- package/dist/daemon/connection.js +17 -9
- package/dist/daemon/router.d.ts +37 -0
- package/dist/daemon/router.js +318 -79
- package/dist/daemon/server.d.ts +15 -0
- package/dist/daemon/server.js +141 -3
- package/dist/dashboard/out/404.html +1 -0
- package/dist/dashboard/out/_next/static/IxxVRv94L1w3ReRGAiI-k/_buildManifest.js +1 -0
- package/dist/dashboard/out/_next/static/IxxVRv94L1w3ReRGAiI-k/_ssgManifest.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/116-eacf84a131b80db9.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/117-c8afed19e821a35d.js +2 -0
- package/dist/dashboard/out/_next/static/chunks/282-980c2eb8fff20123.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/532-bace199897eeab37.js +9 -0
- package/dist/dashboard/out/_next/static/chunks/64-87ab9cd6bcf2f737.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/648-acb2ff9f77cbfbd3.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/766-aa7c8c9900ff5f53.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/83-4f08122d4e7e79a6.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/847-f1f467060f32afff.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/891-a024fbe4b619cf6f.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/_not-found/page-60501fddbafba9dc.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/onboarding/page-f746f29e01fffc43.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/page-ffad986adfcc8b31.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/cloud/link/page-cfeb437f08a12ed9.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/connect-repos/page-03ac6f35a6654ea6.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/history/page-240f91e8b06ba8ac.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/layout-c0d118c0f92d969c.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/login/page-6ec54eee75877971.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/metrics/page-82938ab8fcf44694.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/page-671037943b2f2e43.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/pricing/page-0efa024c28ba4597.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/providers/page-57cbd738c6a73859.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/providers/setup/[provider]/page-5ab0854472b402b0.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/signup/page-18a4665665f6be11.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/e868780c-48e5f147c90a3a41.js +18 -0
- package/dist/dashboard/out/_next/static/chunks/fd9d1056-609918ca7b6280bb.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/framework-f66176bb897dc684.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/main-5a40a5ae29646e1b.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/main-app-6e8e8d3ef4e0192a.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/pages/_app-72b849fbd24ac258.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/pages/_error-7ba65e1336b92748.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/webpack-1cdd8ed57114d5e1.js +1 -0
- package/dist/dashboard/out/_next/static/css/4034f236dd1a3178.css +1 -0
- package/dist/dashboard/out/_next/static/css/8f9ed310f454e5a5.css +1 -0
- package/dist/dashboard/out/alt-logos/agent-relay-logo-128.png +0 -0
- package/dist/dashboard/out/alt-logos/agent-relay-logo-256.png +0 -0
- package/dist/dashboard/out/alt-logos/agent-relay-logo-32.png +0 -0
- package/dist/dashboard/out/alt-logos/agent-relay-logo-512.png +0 -0
- package/dist/dashboard/out/alt-logos/agent-relay-logo-64.png +0 -0
- package/dist/dashboard/out/alt-logos/agent-relay-logo.svg +45 -0
- package/dist/dashboard/out/alt-logos/logo.svg +38 -0
- package/dist/dashboard/out/alt-logos/monogram-logo-128.png +0 -0
- package/dist/dashboard/out/alt-logos/monogram-logo-256.png +0 -0
- package/dist/dashboard/out/alt-logos/monogram-logo-32.png +0 -0
- package/dist/dashboard/out/alt-logos/monogram-logo-512.png +0 -0
- package/dist/dashboard/out/alt-logos/monogram-logo-64.png +0 -0
- package/dist/dashboard/out/alt-logos/monogram-logo.svg +38 -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 -0
- package/dist/dashboard/out/app.txt +7 -0
- package/dist/dashboard/out/apple-icon.png +0 -0
- package/dist/dashboard/out/cloud/link.html +1 -0
- package/dist/dashboard/out/cloud/link.txt +7 -0
- 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 -0
- package/dist/dashboard/out/history.txt +7 -0
- package/dist/dashboard/out/index.html +1 -0
- package/dist/dashboard/out/index.txt +7 -0
- package/dist/dashboard/out/login.html +5 -0
- package/dist/dashboard/out/login.txt +7 -0
- package/dist/dashboard/out/metrics.html +1 -0
- package/dist/dashboard/out/metrics.txt +7 -0
- package/dist/dashboard/out/pricing.html +13 -0
- package/dist/dashboard/out/pricing.txt +7 -0
- package/dist/dashboard/out/providers/setup/claude.html +1 -0
- package/dist/dashboard/out/providers/setup/claude.txt +8 -0
- package/dist/dashboard/out/providers/setup/codex.html +1 -0
- package/dist/dashboard/out/providers/setup/codex.txt +8 -0
- package/dist/dashboard/out/providers.html +1 -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/metrics.d.ts +105 -0
- package/dist/dashboard-server/metrics.js +193 -0
- package/dist/dashboard-server/needs-attention.d.ts +24 -0
- package/dist/dashboard-server/needs-attention.js +78 -0
- package/dist/dashboard-server/server.d.ts +15 -0
- package/dist/dashboard-server/server.js +4753 -0
- package/dist/dashboard-server/start.d.ts +6 -0
- package/dist/dashboard-server/start.js +13 -0
- package/dist/dashboard-server/user-bridge.d.ts +132 -0
- package/dist/dashboard-server/user-bridge.js +317 -0
- package/dist/protocol/channels.d.ts +14 -8
- package/dist/protocol/channels.js +1 -1
- package/dist/protocol/index.d.ts +1 -0
- package/dist/protocol/index.js +1 -0
- package/dist/protocol/relay-pty-schemas.d.ts +209 -0
- package/dist/protocol/relay-pty-schemas.js +60 -0
- package/dist/wrapper/auth-detection.js +8 -1
- package/dist/wrapper/base-wrapper.d.ts +11 -1
- package/dist/wrapper/base-wrapper.js +67 -6
- package/dist/wrapper/client.d.ts +49 -1
- package/dist/wrapper/client.js +167 -0
- package/dist/wrapper/parser.d.ts +0 -4
- package/dist/wrapper/parser.js +38 -10
- package/dist/wrapper/pty-wrapper.d.ts +12 -1
- package/dist/wrapper/pty-wrapper.js +104 -5
- package/dist/wrapper/relay-pty-orchestrator.d.ts +270 -0
- package/dist/wrapper/relay-pty-orchestrator.js +970 -0
- package/dist/wrapper/shared.d.ts +1 -1
- package/dist/wrapper/shared.js +14 -4
- package/dist/wrapper/tmux-wrapper.d.ts +13 -1
- package/dist/wrapper/tmux-wrapper.js +143 -29
- package/package.json +9 -4
- package/scripts/postinstall.js +101 -11
- package/.trajectories/active/traj_3yx9dy148mge.json +0 -42
- package/.trajectories/agent-relay-322-324.md +0 -17
- package/.trajectories/completed/2026-01/traj_03zupyv1s7b9.json +0 -49
- package/.trajectories/completed/2026-01/traj_03zupyv1s7b9.md +0 -31
- package/.trajectories/completed/2026-01/traj_0zacdjl1g4ht.json +0 -125
- package/.trajectories/completed/2026-01/traj_0zacdjl1g4ht.md +0 -62
- package/.trajectories/completed/2026-01/traj_1dviorhnkcb5.json +0 -65
- package/.trajectories/completed/2026-01/traj_1dviorhnkcb5.md +0 -37
- package/.trajectories/completed/2026-01/traj_1g7yx6qtg4ai.json +0 -49
- package/.trajectories/completed/2026-01/traj_1g7yx6qtg4ai.md +0 -31
- package/.trajectories/completed/2026-01/traj_1k5if5snst2e.json +0 -65
- package/.trajectories/completed/2026-01/traj_1k5if5snst2e.md +0 -37
- package/.trajectories/completed/2026-01/traj_1rp3rges5811.json +0 -49
- package/.trajectories/completed/2026-01/traj_1rp3rges5811.md +0 -31
- package/.trajectories/completed/2026-01/traj_22bhyulruouw.json +0 -113
- package/.trajectories/completed/2026-01/traj_22bhyulruouw.md +0 -57
- package/.trajectories/completed/2026-01/traj_2dao7ddgnta0.json +0 -53
- package/.trajectories/completed/2026-01/traj_2dao7ddgnta0.md +0 -32
- package/.trajectories/completed/2026-01/traj_33iuy72sezbk.json +0 -49
- package/.trajectories/completed/2026-01/traj_33iuy72sezbk.md +0 -31
- package/.trajectories/completed/2026-01/traj_3t0440mjeunc.json +0 -26
- package/.trajectories/completed/2026-01/traj_3t0440mjeunc.md +0 -6
- package/.trajectories/completed/2026-01/traj_45x9494d9xnr.json +0 -47
- package/.trajectories/completed/2026-01/traj_45x9494d9xnr.md +0 -32
- package/.trajectories/completed/2026-01/traj_4aa0bb77s4nh.json +0 -53
- package/.trajectories/completed/2026-01/traj_4aa0bb77s4nh.md +0 -32
- package/.trajectories/completed/2026-01/traj_4qwd4zmhfwp4.json +0 -49
- package/.trajectories/completed/2026-01/traj_4qwd4zmhfwp4.md +0 -31
- package/.trajectories/completed/2026-01/traj_5ammh5qtvklq.json +0 -77
- package/.trajectories/completed/2026-01/traj_5ammh5qtvklq.md +0 -42
- package/.trajectories/completed/2026-01/traj_5lhmzq8rxpqv.json +0 -59
- package/.trajectories/completed/2026-01/traj_5lhmzq8rxpqv.md +0 -33
- package/.trajectories/completed/2026-01/traj_5vr4e9erb1fs.json +0 -53
- package/.trajectories/completed/2026-01/traj_5vr4e9erb1fs.md +0 -32
- package/.trajectories/completed/2026-01/traj_6fgiwdoklvym.json +0 -48
- package/.trajectories/completed/2026-01/traj_6fgiwdoklvym.md +0 -24
- package/.trajectories/completed/2026-01/traj_6mieijqyvaag.json +0 -77
- package/.trajectories/completed/2026-01/traj_6mieijqyvaag.md +0 -42
- package/.trajectories/completed/2026-01/traj_6unwwmgyj5sq.json +0 -109
- package/.trajectories/completed/2026-01/traj_78ffm31jn3uk.json +0 -77
- package/.trajectories/completed/2026-01/traj_78ffm31jn3uk.md +0 -42
- package/.trajectories/completed/2026-01/traj_7ludwvz45veh.json +0 -209
- package/.trajectories/completed/2026-01/traj_7ludwvz45veh.md +0 -97
- package/.trajectories/completed/2026-01/traj_94gnp3k30goq.json +0 -66
- package/.trajectories/completed/2026-01/traj_94gnp3k30goq.md +0 -36
- package/.trajectories/completed/2026-01/traj_9921cuhel0pj.json +0 -48
- package/.trajectories/completed/2026-01/traj_9921cuhel0pj.md +0 -24
- package/.trajectories/completed/2026-01/traj_a0tqx8biw9c4.json +0 -49
- package/.trajectories/completed/2026-01/traj_a0tqx8biw9c4.md +0 -31
- package/.trajectories/completed/2026-01/traj_ajs7zqfux4wc.json +0 -49
- package/.trajectories/completed/2026-01/traj_ajs7zqfux4wc.md +0 -23
- package/.trajectories/completed/2026-01/traj_avqeghu6pz5a.json +0 -40
- package/.trajectories/completed/2026-01/traj_avqeghu6pz5a.md +0 -22
- package/.trajectories/completed/2026-01/traj_ax8uungxz2qh.json +0 -66
- package/.trajectories/completed/2026-01/traj_ax8uungxz2qh.md +0 -36
- package/.trajectories/completed/2026-01/traj_c9izbh2snpzf.json +0 -49
- package/.trajectories/completed/2026-01/traj_c9izbh2snpzf.md +0 -31
- package/.trajectories/completed/2026-01/traj_cpn70dw066nt.json +0 -65
- package/.trajectories/completed/2026-01/traj_cpn70dw066nt.md +0 -37
- package/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.json +0 -53
- package/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.md +0 -32
- package/.trajectories/completed/2026-01/traj_cxofprm2m2en.json +0 -49
- package/.trajectories/completed/2026-01/traj_cxofprm2m2en.md +0 -31
- package/.trajectories/completed/2026-01/traj_d2hhz3k0vrhn.json +0 -26
- package/.trajectories/completed/2026-01/traj_d2hhz3k0vrhn.md +0 -6
- package/.trajectories/completed/2026-01/traj_dcsp9s8y01ra.json +0 -121
- package/.trajectories/completed/2026-01/traj_dcsp9s8y01ra.md +0 -29
- package/.trajectories/completed/2026-01/traj_dfuvww9pege5.json +0 -59
- package/.trajectories/completed/2026-01/traj_dfuvww9pege5.md +0 -37
- package/.trajectories/completed/2026-01/traj_erglv2f8t9eh.json +0 -36
- package/.trajectories/completed/2026-01/traj_erglv2f8t9eh.md +0 -21
- package/.trajectories/completed/2026-01/traj_fhx9irlckht6.json +0 -53
- package/.trajectories/completed/2026-01/traj_fhx9irlckht6.md +0 -32
- package/.trajectories/completed/2026-01/traj_fqduidx3xbtp.json +0 -101
- package/.trajectories/completed/2026-01/traj_fqduidx3xbtp.md +0 -52
- package/.trajectories/completed/2026-01/traj_g0fisy9h51mf.json +0 -77
- package/.trajectories/completed/2026-01/traj_g0fisy9h51mf.md +0 -42
- package/.trajectories/completed/2026-01/traj_gjdre5voouod.json +0 -53
- package/.trajectories/completed/2026-01/traj_gjdre5voouod.md +0 -32
- package/.trajectories/completed/2026-01/traj_gtlyqtta3x8l.json +0 -25
- package/.trajectories/completed/2026-01/traj_gtlyqtta3x8l.md +0 -15
- package/.trajectories/completed/2026-01/traj_h4xijiuip3w4.json +0 -101
- package/.trajectories/completed/2026-01/traj_h4xijiuip3w4.md +0 -44
- package/.trajectories/completed/2026-01/traj_he75f24d1xfm.json +0 -101
- package/.trajectories/completed/2026-01/traj_he75f24d1xfm.md +0 -52
- package/.trajectories/completed/2026-01/traj_hf81ey93uz6t.json +0 -49
- package/.trajectories/completed/2026-01/traj_hf81ey93uz6t.md +0 -31
- package/.trajectories/completed/2026-01/traj_hfmki2jr9d4r.json +0 -65
- package/.trajectories/completed/2026-01/traj_hfmki2jr9d4r.md +0 -37
- package/.trajectories/completed/2026-01/traj_hhxte7w4gjjx.json +0 -22
- package/.trajectories/completed/2026-01/traj_hhxte7w4gjjx.md +0 -5
- package/.trajectories/completed/2026-01/traj_hpungyhoj6v5.json +0 -53
- package/.trajectories/completed/2026-01/traj_hpungyhoj6v5.md +0 -32
- package/.trajectories/completed/2026-01/traj_lgtodco7dp1n.json +0 -61
- package/.trajectories/completed/2026-01/traj_lgtodco7dp1n.md +0 -36
- package/.trajectories/completed/2026-01/traj_lq450ly148uw.json +0 -49
- package/.trajectories/completed/2026-01/traj_lq450ly148uw.md +0 -31
- package/.trajectories/completed/2026-01/traj_m2xkjv0w2sq7.json +0 -25
- package/.trajectories/completed/2026-01/traj_m2xkjv0w2sq7.md +0 -15
- package/.trajectories/completed/2026-01/traj_multi_server_arch.md +0 -101
- package/.trajectories/completed/2026-01/traj_noq5zbvnrdvz.json +0 -53
- package/.trajectories/completed/2026-01/traj_noq5zbvnrdvz.md +0 -32
- package/.trajectories/completed/2026-01/traj_ntbs6ppopf46.json +0 -53
- package/.trajectories/completed/2026-01/traj_ntbs6ppopf46.md +0 -32
- package/.trajectories/completed/2026-01/traj_oszg9flv74pk.json +0 -73
- package/.trajectories/completed/2026-01/traj_oszg9flv74pk.md +0 -41
- package/.trajectories/completed/2026-01/traj_ozd98si6a7ns.json +0 -48
- package/.trajectories/completed/2026-01/traj_ozd98si6a7ns.md +0 -24
- package/.trajectories/completed/2026-01/traj_prdza7a5cxp5.json +0 -53
- package/.trajectories/completed/2026-01/traj_prdza7a5cxp5.md +0 -32
- package/.trajectories/completed/2026-01/traj_psd9ob0j2ru3.json +0 -27
- package/.trajectories/completed/2026-01/traj_psd9ob0j2ru3.md +0 -14
- package/.trajectories/completed/2026-01/traj_pulomd3y8cvj.json +0 -77
- package/.trajectories/completed/2026-01/traj_pulomd3y8cvj.md +0 -42
- package/.trajectories/completed/2026-01/traj_qb3twvvywfwi.json +0 -77
- package/.trajectories/completed/2026-01/traj_qb3twvvywfwi.md +0 -42
- package/.trajectories/completed/2026-01/traj_qft54mi7nfor.json +0 -53
- package/.trajectories/completed/2026-01/traj_qft54mi7nfor.md +0 -32
- package/.trajectories/completed/2026-01/traj_qx9uhf8whhxo.json +0 -83
- package/.trajectories/completed/2026-01/traj_qx9uhf8whhxo.md +0 -47
- package/.trajectories/completed/2026-01/traj_rd9toccj18a0.json +0 -59
- package/.trajectories/completed/2026-01/traj_rd9toccj18a0.md +0 -37
- package/.trajectories/completed/2026-01/traj_rsavt0jipi3c.json +0 -109
- package/.trajectories/completed/2026-01/traj_rsavt0jipi3c.md +0 -56
- package/.trajectories/completed/2026-01/traj_rt4fiw3ecp50.json +0 -48
- package/.trajectories/completed/2026-01/traj_rt4fiw3ecp50.md +0 -16
- package/.trajectories/completed/2026-01/traj_st8j35b0hrlc.json +0 -59
- package/.trajectories/completed/2026-01/traj_st8j35b0hrlc.md +0 -37
- package/.trajectories/completed/2026-01/traj_t1yy8m7hbuxp.json +0 -53
- package/.trajectories/completed/2026-01/traj_t1yy8m7hbuxp.md +0 -32
- package/.trajectories/completed/2026-01/traj_tmux_orchestrator_analysis.json +0 -84
- package/.trajectories/completed/2026-01/traj_tmux_orchestrator_analysis.md +0 -109
- package/.trajectories/completed/2026-01/traj_u9n9eqasw16k.json +0 -53
- package/.trajectories/completed/2026-01/traj_u9n9eqasw16k.md +0 -32
- package/.trajectories/completed/2026-01/traj_ub8csuv3lcv4.json +0 -53
- package/.trajectories/completed/2026-01/traj_ub8csuv3lcv4.md +0 -32
- package/.trajectories/completed/2026-01/traj_uc29tlso8i9s.json +0 -186
- package/.trajectories/completed/2026-01/traj_uc29tlso8i9s.md +0 -86
- package/.trajectories/completed/2026-01/traj_ui9b4tqxoa7j.json +0 -77
- package/.trajectories/completed/2026-01/traj_ui9b4tqxoa7j.md +0 -42
- package/.trajectories/completed/2026-01/traj_v87hypnongqx.json +0 -71
- package/.trajectories/completed/2026-01/traj_v87hypnongqx.md +0 -42
- package/.trajectories/completed/2026-01/traj_v9dkdoxylyid.json +0 -89
- package/.trajectories/completed/2026-01/traj_v9dkdoxylyid.md +0 -47
- package/.trajectories/completed/2026-01/traj_wkp2fgzdyinb.json +0 -53
- package/.trajectories/completed/2026-01/traj_wkp2fgzdyinb.md +0 -32
- package/.trajectories/completed/2026-01/traj_x14t8w8rn7xg.json +0 -20
- package/.trajectories/completed/2026-01/traj_x14t8w8rn7xg.md +0 -6
- package/.trajectories/completed/2026-01/traj_x721m1j9rzup.json +0 -113
- package/.trajectories/completed/2026-01/traj_x721m1j9rzup.md +0 -57
- package/.trajectories/completed/2026-01/traj_xjqvmep5ed3h.json +0 -61
- package/.trajectories/completed/2026-01/traj_xjqvmep5ed3h.md +0 -36
- package/.trajectories/completed/2026-01/traj_xnwbznkvv8ua.json +0 -175
- package/.trajectories/completed/2026-01/traj_xnwbznkvv8ua.md +0 -82
- package/.trajectories/completed/2026-01/traj_xy9vifpqet80.json +0 -65
- package/.trajectories/completed/2026-01/traj_xy9vifpqet80.md +0 -37
- package/.trajectories/completed/2026-01/traj_y7aiwijyfmmv.json +0 -49
- package/.trajectories/completed/2026-01/traj_y7aiwijyfmmv.md +0 -31
- package/.trajectories/completed/2026-01/traj_y7n6hfbf7dmg.json +0 -49
- package/.trajectories/completed/2026-01/traj_y7n6hfbf7dmg.md +0 -31
- package/.trajectories/completed/2026-01/traj_ysjc8zaeqtd3.json +0 -47
- package/.trajectories/completed/2026-01/traj_ysjc8zaeqtd3.md +0 -32
- package/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.json +0 -59
- package/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.md +0 -37
- package/.trajectories/completed/2026-01/traj_yvfkwnkdiso2.json +0 -49
- package/.trajectories/completed/2026-01/traj_yvfkwnkdiso2.md +0 -31
- package/.trajectories/completed/2026-01/traj_z0vcw1wrzide.json +0 -53
- package/.trajectories/completed/2026-01/traj_z0vcw1wrzide.md +0 -32
- package/.trajectories/consolidate-settings-panel.md +0 -24
- package/.trajectories/gh-cli-user-token.md +0 -26
- package/.trajectories/index.json +0 -607
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
* Cloud Persistence Service
|
|
3
3
|
*
|
|
4
4
|
* Handles durable persistence of agent session data for cloud deployments.
|
|
5
|
-
* Subscribes to
|
|
5
|
+
* Subscribes to wrapper events ('summary', 'session-end') and persists
|
|
6
6
|
* to PostgreSQL via Drizzle ORM.
|
|
7
7
|
*
|
|
8
|
-
* This decouples
|
|
8
|
+
* This decouples wrappers from storage concerns - the wrapper emits events,
|
|
9
9
|
* this service handles persistence. Different storage backends can be swapped
|
|
10
10
|
* by implementing alternative persistence services.
|
|
11
11
|
*
|
|
12
|
-
* @see
|
|
12
|
+
* @see RelayPtyOrchestratorEvents in src/wrapper/relay-pty-orchestrator.ts for event definitions
|
|
13
13
|
*/
|
|
14
|
-
import type {
|
|
14
|
+
import type { RelayPtyOrchestrator } from '../../wrapper/relay-pty-orchestrator.js';
|
|
15
15
|
/**
|
|
16
16
|
* Configuration for CloudPersistenceService
|
|
17
17
|
*/
|
|
@@ -32,12 +32,12 @@ export interface CloudPersistenceConfig {
|
|
|
32
32
|
* workspaceId: 'workspace-123',
|
|
33
33
|
* });
|
|
34
34
|
*
|
|
35
|
-
* // Bind to a
|
|
36
|
-
* const pty = new
|
|
37
|
-
* const sessionId = await persistence.
|
|
35
|
+
* // Bind to a RelayPtyOrchestrator instance
|
|
36
|
+
* const pty = new RelayPtyOrchestrator(config);
|
|
37
|
+
* const sessionId = await persistence.bindToWrapper(pty);
|
|
38
38
|
*
|
|
39
39
|
* // When done, unbind to clean up listeners
|
|
40
|
-
* persistence.
|
|
40
|
+
* persistence.unbindFromWrapper(pty);
|
|
41
41
|
* ```
|
|
42
42
|
*/
|
|
43
43
|
export declare class CloudPersistenceService {
|
|
@@ -45,19 +45,19 @@ export declare class CloudPersistenceService {
|
|
|
45
45
|
private boundWrappers;
|
|
46
46
|
constructor(config: CloudPersistenceConfig);
|
|
47
47
|
/**
|
|
48
|
-
* Bind to a
|
|
48
|
+
* Bind to a RelayPtyOrchestrator instance and start persisting its events.
|
|
49
49
|
* Creates a new agent session record and returns the session ID.
|
|
50
50
|
*
|
|
51
|
-
* @param wrapper The
|
|
51
|
+
* @param wrapper The RelayPtyOrchestrator to bind to
|
|
52
52
|
* @returns The session ID for this agent session
|
|
53
53
|
*/
|
|
54
|
-
|
|
54
|
+
bindToRelayPtyOrchestrator(wrapper: RelayPtyOrchestrator): Promise<string>;
|
|
55
55
|
/**
|
|
56
|
-
* Unbind from a
|
|
56
|
+
* Unbind from a RelayPtyOrchestrator and clean up event listeners.
|
|
57
57
|
*
|
|
58
|
-
* @param wrapper The
|
|
58
|
+
* @param wrapper The RelayPtyOrchestrator to unbind from
|
|
59
59
|
*/
|
|
60
|
-
|
|
60
|
+
unbindFromRelayPtyOrchestrator(wrapper: RelayPtyOrchestrator): void;
|
|
61
61
|
/**
|
|
62
62
|
* Handle a summary event - persist to agent_summaries table.
|
|
63
63
|
*/
|
|
@@ -69,7 +69,7 @@ export declare class CloudPersistenceService {
|
|
|
69
69
|
/**
|
|
70
70
|
* Get the session ID for a bound wrapper.
|
|
71
71
|
*/
|
|
72
|
-
getSessionId(wrapper:
|
|
72
|
+
getSessionId(wrapper: RelayPtyOrchestrator): string | undefined;
|
|
73
73
|
/**
|
|
74
74
|
* Get all summaries for a session.
|
|
75
75
|
*/
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
* Cloud Persistence Service
|
|
3
3
|
*
|
|
4
4
|
* Handles durable persistence of agent session data for cloud deployments.
|
|
5
|
-
* Subscribes to
|
|
5
|
+
* Subscribes to wrapper events ('summary', 'session-end') and persists
|
|
6
6
|
* to PostgreSQL via Drizzle ORM.
|
|
7
7
|
*
|
|
8
|
-
* This decouples
|
|
8
|
+
* This decouples wrappers from storage concerns - the wrapper emits events,
|
|
9
9
|
* this service handles persistence. Different storage backends can be swapped
|
|
10
10
|
* by implementing alternative persistence services.
|
|
11
11
|
*
|
|
12
|
-
* @see
|
|
12
|
+
* @see RelayPtyOrchestratorEvents in src/wrapper/relay-pty-orchestrator.ts for event definitions
|
|
13
13
|
*/
|
|
14
14
|
import { eq, and, desc } from 'drizzle-orm';
|
|
15
15
|
import { getDb } from '../db/drizzle.js';
|
|
@@ -23,12 +23,12 @@ import { agentSessions, agentSummaries } from '../db/schema.js';
|
|
|
23
23
|
* workspaceId: 'workspace-123',
|
|
24
24
|
* });
|
|
25
25
|
*
|
|
26
|
-
* // Bind to a
|
|
27
|
-
* const pty = new
|
|
28
|
-
* const sessionId = await persistence.
|
|
26
|
+
* // Bind to a RelayPtyOrchestrator instance
|
|
27
|
+
* const pty = new RelayPtyOrchestrator(config);
|
|
28
|
+
* const sessionId = await persistence.bindToWrapper(pty);
|
|
29
29
|
*
|
|
30
30
|
* // When done, unbind to clean up listeners
|
|
31
|
-
* persistence.
|
|
31
|
+
* persistence.unbindFromWrapper(pty);
|
|
32
32
|
* ```
|
|
33
33
|
*/
|
|
34
34
|
export class CloudPersistenceService {
|
|
@@ -38,13 +38,13 @@ export class CloudPersistenceService {
|
|
|
38
38
|
this.config = config;
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
|
-
* Bind to a
|
|
41
|
+
* Bind to a RelayPtyOrchestrator instance and start persisting its events.
|
|
42
42
|
* Creates a new agent session record and returns the session ID.
|
|
43
43
|
*
|
|
44
|
-
* @param wrapper The
|
|
44
|
+
* @param wrapper The RelayPtyOrchestrator to bind to
|
|
45
45
|
* @returns The session ID for this agent session
|
|
46
46
|
*/
|
|
47
|
-
async
|
|
47
|
+
async bindToRelayPtyOrchestrator(wrapper) {
|
|
48
48
|
const db = getDb();
|
|
49
49
|
const agentName = wrapper.name;
|
|
50
50
|
// Create session record
|
|
@@ -79,11 +79,11 @@ export class CloudPersistenceService {
|
|
|
79
79
|
return sessionId;
|
|
80
80
|
}
|
|
81
81
|
/**
|
|
82
|
-
* Unbind from a
|
|
82
|
+
* Unbind from a RelayPtyOrchestrator and clean up event listeners.
|
|
83
83
|
*
|
|
84
|
-
* @param wrapper The
|
|
84
|
+
* @param wrapper The RelayPtyOrchestrator to unbind from
|
|
85
85
|
*/
|
|
86
|
-
|
|
86
|
+
unbindFromRelayPtyOrchestrator(wrapper) {
|
|
87
87
|
const binding = this.boundWrappers.get(wrapper);
|
|
88
88
|
if (!binding)
|
|
89
89
|
return;
|
|
@@ -187,7 +187,7 @@ export class CloudPersistenceService {
|
|
|
187
187
|
*/
|
|
188
188
|
destroy() {
|
|
189
189
|
for (const wrapper of this.boundWrappers.keys()) {
|
|
190
|
-
this.
|
|
190
|
+
this.unbindFromRelayPtyOrchestrator(wrapper);
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
193
|
}
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
* Manages agents across workspaces with integrated resiliency.
|
|
4
4
|
*/
|
|
5
5
|
import { EventEmitter } from 'events';
|
|
6
|
-
import {
|
|
6
|
+
import { RelayPtyOrchestrator } from '../wrapper/relay-pty-orchestrator.js';
|
|
7
|
+
import type { SummaryEvent, SessionEndEvent } from '../wrapper/pty-wrapper.js';
|
|
7
8
|
import type { Agent, SpawnAgentRequest } from './types.js';
|
|
8
9
|
/**
|
|
9
10
|
* Optional cloud persistence handler.
|
|
10
|
-
* When set, agent-manager forwards
|
|
11
|
+
* When set, agent-manager forwards wrapper events to this handler.
|
|
11
12
|
*/
|
|
12
13
|
export interface CloudPersistenceHandler {
|
|
13
14
|
onSummary: (agentId: string, event: SummaryEvent) => Promise<void>;
|
|
@@ -16,7 +17,7 @@ export interface CloudPersistenceHandler {
|
|
|
16
17
|
destroy?: () => void;
|
|
17
18
|
}
|
|
18
19
|
interface ManagedAgent extends Agent {
|
|
19
|
-
pty?:
|
|
20
|
+
pty?: RelayPtyOrchestrator;
|
|
20
21
|
}
|
|
21
22
|
export declare class AgentManager extends EventEmitter {
|
|
22
23
|
private agents;
|
|
@@ -26,7 +27,7 @@ export declare class AgentManager extends EventEmitter {
|
|
|
26
27
|
private cloudPersistence?;
|
|
27
28
|
constructor(dataDir: string);
|
|
28
29
|
/**
|
|
29
|
-
* Set cloud persistence handler for forwarding
|
|
30
|
+
* Set cloud persistence handler for forwarding RelayPtyOrchestrator events.
|
|
30
31
|
* When set, 'summary' and 'session-end' events from agents are forwarded
|
|
31
32
|
* to the handler for cloud persistence (PostgreSQL/Redis).
|
|
32
33
|
*/
|
|
@@ -99,7 +100,7 @@ export declare class AgentManager extends EventEmitter {
|
|
|
99
100
|
*/
|
|
100
101
|
private handleAgentExit;
|
|
101
102
|
/**
|
|
102
|
-
* Bind
|
|
103
|
+
* Bind RelayPtyOrchestrator events to cloud persistence and daemon events.
|
|
103
104
|
*
|
|
104
105
|
* Events bound:
|
|
105
106
|
* - 'summary': Agent output a [[SUMMARY]] block
|
|
@@ -8,7 +8,7 @@ import { EventEmitter } from 'events';
|
|
|
8
8
|
import { createLogger } from '../resiliency/logger.js';
|
|
9
9
|
import { getSupervisor } from '../resiliency/supervisor.js';
|
|
10
10
|
import { detectProvider } from '../resiliency/provider-context.js';
|
|
11
|
-
import {
|
|
11
|
+
import { RelayPtyOrchestrator } from '../wrapper/relay-pty-orchestrator.js';
|
|
12
12
|
import { resolveCommand } from '../utils/command-resolver.js';
|
|
13
13
|
const logger = createLogger('agent-manager');
|
|
14
14
|
function generateId() {
|
|
@@ -42,7 +42,7 @@ export class AgentManager extends EventEmitter {
|
|
|
42
42
|
logger.info('Agent manager initialized');
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
45
|
-
* Set cloud persistence handler for forwarding
|
|
45
|
+
* Set cloud persistence handler for forwarding RelayPtyOrchestrator events.
|
|
46
46
|
* When set, 'summary' and 'session-end' events from agents are forwarded
|
|
47
47
|
* to the handler for cloud persistence (PostgreSQL/Redis).
|
|
48
48
|
*/
|
|
@@ -96,7 +96,9 @@ export class AgentManager extends EventEmitter {
|
|
|
96
96
|
command,
|
|
97
97
|
args,
|
|
98
98
|
cwd: workspacePath,
|
|
99
|
-
|
|
99
|
+
streamLogs: true,
|
|
100
|
+
// Skip continuity for cloud-managed agents
|
|
101
|
+
skipContinuity: true,
|
|
100
102
|
env: {
|
|
101
103
|
CLOUD_API_URL: process.env.CLOUD_API_URL || '',
|
|
102
104
|
WORKSPACE_TOKEN: process.env.WORKSPACE_TOKEN || '',
|
|
@@ -109,11 +111,11 @@ export class AgentManager extends EventEmitter {
|
|
|
109
111
|
},
|
|
110
112
|
};
|
|
111
113
|
// Create and start PTY
|
|
112
|
-
const pty = new
|
|
114
|
+
const pty = new RelayPtyOrchestrator(ptyConfig);
|
|
113
115
|
await pty.start();
|
|
114
116
|
agent.pid = pty.pid;
|
|
115
117
|
agent.pty = pty;
|
|
116
|
-
// Subscribe to
|
|
118
|
+
// Subscribe to RelayPtyOrchestrator events for cloud persistence
|
|
117
119
|
this.bindPtyEvents(agent.id, pty);
|
|
118
120
|
// Inject initial task
|
|
119
121
|
if (task && task.trim()) {
|
|
@@ -340,7 +342,9 @@ export class AgentManager extends EventEmitter {
|
|
|
340
342
|
command,
|
|
341
343
|
args,
|
|
342
344
|
cwd: workspacePath,
|
|
343
|
-
|
|
345
|
+
streamLogs: true,
|
|
346
|
+
// Skip continuity for cloud-managed agents
|
|
347
|
+
skipContinuity: true,
|
|
344
348
|
env: {
|
|
345
349
|
CLOUD_API_URL: process.env.CLOUD_API_URL || '',
|
|
346
350
|
WORKSPACE_TOKEN: process.env.WORKSPACE_TOKEN || '',
|
|
@@ -351,7 +355,7 @@ export class AgentManager extends EventEmitter {
|
|
|
351
355
|
this.handleAgentExit(agent.id, code);
|
|
352
356
|
},
|
|
353
357
|
};
|
|
354
|
-
const pty = new
|
|
358
|
+
const pty = new RelayPtyOrchestrator(ptyConfig);
|
|
355
359
|
await pty.start();
|
|
356
360
|
agent.pid = pty.pid;
|
|
357
361
|
agent.pty = pty;
|
|
@@ -403,7 +407,7 @@ export class AgentManager extends EventEmitter {
|
|
|
403
407
|
}
|
|
404
408
|
}
|
|
405
409
|
/**
|
|
406
|
-
* Bind
|
|
410
|
+
* Bind RelayPtyOrchestrator events to cloud persistence and daemon events.
|
|
407
411
|
*
|
|
408
412
|
* Events bound:
|
|
409
413
|
* - 'summary': Agent output a [[SUMMARY]] block
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export interface ChannelMembershipRecord {
|
|
2
|
+
channel: string;
|
|
3
|
+
member: string;
|
|
4
|
+
}
|
|
5
|
+
export interface ChannelMembershipStore {
|
|
6
|
+
loadMemberships(): Promise<ChannelMembershipRecord[]>;
|
|
7
|
+
addMember(channel: string, member: string): Promise<void>;
|
|
8
|
+
removeMember(channel: string, member: string): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export interface CloudChannelMembershipStoreOptions {
|
|
11
|
+
workspaceId: string;
|
|
12
|
+
databaseUrl: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Cloud-backed membership store that uses the channel_members table in Postgres.
|
|
16
|
+
* This is used by the daemon when running in a cloud workspace so membership
|
|
17
|
+
* survives restarts and is shared across processes.
|
|
18
|
+
*/
|
|
19
|
+
export declare class CloudChannelMembershipStore implements ChannelMembershipStore {
|
|
20
|
+
private workspaceId;
|
|
21
|
+
private pool;
|
|
22
|
+
constructor(options: CloudChannelMembershipStoreOptions);
|
|
23
|
+
/**
|
|
24
|
+
* Load all memberships for the workspace from Postgres.
|
|
25
|
+
*/
|
|
26
|
+
loadMemberships(): Promise<ChannelMembershipRecord[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Add a member to a channel in Postgres (no-op if already present).
|
|
29
|
+
*/
|
|
30
|
+
addMember(channel: string, member: string): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Remove a member from a channel in Postgres.
|
|
33
|
+
*/
|
|
34
|
+
removeMember(channel: string, member: string): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Normalize channel name for DB lookups (strip leading '#' and ignore DMs).
|
|
37
|
+
*/
|
|
38
|
+
private normalizeChannelId;
|
|
39
|
+
/**
|
|
40
|
+
* Convert DB channel_id to router/channel format (prepend '#').
|
|
41
|
+
*/
|
|
42
|
+
private formatChannelId;
|
|
43
|
+
/**
|
|
44
|
+
* Look up the channel row ID for a workspace/channel_id combination.
|
|
45
|
+
*/
|
|
46
|
+
private getChannelRowId;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=channel-membership-store.d.ts.map
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { Pool } from 'pg';
|
|
2
|
+
import { createLogger } from '../utils/logger.js';
|
|
3
|
+
const log = createLogger('channel-membership-store');
|
|
4
|
+
/**
|
|
5
|
+
* Cloud-backed membership store that uses the channel_members table in Postgres.
|
|
6
|
+
* This is used by the daemon when running in a cloud workspace so membership
|
|
7
|
+
* survives restarts and is shared across processes.
|
|
8
|
+
*/
|
|
9
|
+
export class CloudChannelMembershipStore {
|
|
10
|
+
workspaceId;
|
|
11
|
+
pool;
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.workspaceId = options.workspaceId;
|
|
14
|
+
this.pool = new Pool({
|
|
15
|
+
connectionString: options.databaseUrl,
|
|
16
|
+
ssl: options.databaseUrl.includes('sslmode=require')
|
|
17
|
+
? { rejectUnauthorized: false }
|
|
18
|
+
: undefined,
|
|
19
|
+
max: 5,
|
|
20
|
+
idleTimeoutMillis: 30_000,
|
|
21
|
+
connectionTimeoutMillis: 10_000,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Load all memberships for the workspace from Postgres.
|
|
26
|
+
*/
|
|
27
|
+
async loadMemberships() {
|
|
28
|
+
try {
|
|
29
|
+
const result = await this.pool.query(`
|
|
30
|
+
SELECT c.channel_id AS channel_id, cm.member_id AS member_id
|
|
31
|
+
FROM channel_members cm
|
|
32
|
+
INNER JOIN channels c ON cm.channel_id = c.id
|
|
33
|
+
WHERE c.workspace_id = $1 AND c.status != 'archived'
|
|
34
|
+
`, [this.workspaceId]);
|
|
35
|
+
return result.rows
|
|
36
|
+
.map((row) => ({
|
|
37
|
+
channel: this.formatChannelId(row.channel_id),
|
|
38
|
+
member: row.member_id,
|
|
39
|
+
}))
|
|
40
|
+
.filter((row) => Boolean(row.channel && row.member));
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
log.error('Failed to load channel memberships from cloud DB', {
|
|
44
|
+
error: err instanceof Error ? err.message : String(err),
|
|
45
|
+
});
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Add a member to a channel in Postgres (no-op if already present).
|
|
51
|
+
*/
|
|
52
|
+
async addMember(channel, member) {
|
|
53
|
+
const normalized = this.normalizeChannelId(channel);
|
|
54
|
+
if (!normalized) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const channelRowId = await this.getChannelRowId(normalized);
|
|
58
|
+
if (!channelRowId) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
await this.pool.query(`
|
|
63
|
+
INSERT INTO channel_members (channel_id, member_id, member_type, role)
|
|
64
|
+
VALUES ($1, $2, 'agent', 'member')
|
|
65
|
+
ON CONFLICT (channel_id, member_id) DO NOTHING
|
|
66
|
+
`, [channelRowId, member]);
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
log.error('Failed to add channel member in cloud DB', {
|
|
70
|
+
channel: normalized,
|
|
71
|
+
member,
|
|
72
|
+
error: err instanceof Error ? err.message : String(err),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Remove a member from a channel in Postgres.
|
|
78
|
+
*/
|
|
79
|
+
async removeMember(channel, member) {
|
|
80
|
+
const normalized = this.normalizeChannelId(channel);
|
|
81
|
+
if (!normalized) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const channelRowId = await this.getChannelRowId(normalized);
|
|
85
|
+
if (!channelRowId) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
await this.pool.query('DELETE FROM channel_members WHERE channel_id = $1 AND member_id = $2', [channelRowId, member]);
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
log.error('Failed to remove channel member in cloud DB', {
|
|
93
|
+
channel: normalized,
|
|
94
|
+
member,
|
|
95
|
+
error: err instanceof Error ? err.message : String(err),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Normalize channel name for DB lookups (strip leading '#' and ignore DMs).
|
|
101
|
+
*/
|
|
102
|
+
normalizeChannelId(channel) {
|
|
103
|
+
if (!channel)
|
|
104
|
+
return null;
|
|
105
|
+
if (channel.startsWith('dm:')) {
|
|
106
|
+
return null; // DM channels are not stored in channel_members
|
|
107
|
+
}
|
|
108
|
+
return channel.startsWith('#') ? channel.slice(1) : channel;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Convert DB channel_id to router/channel format (prepend '#').
|
|
112
|
+
*/
|
|
113
|
+
formatChannelId(channelId) {
|
|
114
|
+
if (!channelId)
|
|
115
|
+
return '';
|
|
116
|
+
if (channelId.startsWith('#') || channelId.startsWith('dm:')) {
|
|
117
|
+
return channelId;
|
|
118
|
+
}
|
|
119
|
+
return `#${channelId}`;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Look up the channel row ID for a workspace/channel_id combination.
|
|
123
|
+
*/
|
|
124
|
+
async getChannelRowId(channelId) {
|
|
125
|
+
try {
|
|
126
|
+
const result = await this.pool.query(`
|
|
127
|
+
SELECT id FROM channels
|
|
128
|
+
WHERE workspace_id = $1 AND channel_id = $2
|
|
129
|
+
LIMIT 1
|
|
130
|
+
`, [this.workspaceId, channelId]);
|
|
131
|
+
if (!result.rows[0]?.id) {
|
|
132
|
+
log.warn('Channel not found in cloud DB for membership update', {
|
|
133
|
+
workspaceId: this.workspaceId,
|
|
134
|
+
channelId,
|
|
135
|
+
});
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
return result.rows[0].id;
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
log.error('Failed to look up channel row in cloud DB', {
|
|
142
|
+
channelId,
|
|
143
|
+
error: err instanceof Error ? err.message : String(err),
|
|
144
|
+
});
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=channel-membership-store.js.map
|
|
@@ -175,6 +175,8 @@ export class CloudSyncService extends EventEmitter {
|
|
|
175
175
|
const agents = Array.from(this.localAgents.entries()).map(([name, info]) => ({
|
|
176
176
|
name,
|
|
177
177
|
status: info.status,
|
|
178
|
+
isHuman: info.isHuman,
|
|
179
|
+
avatarUrl: info.avatarUrl,
|
|
178
180
|
}));
|
|
179
181
|
const response = await fetch(`${this.config.cloudUrl}/api/daemons/heartbeat`, {
|
|
180
182
|
method: 'POST',
|
|
@@ -224,6 +226,8 @@ export class CloudSyncService extends EventEmitter {
|
|
|
224
226
|
const agents = Array.from(this.localAgents.entries()).map(([name, info]) => ({
|
|
225
227
|
name,
|
|
226
228
|
status: info.status,
|
|
229
|
+
isHuman: info.isHuman,
|
|
230
|
+
avatarUrl: info.avatarUrl,
|
|
227
231
|
}));
|
|
228
232
|
const response = await fetch(`${this.config.cloudUrl}/api/daemons/agents`, {
|
|
229
233
|
method: 'POST',
|
|
@@ -300,7 +300,8 @@ export class Connection {
|
|
|
300
300
|
* Returns false if the connection is closed or the queue is full.
|
|
301
301
|
*/
|
|
302
302
|
send(envelope) {
|
|
303
|
-
if (this._state === 'CLOSED' || this._state === 'ERROR') {
|
|
303
|
+
if (this._state === 'CLOSED' || this._state === 'ERROR' || this._state === 'CLOSING') {
|
|
304
|
+
console.log(`[connection] Send to ${this._agentName} blocked - state: ${this._state}`);
|
|
304
305
|
return false;
|
|
305
306
|
}
|
|
306
307
|
const maxQueueSize = this.config.maxWriteQueueSize ?? 2000;
|
|
@@ -343,7 +344,7 @@ export class Connection {
|
|
|
343
344
|
*/
|
|
344
345
|
drain() {
|
|
345
346
|
while (this.writeQueue.length > 0) {
|
|
346
|
-
if (this._state === 'CLOSED' || this._state === 'ERROR') {
|
|
347
|
+
if (this._state === 'CLOSED' || this._state === 'ERROR' || this._state === 'CLOSING') {
|
|
347
348
|
this.draining = false;
|
|
348
349
|
return;
|
|
349
350
|
}
|
|
@@ -417,13 +418,20 @@ export class Connection {
|
|
|
417
418
|
if (this._state === 'CLOSED' || this._state === 'CLOSING')
|
|
418
419
|
return;
|
|
419
420
|
this._state = 'CLOSING';
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
421
|
+
// Write BYE message directly (not via queue) to avoid race with socket.end()
|
|
422
|
+
try {
|
|
423
|
+
const byeFrame = encodeFrame({
|
|
424
|
+
v: PROTOCOL_VERSION,
|
|
425
|
+
type: 'BYE',
|
|
426
|
+
id: generateId(),
|
|
427
|
+
ts: Date.now(),
|
|
428
|
+
payload: {},
|
|
429
|
+
});
|
|
430
|
+
this.socket.write(byeFrame);
|
|
431
|
+
}
|
|
432
|
+
catch {
|
|
433
|
+
// Ignore write errors during close
|
|
434
|
+
}
|
|
427
435
|
this.socket.end();
|
|
428
436
|
}
|
|
429
437
|
}
|
package/dist/daemon/router.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type { StorageAdapter } from '../storage/adapter.js';
|
|
|
8
8
|
import type { AgentRegistry } from './agent-registry.js';
|
|
9
9
|
import { type RateLimitConfig } from './rate-limiter.js';
|
|
10
10
|
import { type DeliveryReliabilityOptions } from './delivery-tracker.js';
|
|
11
|
+
import type { ChannelMembershipStore } from './channel-membership-store.js';
|
|
11
12
|
export interface RoutableConnection {
|
|
12
13
|
id: string;
|
|
13
14
|
agentName?: string;
|
|
@@ -40,6 +41,7 @@ interface ShadowRelationship extends ShadowConfig {
|
|
|
40
41
|
}
|
|
41
42
|
export declare class Router {
|
|
42
43
|
private storage?;
|
|
44
|
+
private channelMembershipStore?;
|
|
43
45
|
private connections;
|
|
44
46
|
private agents;
|
|
45
47
|
private subscriptions;
|
|
@@ -71,7 +73,12 @@ export declare class Router {
|
|
|
71
73
|
crossMachineHandler?: CrossMachineHandler;
|
|
72
74
|
/** Rate limit configuration. Set to null to disable rate limiting. */
|
|
73
75
|
rateLimit?: Partial<RateLimitConfig> | null;
|
|
76
|
+
channelMembershipStore?: ChannelMembershipStore;
|
|
74
77
|
});
|
|
78
|
+
/**
|
|
79
|
+
* Restore channel memberships from persisted storage.
|
|
80
|
+
*/
|
|
81
|
+
restoreChannelMemberships(): Promise<void>;
|
|
75
82
|
/**
|
|
76
83
|
* Set or update the cross-machine handler.
|
|
77
84
|
*/
|
|
@@ -229,11 +236,14 @@ export declare class Router {
|
|
|
229
236
|
/**
|
|
230
237
|
* Handle a CHANNEL_JOIN message.
|
|
231
238
|
* Adds the member to the channel and notifies existing members.
|
|
239
|
+
* If payload.member is set, adds that member (admin mode).
|
|
240
|
+
* Otherwise, adds the connection's agent name.
|
|
232
241
|
*/
|
|
233
242
|
handleChannelJoin(connection: RoutableConnection, envelope: Envelope<ChannelJoinPayload>): void;
|
|
234
243
|
/**
|
|
235
244
|
* Handle a CHANNEL_LEAVE message.
|
|
236
245
|
* Removes the member from the channel and notifies remaining members.
|
|
246
|
+
* If payload.member is provided, removes that member instead (admin mode).
|
|
237
247
|
*/
|
|
238
248
|
handleChannelLeave(connection: RoutableConnection, envelope: Envelope<ChannelLeavePayload>): void;
|
|
239
249
|
/**
|
|
@@ -244,6 +254,7 @@ export declare class Router {
|
|
|
244
254
|
* Persist a channel message to storage.
|
|
245
255
|
*/
|
|
246
256
|
private persistChannelMessage;
|
|
257
|
+
private persistChannelMembership;
|
|
247
258
|
/**
|
|
248
259
|
* Get all members of a channel.
|
|
249
260
|
*/
|
|
@@ -270,8 +281,34 @@ export declare class Router {
|
|
|
270
281
|
getUsers(): string[];
|
|
271
282
|
/**
|
|
272
283
|
* Get a connection by name (checks both agents and users).
|
|
284
|
+
* Uses case-insensitive lookup to handle mismatched casing.
|
|
273
285
|
*/
|
|
274
286
|
private getConnectionByName;
|
|
287
|
+
/**
|
|
288
|
+
* Check if a member is in a Set (case-insensitive).
|
|
289
|
+
* Returns the actual stored name if found, undefined otherwise.
|
|
290
|
+
*/
|
|
291
|
+
private findMemberInSet;
|
|
292
|
+
/**
|
|
293
|
+
* Check if two names match (case-insensitive).
|
|
294
|
+
*/
|
|
295
|
+
private namesMatch;
|
|
296
|
+
/**
|
|
297
|
+
* Auto-join a member to a channel without notifications.
|
|
298
|
+
* Used for default channel membership (e.g., #general).
|
|
299
|
+
* @param memberName - The agent or user name to add
|
|
300
|
+
* @param channel - The channel to join (e.g., '#general')
|
|
301
|
+
*/
|
|
302
|
+
autoJoinChannel(memberName: string, channel: string, options?: {
|
|
303
|
+
persist?: boolean;
|
|
304
|
+
}): void;
|
|
305
|
+
private addChannelMember;
|
|
306
|
+
private removeChannelMember;
|
|
307
|
+
handleMembershipUpdate(update: {
|
|
308
|
+
channel: string;
|
|
309
|
+
member: string;
|
|
310
|
+
action: 'join' | 'leave' | 'invite';
|
|
311
|
+
}): void;
|
|
275
312
|
}
|
|
276
313
|
export {};
|
|
277
314
|
//# sourceMappingURL=router.d.ts.map
|