agent-relay 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +3 -0
- package/.nvmrc +1 -0
- package/.trajectories/agent-relay-322-324.md +17 -0
- package/.trajectories/completed/2026-01/traj_03zupyv1s7b9.json +49 -0
- package/.trajectories/completed/2026-01/traj_03zupyv1s7b9.md +31 -0
- package/.trajectories/completed/2026-01/traj_0zacdjl1g4ht.json +125 -0
- package/.trajectories/completed/2026-01/traj_0zacdjl1g4ht.md +62 -0
- package/.trajectories/completed/2026-01/traj_1dviorhnkcb5.json +65 -0
- package/.trajectories/completed/2026-01/traj_1dviorhnkcb5.md +37 -0
- package/.trajectories/completed/2026-01/traj_1k5if5snst2e.json +65 -0
- package/.trajectories/completed/2026-01/traj_1k5if5snst2e.md +37 -0
- package/.trajectories/completed/2026-01/traj_1rp3rges5811.json +49 -0
- package/.trajectories/completed/2026-01/traj_1rp3rges5811.md +31 -0
- package/.trajectories/completed/2026-01/traj_22bhyulruouw.json +113 -0
- package/.trajectories/completed/2026-01/traj_22bhyulruouw.md +57 -0
- package/.trajectories/completed/2026-01/traj_2dao7ddgnta0.json +53 -0
- package/.trajectories/completed/2026-01/traj_2dao7ddgnta0.md +32 -0
- package/.trajectories/completed/2026-01/traj_33iuy72sezbk.json +49 -0
- package/.trajectories/completed/2026-01/traj_33iuy72sezbk.md +31 -0
- package/.trajectories/completed/2026-01/traj_3t0440mjeunc.json +26 -0
- package/.trajectories/completed/2026-01/traj_3t0440mjeunc.md +6 -0
- package/.trajectories/completed/2026-01/traj_45x9494d9xnr.json +47 -0
- package/.trajectories/completed/2026-01/traj_45x9494d9xnr.md +32 -0
- package/.trajectories/completed/2026-01/traj_4aa0bb77s4nh.json +53 -0
- package/.trajectories/completed/2026-01/traj_4aa0bb77s4nh.md +32 -0
- package/.trajectories/completed/2026-01/traj_5ammh5qtvklq.json +77 -0
- package/.trajectories/completed/2026-01/traj_5ammh5qtvklq.md +42 -0
- package/.trajectories/completed/2026-01/traj_5lhmzq8rxpqv.json +59 -0
- package/.trajectories/completed/2026-01/traj_5lhmzq8rxpqv.md +33 -0
- package/.trajectories/completed/2026-01/traj_5vr4e9erb1fs.json +53 -0
- package/.trajectories/completed/2026-01/traj_5vr4e9erb1fs.md +32 -0
- package/.trajectories/completed/2026-01/traj_6fgiwdoklvym.json +48 -0
- package/.trajectories/completed/2026-01/traj_6fgiwdoklvym.md +24 -0
- package/.trajectories/completed/2026-01/traj_6mieijqyvaag.json +77 -0
- package/.trajectories/completed/2026-01/traj_6mieijqyvaag.md +42 -0
- package/.trajectories/completed/2026-01/traj_78ffm31jn3uk.json +77 -0
- package/.trajectories/completed/2026-01/traj_78ffm31jn3uk.md +42 -0
- package/.trajectories/completed/2026-01/traj_7ludwvz45veh.json +209 -0
- package/.trajectories/completed/2026-01/traj_7ludwvz45veh.md +97 -0
- package/.trajectories/completed/2026-01/traj_94gnp3k30goq.json +66 -0
- package/.trajectories/completed/2026-01/traj_94gnp3k30goq.md +36 -0
- package/.trajectories/completed/2026-01/traj_9921cuhel0pj.json +48 -0
- package/.trajectories/completed/2026-01/traj_9921cuhel0pj.md +24 -0
- package/.trajectories/completed/2026-01/traj_ajs7zqfux4wc.json +49 -0
- package/.trajectories/completed/2026-01/traj_ajs7zqfux4wc.md +23 -0
- package/.trajectories/completed/2026-01/traj_avqeghu6pz5a.json +40 -0
- package/.trajectories/completed/2026-01/traj_avqeghu6pz5a.md +22 -0
- package/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.json +53 -0
- package/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.md +32 -0
- package/.trajectories/completed/2026-01/traj_cxofprm2m2en.json +49 -0
- package/.trajectories/completed/2026-01/traj_cxofprm2m2en.md +31 -0
- package/.trajectories/completed/2026-01/traj_d2hhz3k0vrhn.json +26 -0
- package/.trajectories/completed/2026-01/traj_d2hhz3k0vrhn.md +6 -0
- package/.trajectories/completed/2026-01/traj_dcsp9s8y01ra.json +121 -0
- package/.trajectories/completed/2026-01/traj_dcsp9s8y01ra.md +29 -0
- package/.trajectories/completed/2026-01/traj_dfuvww9pege5.json +59 -0
- package/.trajectories/completed/2026-01/traj_dfuvww9pege5.md +37 -0
- package/.trajectories/completed/2026-01/traj_fhx9irlckht6.json +53 -0
- package/.trajectories/completed/2026-01/traj_fhx9irlckht6.md +32 -0
- package/.trajectories/completed/2026-01/traj_fqduidx3xbtp.json +101 -0
- package/.trajectories/completed/2026-01/traj_fqduidx3xbtp.md +52 -0
- package/.trajectories/completed/2026-01/traj_g0fisy9h51mf.json +77 -0
- package/.trajectories/completed/2026-01/traj_g0fisy9h51mf.md +42 -0
- package/.trajectories/completed/2026-01/traj_gjdre5voouod.json +53 -0
- package/.trajectories/completed/2026-01/traj_gjdre5voouod.md +32 -0
- package/.trajectories/completed/2026-01/traj_gtlyqtta3x8l.json +25 -0
- package/.trajectories/completed/2026-01/traj_gtlyqtta3x8l.md +15 -0
- package/.trajectories/completed/2026-01/traj_h4xijiuip3w4.json +101 -0
- package/.trajectories/completed/2026-01/traj_h4xijiuip3w4.md +44 -0
- package/.trajectories/completed/2026-01/traj_hf81ey93uz6t.json +49 -0
- package/.trajectories/completed/2026-01/traj_hf81ey93uz6t.md +31 -0
- package/.trajectories/completed/2026-01/traj_hfmki2jr9d4r.json +65 -0
- package/.trajectories/completed/2026-01/traj_hfmki2jr9d4r.md +37 -0
- package/.trajectories/completed/2026-01/traj_hhxte7w4gjjx.json +22 -0
- package/.trajectories/completed/2026-01/traj_hhxte7w4gjjx.md +5 -0
- package/.trajectories/completed/2026-01/traj_hpungyhoj6v5.json +53 -0
- package/.trajectories/completed/2026-01/traj_hpungyhoj6v5.md +32 -0
- package/.trajectories/completed/2026-01/traj_lq450ly148uw.json +49 -0
- package/.trajectories/completed/2026-01/traj_lq450ly148uw.md +31 -0
- package/.trajectories/completed/2026-01/traj_m2xkjv0w2sq7.json +25 -0
- package/.trajectories/completed/2026-01/traj_m2xkjv0w2sq7.md +15 -0
- package/.trajectories/completed/2026-01/traj_multi_server_arch.md +101 -0
- package/.trajectories/completed/2026-01/traj_noq5zbvnrdvz.json +53 -0
- package/.trajectories/completed/2026-01/traj_noq5zbvnrdvz.md +32 -0
- package/.trajectories/completed/2026-01/traj_ntbs6ppopf46.json +53 -0
- package/.trajectories/completed/2026-01/traj_ntbs6ppopf46.md +32 -0
- package/.trajectories/completed/2026-01/traj_ozd98si6a7ns.json +48 -0
- package/.trajectories/completed/2026-01/traj_ozd98si6a7ns.md +24 -0
- package/.trajectories/completed/2026-01/traj_prdza7a5cxp5.json +53 -0
- package/.trajectories/completed/2026-01/traj_prdza7a5cxp5.md +32 -0
- package/.trajectories/completed/2026-01/traj_psd9ob0j2ru3.json +27 -0
- package/.trajectories/completed/2026-01/traj_psd9ob0j2ru3.md +14 -0
- package/.trajectories/completed/2026-01/traj_qb3twvvywfwi.json +77 -0
- package/.trajectories/completed/2026-01/traj_qb3twvvywfwi.md +42 -0
- package/.trajectories/completed/2026-01/traj_qft54mi7nfor.json +53 -0
- package/.trajectories/completed/2026-01/traj_qft54mi7nfor.md +32 -0
- package/.trajectories/completed/2026-01/traj_qx9uhf8whhxo.json +83 -0
- package/.trajectories/completed/2026-01/traj_qx9uhf8whhxo.md +47 -0
- package/.trajectories/completed/2026-01/traj_rd9toccj18a0.json +59 -0
- package/.trajectories/completed/2026-01/traj_rd9toccj18a0.md +37 -0
- package/.trajectories/completed/2026-01/traj_rt4fiw3ecp50.json +48 -0
- package/.trajectories/completed/2026-01/traj_rt4fiw3ecp50.md +16 -0
- package/.trajectories/completed/2026-01/traj_st8j35b0hrlc.json +59 -0
- package/.trajectories/completed/2026-01/traj_st8j35b0hrlc.md +37 -0
- package/.trajectories/completed/2026-01/traj_t1yy8m7hbuxp.json +53 -0
- package/.trajectories/completed/2026-01/traj_t1yy8m7hbuxp.md +32 -0
- package/.trajectories/completed/2026-01/traj_tmux_orchestrator_analysis.json +84 -0
- package/.trajectories/completed/2026-01/traj_tmux_orchestrator_analysis.md +109 -0
- package/.trajectories/completed/2026-01/traj_u9n9eqasw16k.json +53 -0
- package/.trajectories/completed/2026-01/traj_u9n9eqasw16k.md +32 -0
- package/.trajectories/completed/2026-01/traj_ub8csuv3lcv4.json +53 -0
- package/.trajectories/completed/2026-01/traj_ub8csuv3lcv4.md +32 -0
- package/.trajectories/completed/2026-01/traj_uc29tlso8i9s.json +186 -0
- package/.trajectories/completed/2026-01/traj_uc29tlso8i9s.md +86 -0
- package/.trajectories/completed/2026-01/traj_ui9b4tqxoa7j.json +77 -0
- package/.trajectories/completed/2026-01/traj_ui9b4tqxoa7j.md +42 -0
- package/.trajectories/completed/2026-01/traj_v87hypnongqx.json +71 -0
- package/.trajectories/completed/2026-01/traj_v87hypnongqx.md +42 -0
- package/.trajectories/completed/2026-01/traj_v9dkdoxylyid.json +89 -0
- package/.trajectories/completed/2026-01/traj_v9dkdoxylyid.md +47 -0
- package/.trajectories/completed/2026-01/traj_wkp2fgzdyinb.json +53 -0
- package/.trajectories/completed/2026-01/traj_wkp2fgzdyinb.md +32 -0
- package/.trajectories/completed/2026-01/traj_x14t8w8rn7xg.json +20 -0
- package/.trajectories/completed/2026-01/traj_x14t8w8rn7xg.md +6 -0
- package/.trajectories/completed/2026-01/traj_xnwbznkvv8ua.json +175 -0
- package/.trajectories/completed/2026-01/traj_xnwbznkvv8ua.md +82 -0
- package/.trajectories/completed/2026-01/traj_xy9vifpqet80.json +65 -0
- package/.trajectories/completed/2026-01/traj_xy9vifpqet80.md +37 -0
- package/.trajectories/completed/2026-01/traj_y7aiwijyfmmv.json +49 -0
- package/.trajectories/completed/2026-01/traj_y7aiwijyfmmv.md +31 -0
- package/.trajectories/completed/2026-01/traj_ysjc8zaeqtd3.json +47 -0
- package/.trajectories/completed/2026-01/traj_ysjc8zaeqtd3.md +32 -0
- package/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.json +59 -0
- package/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.md +37 -0
- package/.trajectories/completed/2026-01/traj_z0vcw1wrzide.json +53 -0
- package/.trajectories/completed/2026-01/traj_z0vcw1wrzide.md +32 -0
- package/.trajectories/consolidate-settings-panel.md +24 -0
- package/.trajectories/gh-cli-user-token.md +26 -0
- package/.trajectories/index.json +468 -0
- package/ARCHITECTURE.md +1245 -0
- package/TESTING.md +278 -0
- package/deploy/init-db.sql +5 -0
- package/deploy/scripts/setup-fly-workspaces.sh +69 -0
- package/deploy/scripts/setup-railway.sh +75 -0
- package/deploy/workspace/codex.config.toml +15 -0
- package/deploy/workspace/entrypoint-browser.sh +118 -0
- package/deploy/workspace/entrypoint.sh +508 -0
- package/deploy/workspace/git-credential-relay +126 -0
- package/dist/bridge/spawner.d.ts +7 -0
- package/dist/bridge/spawner.js +40 -9
- package/dist/bridge/types.d.ts +2 -0
- package/dist/cli/index.js +260 -1
- package/dist/cloud/api/admin.d.ts +8 -0
- package/dist/cloud/api/admin.js +212 -0
- package/dist/cloud/api/auth.js +8 -0
- package/dist/cloud/api/billing.d.ts +0 -10
- package/dist/cloud/api/billing.js +278 -67
- package/dist/cloud/api/codex-auth-helper.d.ts +21 -0
- package/dist/cloud/api/codex-auth-helper.js +307 -0
- package/dist/cloud/api/coordinators.js +402 -0
- package/dist/cloud/api/daemons.js +15 -11
- package/dist/cloud/api/git.js +127 -19
- package/dist/cloud/api/github-app.js +42 -8
- package/dist/cloud/api/nango-auth.js +297 -16
- package/dist/cloud/api/onboarding.js +112 -35
- package/dist/cloud/api/providers.js +12 -16
- package/dist/cloud/api/repos.d.ts +1 -0
- package/dist/cloud/api/repos.js +311 -49
- package/dist/cloud/api/test-helpers.js +40 -0
- package/dist/cloud/api/usage.js +13 -0
- package/dist/cloud/api/webhooks.d.ts +1 -0
- package/dist/cloud/api/webhooks.js +149 -0
- package/dist/cloud/api/workspaces.d.ts +18 -0
- package/dist/cloud/api/workspaces.js +1042 -21
- package/dist/cloud/billing/plans.js +19 -19
- package/dist/cloud/config.d.ts +8 -0
- package/dist/cloud/config.js +15 -0
- package/dist/cloud/db/drizzle.d.ts +5 -2
- package/dist/cloud/db/drizzle.js +27 -20
- package/dist/cloud/db/schema.d.ts +19 -51
- package/dist/cloud/db/schema.js +5 -4
- package/dist/cloud/index.d.ts +0 -1
- package/dist/cloud/index.js +0 -1
- package/dist/cloud/provisioner/index.d.ts +125 -1
- package/dist/cloud/provisioner/index.js +939 -53
- package/dist/cloud/server.js +161 -16
- package/dist/cloud/services/compute-enforcement.d.ts +57 -0
- package/dist/cloud/services/compute-enforcement.js +175 -0
- package/dist/cloud/services/index.d.ts +2 -0
- package/dist/cloud/services/index.js +4 -0
- package/dist/cloud/services/intro-expiration.d.ts +55 -0
- package/dist/cloud/services/intro-expiration.js +211 -0
- package/dist/cloud/services/nango.d.ts +74 -0
- package/dist/cloud/services/nango.js +218 -5
- package/dist/cloud/services/planLimits.d.ts +22 -0
- package/dist/cloud/services/planLimits.js +58 -5
- package/dist/cloud/services/ssh-security.d.ts +31 -0
- package/dist/cloud/services/ssh-security.js +63 -0
- package/dist/continuity/manager.d.ts +5 -0
- package/dist/continuity/manager.js +56 -2
- package/dist/daemon/api.d.ts +2 -0
- package/dist/daemon/api.js +214 -5
- package/dist/daemon/cli-auth.d.ts +13 -1
- package/dist/daemon/cli-auth.js +166 -47
- package/dist/daemon/connection.d.ts +7 -1
- package/dist/daemon/connection.js +15 -0
- package/dist/daemon/orchestrator.d.ts +2 -0
- package/dist/daemon/orchestrator.js +26 -0
- package/dist/daemon/repo-manager.d.ts +116 -0
- package/dist/daemon/repo-manager.js +384 -0
- package/dist/daemon/router.d.ts +60 -1
- package/dist/daemon/router.js +281 -20
- package/dist/daemon/user-directory.d.ts +111 -0
- package/dist/daemon/user-directory.js +233 -0
- package/dist/dashboard/out/404.html +1 -1
- package/dist/dashboard/out/_next/static/T1tgCqVWHFIkV7ClEtzD7/_ssgManifest.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/532-bace199897eeab37.js +9 -0
- package/dist/dashboard/out/_next/static/chunks/766-b54f0853794b78c3.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/83-b51836037078006c.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/891-6cd50de1224f70bb.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/899-bb19a9b3d9b39ea6.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/onboarding/page-8939b0fc700f7eca.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/page-5af1b6b439858aa6.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/metrics/page-ac39dc0cc3c26fa7.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/{page-daf87e86f783f980.js → page-4a5938c18a11a654.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/app/providers/page-ac3a6ac433fd6001.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/providers/setup/[provider]/page-09f9caae98a18c09.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/{main-97850e03d723ea8c.js → main-2ee6beb2ae96d210.js} +1 -1
- package/dist/dashboard/out/_next/static/css/85d2af9c7ac74d62.css +1 -0
- package/dist/dashboard/out/_next/static/css/fe4b28883eeff359.css +1 -0
- package/dist/dashboard/out/app/onboarding.html +1 -0
- package/dist/dashboard/out/app/onboarding.txt +7 -0
- package/dist/dashboard/out/app.html +1 -1
- package/dist/dashboard/out/app.txt +3 -3
- package/dist/dashboard/out/apple-icon.png +0 -0
- package/dist/dashboard/out/connect-repos.html +1 -1
- package/dist/dashboard/out/connect-repos.txt +3 -3
- package/dist/dashboard/out/history.html +1 -1
- package/dist/dashboard/out/history.txt +3 -3
- package/dist/dashboard/out/index.html +1 -1
- package/dist/dashboard/out/index.txt +3 -3
- package/dist/dashboard/out/login.html +2 -2
- package/dist/dashboard/out/login.txt +3 -3
- package/dist/dashboard/out/metrics.html +1 -1
- package/dist/dashboard/out/metrics.txt +3 -3
- package/dist/dashboard/out/pricing.html +3 -3
- package/dist/dashboard/out/pricing.txt +3 -3
- package/dist/dashboard/out/providers/setup/claude.html +1 -0
- package/dist/dashboard/out/providers/setup/claude.txt +8 -0
- package/dist/dashboard/out/providers/setup/codex.html +1 -0
- package/dist/dashboard/out/providers/setup/codex.txt +8 -0
- package/dist/dashboard/out/providers.html +1 -1
- package/dist/dashboard/out/providers.txt +3 -3
- package/dist/dashboard/out/signup.html +2 -2
- package/dist/dashboard/out/signup.txt +3 -3
- package/dist/dashboard-server/server.js +316 -12
- package/dist/dashboard-server/user-bridge.d.ts +103 -0
- package/dist/dashboard-server/user-bridge.js +189 -0
- package/dist/protocol/channels.d.ts +205 -0
- package/dist/protocol/channels.js +154 -0
- package/dist/protocol/types.d.ts +13 -1
- package/dist/resiliency/provider-context.js +2 -0
- package/dist/shared/cli-auth-config.d.ts +19 -0
- package/dist/shared/cli-auth-config.js +58 -2
- package/dist/utils/agent-config.js +1 -1
- package/dist/wrapper/auth-detection.d.ts +49 -0
- package/dist/wrapper/auth-detection.js +192 -0
- package/dist/wrapper/base-wrapper.d.ts +153 -0
- package/dist/wrapper/base-wrapper.js +393 -0
- package/dist/wrapper/client.d.ts +7 -1
- package/dist/wrapper/client.js +3 -0
- package/dist/wrapper/index.d.ts +1 -0
- package/dist/wrapper/index.js +4 -3
- package/dist/wrapper/pty-wrapper.d.ts +62 -84
- package/dist/wrapper/pty-wrapper.js +154 -180
- package/dist/wrapper/tmux-wrapper.d.ts +41 -66
- package/dist/wrapper/tmux-wrapper.js +90 -134
- package/package.json +5 -12
- package/scripts/postinstall.js +11 -155
- package/scripts/test-interactive-terminal.sh +248 -0
- package/test-push.txt +1 -0
- package/bin/tmux +0 -0
- package/dist/bridge/config.d.ts.map +0 -1
- package/dist/bridge/config.js.map +0 -1
- package/dist/bridge/index.d.ts.map +0 -1
- package/dist/bridge/index.js.map +0 -1
- package/dist/bridge/multi-project-client.d.ts.map +0 -1
- package/dist/bridge/multi-project-client.js.map +0 -1
- package/dist/bridge/shadow-cli.d.ts.map +0 -1
- package/dist/bridge/shadow-cli.js.map +0 -1
- package/dist/bridge/shadow-config.d.ts.map +0 -1
- package/dist/bridge/shadow-config.js.map +0 -1
- package/dist/bridge/spawner.d.ts.map +0 -1
- package/dist/bridge/spawner.js.map +0 -1
- package/dist/bridge/teams-config.d.ts.map +0 -1
- package/dist/bridge/teams-config.js.map +0 -1
- package/dist/bridge/types.d.ts.map +0 -1
- package/dist/bridge/types.js.map +0 -1
- package/dist/bridge/utils.d.ts.map +0 -1
- package/dist/bridge/utils.js.map +0 -1
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js.map +0 -1
- package/dist/cloud/api/auth.d.ts.map +0 -1
- package/dist/cloud/api/auth.js.map +0 -1
- package/dist/cloud/api/billing.d.ts.map +0 -1
- package/dist/cloud/api/billing.js.map +0 -1
- package/dist/cloud/api/cli-pty-runner.d.ts.map +0 -1
- package/dist/cloud/api/cli-pty-runner.js.map +0 -1
- package/dist/cloud/api/coordinators.d.ts.map +0 -1
- package/dist/cloud/api/coordinators.js.map +0 -1
- package/dist/cloud/api/daemons.d.ts.map +0 -1
- package/dist/cloud/api/daemons.js.map +0 -1
- package/dist/cloud/api/generic-webhooks.d.ts.map +0 -1
- package/dist/cloud/api/generic-webhooks.js.map +0 -1
- package/dist/cloud/api/git.d.ts.map +0 -1
- package/dist/cloud/api/git.js.map +0 -1
- package/dist/cloud/api/github-app.d.ts.map +0 -1
- package/dist/cloud/api/github-app.js.map +0 -1
- package/dist/cloud/api/middleware/planLimits.d.ts.map +0 -1
- package/dist/cloud/api/middleware/planLimits.js.map +0 -1
- package/dist/cloud/api/monitoring.d.ts.map +0 -1
- package/dist/cloud/api/monitoring.js.map +0 -1
- package/dist/cloud/api/nango-auth.d.ts.map +0 -1
- package/dist/cloud/api/nango-auth.js.map +0 -1
- package/dist/cloud/api/onboarding.d.ts.map +0 -1
- package/dist/cloud/api/onboarding.js.map +0 -1
- package/dist/cloud/api/policy.d.ts.map +0 -1
- package/dist/cloud/api/policy.js.map +0 -1
- package/dist/cloud/api/providers.d.ts.map +0 -1
- package/dist/cloud/api/providers.js.map +0 -1
- package/dist/cloud/api/repos.d.ts.map +0 -1
- package/dist/cloud/api/repos.js.map +0 -1
- package/dist/cloud/api/teams.d.ts.map +0 -1
- package/dist/cloud/api/teams.js.map +0 -1
- package/dist/cloud/api/test-helpers.d.ts.map +0 -1
- package/dist/cloud/api/test-helpers.js.map +0 -1
- package/dist/cloud/api/usage.d.ts.map +0 -1
- package/dist/cloud/api/usage.js.map +0 -1
- package/dist/cloud/api/webhooks.d.ts.map +0 -1
- package/dist/cloud/api/webhooks.js.map +0 -1
- package/dist/cloud/api/workspaces.d.ts.map +0 -1
- package/dist/cloud/api/workspaces.js.map +0 -1
- package/dist/cloud/billing/index.d.ts.map +0 -1
- package/dist/cloud/billing/index.js.map +0 -1
- package/dist/cloud/billing/plans.d.ts.map +0 -1
- package/dist/cloud/billing/plans.js.map +0 -1
- package/dist/cloud/billing/service.d.ts.map +0 -1
- package/dist/cloud/billing/service.js.map +0 -1
- package/dist/cloud/billing/types.d.ts.map +0 -1
- package/dist/cloud/billing/types.js.map +0 -1
- package/dist/cloud/config.d.ts.map +0 -1
- package/dist/cloud/config.js.map +0 -1
- package/dist/cloud/db/drizzle.d.ts.map +0 -1
- package/dist/cloud/db/drizzle.js.map +0 -1
- package/dist/cloud/db/index.d.ts.map +0 -1
- package/dist/cloud/db/index.js.map +0 -1
- package/dist/cloud/db/schema.d.ts.map +0 -1
- package/dist/cloud/db/schema.js.map +0 -1
- package/dist/cloud/index.d.ts.map +0 -1
- package/dist/cloud/index.js.map +0 -1
- package/dist/cloud/provisioner/index.d.ts.map +0 -1
- package/dist/cloud/provisioner/index.js.map +0 -1
- package/dist/cloud/server.d.ts.map +0 -1
- package/dist/cloud/server.js.map +0 -1
- package/dist/cloud/services/auto-scaler.d.ts.map +0 -1
- package/dist/cloud/services/auto-scaler.js.map +0 -1
- package/dist/cloud/services/capacity-manager.d.ts.map +0 -1
- package/dist/cloud/services/capacity-manager.js.map +0 -1
- package/dist/cloud/services/ci-agent-spawner.d.ts.map +0 -1
- package/dist/cloud/services/ci-agent-spawner.js.map +0 -1
- package/dist/cloud/services/coordinator.d.ts.map +0 -1
- package/dist/cloud/services/coordinator.js.map +0 -1
- package/dist/cloud/services/index.d.ts.map +0 -1
- package/dist/cloud/services/index.js.map +0 -1
- package/dist/cloud/services/mention-handler.d.ts.map +0 -1
- package/dist/cloud/services/mention-handler.js.map +0 -1
- package/dist/cloud/services/nango.d.ts.map +0 -1
- package/dist/cloud/services/nango.js.map +0 -1
- package/dist/cloud/services/persistence.d.ts.map +0 -1
- package/dist/cloud/services/persistence.js.map +0 -1
- package/dist/cloud/services/planLimits.d.ts.map +0 -1
- package/dist/cloud/services/planLimits.js.map +0 -1
- package/dist/cloud/services/scaling-orchestrator.d.ts.map +0 -1
- package/dist/cloud/services/scaling-orchestrator.js.map +0 -1
- package/dist/cloud/services/scaling-policy.d.ts.map +0 -1
- package/dist/cloud/services/scaling-policy.js.map +0 -1
- package/dist/cloud/vault/index.d.ts +0 -76
- package/dist/cloud/vault/index.d.ts.map +0 -1
- package/dist/cloud/vault/index.js +0 -219
- package/dist/cloud/vault/index.js.map +0 -1
- package/dist/cloud/webhooks/index.d.ts.map +0 -1
- package/dist/cloud/webhooks/index.js.map +0 -1
- package/dist/cloud/webhooks/parsers/github.d.ts.map +0 -1
- package/dist/cloud/webhooks/parsers/github.js.map +0 -1
- package/dist/cloud/webhooks/parsers/index.d.ts.map +0 -1
- package/dist/cloud/webhooks/parsers/index.js.map +0 -1
- package/dist/cloud/webhooks/parsers/linear.d.ts.map +0 -1
- package/dist/cloud/webhooks/parsers/linear.js.map +0 -1
- package/dist/cloud/webhooks/parsers/slack.d.ts.map +0 -1
- package/dist/cloud/webhooks/parsers/slack.js.map +0 -1
- package/dist/cloud/webhooks/responders/github.d.ts.map +0 -1
- package/dist/cloud/webhooks/responders/github.js.map +0 -1
- package/dist/cloud/webhooks/responders/index.d.ts.map +0 -1
- package/dist/cloud/webhooks/responders/index.js.map +0 -1
- package/dist/cloud/webhooks/responders/linear.d.ts.map +0 -1
- package/dist/cloud/webhooks/responders/linear.js.map +0 -1
- package/dist/cloud/webhooks/responders/slack.d.ts.map +0 -1
- package/dist/cloud/webhooks/responders/slack.js.map +0 -1
- package/dist/cloud/webhooks/router.d.ts.map +0 -1
- package/dist/cloud/webhooks/router.js.map +0 -1
- package/dist/cloud/webhooks/rules-engine.d.ts.map +0 -1
- package/dist/cloud/webhooks/rules-engine.js.map +0 -1
- package/dist/cloud/webhooks/types.d.ts.map +0 -1
- package/dist/cloud/webhooks/types.js.map +0 -1
- package/dist/continuity/formatter.d.ts.map +0 -1
- package/dist/continuity/formatter.js.map +0 -1
- package/dist/continuity/handoff-store.d.ts.map +0 -1
- package/dist/continuity/handoff-store.js.map +0 -1
- package/dist/continuity/index.d.ts.map +0 -1
- package/dist/continuity/index.js.map +0 -1
- package/dist/continuity/ledger-store.d.ts.map +0 -1
- package/dist/continuity/ledger-store.js.map +0 -1
- package/dist/continuity/manager.d.ts.map +0 -1
- package/dist/continuity/manager.js.map +0 -1
- package/dist/continuity/parser.d.ts.map +0 -1
- package/dist/continuity/parser.js.map +0 -1
- package/dist/continuity/types.d.ts.map +0 -1
- package/dist/continuity/types.js.map +0 -1
- package/dist/daemon/agent-manager.d.ts.map +0 -1
- package/dist/daemon/agent-manager.js.map +0 -1
- package/dist/daemon/agent-registry.d.ts.map +0 -1
- package/dist/daemon/agent-registry.js.map +0 -1
- package/dist/daemon/api.d.ts.map +0 -1
- package/dist/daemon/api.js.map +0 -1
- package/dist/daemon/auth.d.ts.map +0 -1
- package/dist/daemon/auth.js.map +0 -1
- package/dist/daemon/cli-auth.d.ts.map +0 -1
- package/dist/daemon/cli-auth.js.map +0 -1
- package/dist/daemon/cloud-sync.d.ts.map +0 -1
- package/dist/daemon/cloud-sync.js.map +0 -1
- package/dist/daemon/connection.d.ts.map +0 -1
- package/dist/daemon/connection.js.map +0 -1
- package/dist/daemon/index.d.ts.map +0 -1
- package/dist/daemon/index.js.map +0 -1
- package/dist/daemon/orchestrator.d.ts.map +0 -1
- package/dist/daemon/orchestrator.js.map +0 -1
- package/dist/daemon/registry.d.ts.map +0 -1
- package/dist/daemon/registry.js.map +0 -1
- package/dist/daemon/router.d.ts.map +0 -1
- package/dist/daemon/router.js.map +0 -1
- package/dist/daemon/server.d.ts.map +0 -1
- package/dist/daemon/server.js.map +0 -1
- package/dist/daemon/services/browser-testing.d.ts.map +0 -1
- package/dist/daemon/services/browser-testing.js.map +0 -1
- package/dist/daemon/services/container-spawner.d.ts.map +0 -1
- package/dist/daemon/services/container-spawner.js.map +0 -1
- package/dist/daemon/types.d.ts.map +0 -1
- package/dist/daemon/types.js.map +0 -1
- package/dist/daemon/workspace-manager.d.ts.map +0 -1
- package/dist/daemon/workspace-manager.js.map +0 -1
- package/dist/dashboard/out/_next/static/H5aWG0udPB4iOUIl_gytz/_ssgManifest.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/480-2d4111711d4e473c.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/724-73c1ee5f60abe860.js +0 -9
- package/dist/dashboard/out/_next/static/chunks/766-c3a14283c88d815b.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/app/page-7120be68bea622f3.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/metrics/page-1081dd190a331a91.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/providers/page-b68a681526eb145e.js +0 -1
- package/dist/dashboard/out/_next/static/css/29852f26181969a0.css +0 -1
- package/dist/dashboard/out/_next/static/css/411ce23ffeae9f76.css +0 -1
- package/dist/dashboard-server/metrics.d.ts.map +0 -1
- package/dist/dashboard-server/metrics.js.map +0 -1
- package/dist/dashboard-server/needs-attention.d.ts.map +0 -1
- package/dist/dashboard-server/needs-attention.js.map +0 -1
- package/dist/dashboard-server/server.d.ts.map +0 -1
- package/dist/dashboard-server/server.js.map +0 -1
- package/dist/dashboard-server/start.d.ts.map +0 -1
- package/dist/dashboard-server/start.js.map +0 -1
- package/dist/hooks/emitter.d.ts.map +0 -1
- package/dist/hooks/emitter.js.map +0 -1
- package/dist/hooks/inbox-check/hook.d.ts.map +0 -1
- package/dist/hooks/inbox-check/hook.js.map +0 -1
- package/dist/hooks/inbox-check/index.d.ts.map +0 -1
- package/dist/hooks/inbox-check/index.js.map +0 -1
- package/dist/hooks/inbox-check/types.d.ts.map +0 -1
- package/dist/hooks/inbox-check/types.js.map +0 -1
- package/dist/hooks/inbox-check/utils.d.ts.map +0 -1
- package/dist/hooks/inbox-check/utils.js.map +0 -1
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/hooks/index.js.map +0 -1
- package/dist/hooks/registry.d.ts.map +0 -1
- package/dist/hooks/registry.js.map +0 -1
- package/dist/hooks/trajectory-hooks.d.ts.map +0 -1
- package/dist/hooks/trajectory-hooks.js.map +0 -1
- package/dist/hooks/types.d.ts.map +0 -1
- package/dist/hooks/types.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/memory/adapters/index.d.ts.map +0 -1
- package/dist/memory/adapters/index.js.map +0 -1
- package/dist/memory/adapters/inmemory.d.ts.map +0 -1
- package/dist/memory/adapters/inmemory.js.map +0 -1
- package/dist/memory/adapters/supermemory.d.ts.map +0 -1
- package/dist/memory/adapters/supermemory.js.map +0 -1
- package/dist/memory/factory.d.ts.map +0 -1
- package/dist/memory/factory.js.map +0 -1
- package/dist/memory/index.d.ts.map +0 -1
- package/dist/memory/index.js.map +0 -1
- package/dist/memory/memory-hooks.d.ts.map +0 -1
- package/dist/memory/memory-hooks.js.map +0 -1
- package/dist/memory/service.d.ts.map +0 -1
- package/dist/memory/service.js.map +0 -1
- package/dist/memory/types.d.ts.map +0 -1
- package/dist/memory/types.js.map +0 -1
- package/dist/policy/agent-policy.d.ts.map +0 -1
- package/dist/policy/agent-policy.js.map +0 -1
- package/dist/policy/cloud-policy-fetcher.d.ts.map +0 -1
- package/dist/policy/cloud-policy-fetcher.js.map +0 -1
- package/dist/protocol/framing.d.ts.map +0 -1
- package/dist/protocol/framing.js.map +0 -1
- package/dist/protocol/index.d.ts.map +0 -1
- package/dist/protocol/index.js.map +0 -1
- package/dist/protocol/types.d.ts.map +0 -1
- package/dist/protocol/types.js.map +0 -1
- package/dist/resiliency/context-persistence.d.ts.map +0 -1
- package/dist/resiliency/context-persistence.js.map +0 -1
- package/dist/resiliency/crash-insights.d.ts.map +0 -1
- package/dist/resiliency/crash-insights.js.map +0 -1
- package/dist/resiliency/gossip-health.d.ts.map +0 -1
- package/dist/resiliency/gossip-health.js.map +0 -1
- package/dist/resiliency/health-monitor.d.ts.map +0 -1
- package/dist/resiliency/health-monitor.js.map +0 -1
- package/dist/resiliency/index.d.ts.map +0 -1
- package/dist/resiliency/index.js.map +0 -1
- package/dist/resiliency/leader-watchdog.d.ts.map +0 -1
- package/dist/resiliency/leader-watchdog.js.map +0 -1
- package/dist/resiliency/logger.d.ts.map +0 -1
- package/dist/resiliency/logger.js.map +0 -1
- package/dist/resiliency/memory-monitor.d.ts.map +0 -1
- package/dist/resiliency/memory-monitor.js.map +0 -1
- package/dist/resiliency/metrics.d.ts.map +0 -1
- package/dist/resiliency/metrics.js.map +0 -1
- package/dist/resiliency/provider-context.d.ts.map +0 -1
- package/dist/resiliency/provider-context.js.map +0 -1
- package/dist/resiliency/stateless-lead.d.ts.map +0 -1
- package/dist/resiliency/stateless-lead.js.map +0 -1
- package/dist/resiliency/supervisor.d.ts.map +0 -1
- package/dist/resiliency/supervisor.js.map +0 -1
- package/dist/shared/cli-auth-config.d.ts.map +0 -1
- package/dist/shared/cli-auth-config.js.map +0 -1
- package/dist/state/agent-state.d.ts.map +0 -1
- package/dist/state/agent-state.js.map +0 -1
- package/dist/storage/adapter.d.ts.map +0 -1
- package/dist/storage/adapter.js.map +0 -1
- package/dist/storage/sqlite-adapter.d.ts.map +0 -1
- package/dist/storage/sqlite-adapter.js.map +0 -1
- package/dist/trajectory/config.d.ts.map +0 -1
- package/dist/trajectory/config.js.map +0 -1
- package/dist/trajectory/index.d.ts.map +0 -1
- package/dist/trajectory/index.js.map +0 -1
- package/dist/trajectory/integration.d.ts.map +0 -1
- package/dist/trajectory/integration.js.map +0 -1
- package/dist/utils/agent-config.d.ts.map +0 -1
- package/dist/utils/agent-config.js.map +0 -1
- package/dist/utils/command-resolver.d.ts.map +0 -1
- package/dist/utils/command-resolver.js.map +0 -1
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/name-generator.d.ts.map +0 -1
- package/dist/utils/name-generator.js.map +0 -1
- package/dist/utils/project-namespace.d.ts.map +0 -1
- package/dist/utils/project-namespace.js.map +0 -1
- package/dist/utils/tmux-resolver.d.ts.map +0 -1
- package/dist/utils/tmux-resolver.js.map +0 -1
- package/dist/utils/update-checker.d.ts.map +0 -1
- package/dist/utils/update-checker.js.map +0 -1
- package/dist/wrapper/client.d.ts.map +0 -1
- package/dist/wrapper/client.js.map +0 -1
- package/dist/wrapper/inbox.d.ts.map +0 -1
- package/dist/wrapper/inbox.js.map +0 -1
- package/dist/wrapper/index.d.ts.map +0 -1
- package/dist/wrapper/index.js.map +0 -1
- package/dist/wrapper/parser.d.ts.map +0 -1
- package/dist/wrapper/parser.js.map +0 -1
- package/dist/wrapper/pty-wrapper.d.ts.map +0 -1
- package/dist/wrapper/pty-wrapper.js.map +0 -1
- package/dist/wrapper/shared.d.ts.map +0 -1
- package/dist/wrapper/shared.js.map +0 -1
- package/dist/wrapper/tmux-wrapper.d.ts.map +0 -1
- package/dist/wrapper/tmux-wrapper.js.map +0 -1
- package/docs/AGENTS.md +0 -513
- package/docs/ARCHITECTURE_DECISIONS.md +0 -175
- package/docs/CLOUD-ARCHITECTURE.md +0 -804
- package/docs/CLOUD-ONBOARDING-DESIGN.md +0 -1983
- package/docs/CONTRIBUTING.md +0 -151
- package/docs/HOOKS_API.md +0 -394
- package/docs/INTEGRATION-GUIDE.md +0 -926
- package/docs/PROTOCOL.md +0 -325
- package/docs/WRAPPER_EVENTS.md +0 -358
- package/docs/agent-policy-snippet.md +0 -40
- package/docs/agent-relay-protocol.md +0 -238
- package/docs/agent-relay-snippet.md +0 -174
- package/docs/archive/CHANGELOG.md +0 -11
- package/docs/archive/CLI-SIMPLIFICATION-COMPLETE.md +0 -48
- package/docs/archive/DESIGN_BRIDGE_STAFFING.md +0 -878
- package/docs/archive/DESIGN_V2.md +0 -1079
- package/docs/archive/EXECUTIVE_SUMMARY.md +0 -358
- package/docs/archive/MONETIZATION.md +0 -1679
- package/docs/archive/PROPOSAL-trajectories.md +0 -1582
- package/docs/archive/ROADMAP.md +0 -329
- package/docs/archive/SCALING_ANALYSIS.md +0 -280
- package/docs/archive/TESTING_PRESENCE_FEATURES.md +0 -327
- package/docs/archive/TMUX_IMPLEMENTATION_NOTES.md +0 -364
- package/docs/archive/TMUX_IMPROVEMENTS.md +0 -968
- package/docs/archive/dashboard-v2-plan.md +0 -179
- package/docs/archive/removable-code-analysis.md +0 -24
- package/docs/competitive/GASTOWN.md +0 -451
- package/docs/competitive/MCP_AGENT_MAIL.md +0 -389
- package/docs/competitive/OVERVIEW.md +0 -898
- package/docs/competitive/README.md +0 -34
- package/docs/competitive/TMUX_ORCHESTRATOR.md +0 -605
- package/docs/dashboard.png +0 -0
- package/docs/design/ci-failure-webhooks.md +0 -812
- package/docs/design/comprehensive-integrations.md +0 -238
- package/docs/design/e2b-sandbox-integration.md +0 -504
- package/docs/design/github-app-permissions.md +0 -264
- package/docs/guides/CLOUD.md +0 -236
- package/docs/guides/LOCAL.md +0 -535
- package/docs/guides/SELF-HOSTED.md +0 -494
- package/docs/local-testing.md +0 -428
- package/docs/proposals/continuous-claude-integration.md +0 -622
- package/docs/proposals/custom-commands.md +0 -368
- package/docs/proposals/shadow-as-subagent.md +0 -765
- package/docs/proposals/slack-bot-integration.md +0 -1457
- package/docs/tasks/global-skills-system.tasks.md +0 -230
- package/docs/tasks/webhook-integrations.tasks.md +0 -184
- package/docs/tasks/workspace-capabilities.tasks.md +0 -121
- package/docs/testing/RESILIENCY-TEST-PLAN-2026-01-01.md +0 -366
- package/scripts/cloud-setup.sh +0 -96
- package/scripts/dev/PUBLIC_RELEASE_PLAN.md +0 -88
- package/scripts/dev/dev-team-setup.sh +0 -431
- package/scripts/e2e-test.sh +0 -119
- package/scripts/games/game-protocol.md +0 -79
- package/scripts/games/hearts-setup.sh +0 -264
- package/scripts/manual-qa.sh +0 -293
- package/scripts/run-cloud-qa.sh +0 -220
- package/scripts/test-cli-auth/Dockerfile +0 -44
- package/scripts/test-cli-auth/Dockerfile.real +0 -79
- package/scripts/test-cli-auth/README.md +0 -286
- package/scripts/test-cli-auth/ci-test-real-clis.ts +0 -251
- package/scripts/test-cli-auth/ci-test-runner.ts +0 -263
- package/scripts/test-cli-auth/mock-cli.sh +0 -147
- package/scripts/test-cli-auth/package.json +0 -14
- package/scripts/test-cli-auth/test-oauth-flow.ts +0 -220
- package/scripts/test-pty-input-auto.js +0 -222
- package/scripts/test-pty-input.js +0 -150
- package/scripts/tictactoe-setup.sh +0 -181
- /package/dist/dashboard/out/_next/static/{H5aWG0udPB4iOUIl_gytz → T1tgCqVWHFIkV7ClEtzD7}/_buildManifest.js +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{117-b100311aff8d5c61.js → 117-f7b8ab0809342e77.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{648-a13d3c2b1be45466.js → 648-5cc6e1921389a58a.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/app/_not-found/{page-a4973f3e3c82fb67.js → page-53b8a69f76db17d0.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/app/connect-repos/{page-dc2e3a1a22478efc.js → page-f45ecbc3e06134fc.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/app/history/{page-56a8b4616a90dc43.js → page-8c8bed33beb2bf1c.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/app/login/{page-3eac37ea6f5dd153.js → page-16f3b49e55b1e0ed.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/app/pricing/{page-4d72d5a5d8a9b618.js → page-982a7000fee44014.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/app/signup/{page-fee4ed1709070bcd.js → page-547dd0ca55ecd0ba.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{fd9d1056-bf46c09eb57e019c.js → fd9d1056-609918ca7b6280bb.js} +0 -0
|
@@ -27,22 +27,56 @@ githubAppRouter.get('/status', (_req, res) => {
|
|
|
27
27
|
});
|
|
28
28
|
/**
|
|
29
29
|
* GET /api/github-app/repos
|
|
30
|
-
* List repositories the user has
|
|
30
|
+
* List repositories the user has access to
|
|
31
|
+
*
|
|
32
|
+
* First tries database (populated by GitHub App OAuth).
|
|
33
|
+
* If empty, queries GitHub directly via user OAuth connection.
|
|
31
34
|
*/
|
|
32
35
|
githubAppRouter.get('/repos', async (req, res) => {
|
|
33
36
|
const userId = req.session.userId;
|
|
34
37
|
try {
|
|
35
|
-
|
|
38
|
+
// Try database first (from GitHub App OAuth flow)
|
|
39
|
+
const dbRepos = await db.repositories.findByUserId(userId);
|
|
40
|
+
if (dbRepos.length > 0) {
|
|
41
|
+
// Return repos from database
|
|
42
|
+
return res.json({
|
|
43
|
+
repositories: dbRepos.map((r) => ({
|
|
44
|
+
id: r.id,
|
|
45
|
+
fullName: r.githubFullName,
|
|
46
|
+
isPrivate: r.isPrivate,
|
|
47
|
+
defaultBranch: r.defaultBranch,
|
|
48
|
+
syncStatus: r.syncStatus,
|
|
49
|
+
hasNangoConnection: !!r.nangoConnectionId,
|
|
50
|
+
lastSyncedAt: r.lastSyncedAt,
|
|
51
|
+
})),
|
|
52
|
+
source: 'database',
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
// Database empty - query GitHub directly via user OAuth
|
|
56
|
+
const user = await db.users.findById(userId);
|
|
57
|
+
if (!user?.nangoConnectionId) {
|
|
58
|
+
return res.json({
|
|
59
|
+
repositories: [],
|
|
60
|
+
source: 'none',
|
|
61
|
+
hint: 'User not connected to GitHub',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
console.log(`[github-app/repos] Database empty, querying GitHub for user ${user.githubUsername}`);
|
|
65
|
+
const { repositories } = await nangoService.listUserAccessibleRepos(user.nangoConnectionId, {
|
|
66
|
+
perPage: 100,
|
|
67
|
+
type: 'all',
|
|
68
|
+
});
|
|
36
69
|
res.json({
|
|
37
|
-
repositories:
|
|
38
|
-
id:
|
|
39
|
-
fullName: r.
|
|
70
|
+
repositories: repositories.map((r) => ({
|
|
71
|
+
id: null, // No database ID yet
|
|
72
|
+
fullName: r.fullName,
|
|
40
73
|
isPrivate: r.isPrivate,
|
|
41
74
|
defaultBranch: r.defaultBranch,
|
|
42
|
-
syncStatus:
|
|
43
|
-
hasNangoConnection:
|
|
44
|
-
lastSyncedAt:
|
|
75
|
+
syncStatus: 'live', // Queried from GitHub, not cached
|
|
76
|
+
hasNangoConnection: true,
|
|
77
|
+
lastSyncedAt: null,
|
|
45
78
|
})),
|
|
79
|
+
source: 'github-api',
|
|
46
80
|
});
|
|
47
81
|
}
|
|
48
82
|
catch (error) {
|
|
@@ -160,27 +160,17 @@ nangoAuthRouter.get('/repo-status/:connectionId', requireAuth, async (req, res)
|
|
|
160
160
|
* Handle Nango webhooks for auth and sync events
|
|
161
161
|
*/
|
|
162
162
|
nangoAuthRouter.post('/webhook', async (req, res) => {
|
|
163
|
-
// Use the preserved raw body from express.json verify callback
|
|
164
163
|
const rawBody = req.rawBody || JSON.stringify(req.body);
|
|
165
|
-
// Verify signature
|
|
164
|
+
// Verify webhook signature if present
|
|
166
165
|
const hasSignature = req.headers['x-nango-signature'] || req.headers['x-nango-hmac-sha256'];
|
|
167
|
-
const isDev = process.env.NODE_ENV !== 'production';
|
|
168
166
|
if (hasSignature) {
|
|
169
167
|
if (!nangoService.verifyWebhookSignature(rawBody, req.headers)) {
|
|
170
168
|
console.error('[nango-webhook] Invalid signature');
|
|
171
169
|
return res.status(401).json({ error: 'Invalid signature' });
|
|
172
170
|
}
|
|
173
|
-
console.log('[nango-webhook] Signature verified');
|
|
174
|
-
}
|
|
175
|
-
else if (!isDev) {
|
|
176
|
-
console.error('[nango-webhook] Missing signature in production');
|
|
177
|
-
return res.status(401).json({ error: 'Missing signature' });
|
|
178
|
-
}
|
|
179
|
-
else {
|
|
180
|
-
console.warn('[nango-webhook] Skipping signature verification in development (no signature)');
|
|
181
171
|
}
|
|
182
172
|
const payload = req.body;
|
|
183
|
-
console.log(`[nango-webhook] Received ${payload.type} event
|
|
173
|
+
console.log(`[nango-webhook] Received ${payload.type} event`);
|
|
184
174
|
try {
|
|
185
175
|
switch (payload.type) {
|
|
186
176
|
case 'auth':
|
|
@@ -190,8 +180,7 @@ nangoAuthRouter.post('/webhook', async (req, res) => {
|
|
|
190
180
|
console.log('[nango-webhook] Sync event received');
|
|
191
181
|
break;
|
|
192
182
|
case 'forward':
|
|
193
|
-
|
|
194
|
-
console.log('[nango-webhook] Forward event from provider (ignored)');
|
|
183
|
+
await handleForwardWebhook(payload);
|
|
195
184
|
break;
|
|
196
185
|
default:
|
|
197
186
|
console.log(`[nango-webhook] Unhandled event type: ${payload.type}`);
|
|
@@ -216,6 +205,72 @@ async function handleAuthWebhook(payload) {
|
|
|
216
205
|
await handleRepoAuthWebhook(connectionId, endUser);
|
|
217
206
|
}
|
|
218
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* Check user's repo access and auto-add them to workspaces
|
|
210
|
+
* Uses GitHub user OAuth to query accessible repos and persists them to database
|
|
211
|
+
*/
|
|
212
|
+
async function checkAndAutoAddToWorkspaces(userId, connectionId) {
|
|
213
|
+
try {
|
|
214
|
+
const user = await db.users.findById(userId);
|
|
215
|
+
if (!user)
|
|
216
|
+
return;
|
|
217
|
+
console.log(`[nango-webhook] Checking workspace auto-add for ${user.githubUsername}`);
|
|
218
|
+
// Query repos the user has access to via GitHub OAuth
|
|
219
|
+
const { repositories } = await nangoService.listUserAccessibleRepos(connectionId, {
|
|
220
|
+
perPage: 100,
|
|
221
|
+
type: 'all',
|
|
222
|
+
});
|
|
223
|
+
const workspacesToJoin = new Set();
|
|
224
|
+
// Check for workspace memberships - only persist repos that match existing workspaces
|
|
225
|
+
for (const repo of repositories) {
|
|
226
|
+
// Check if any user has this repo linked to a workspace
|
|
227
|
+
const allRepoRecords = await db.repositories.findByGithubFullName(repo.fullName);
|
|
228
|
+
let matchedWorkspaceId = null;
|
|
229
|
+
for (const record of allRepoRecords) {
|
|
230
|
+
if (record.workspaceId) {
|
|
231
|
+
workspacesToJoin.add(record.workspaceId);
|
|
232
|
+
matchedWorkspaceId = record.workspaceId; // Save the workspaceId to copy
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// Only persist repos that are linked to workspaces
|
|
236
|
+
if (matchedWorkspaceId) {
|
|
237
|
+
await db.repositories.upsert({
|
|
238
|
+
userId: user.id,
|
|
239
|
+
githubFullName: repo.fullName,
|
|
240
|
+
githubId: repo.id,
|
|
241
|
+
isPrivate: repo.isPrivate,
|
|
242
|
+
defaultBranch: repo.defaultBranch,
|
|
243
|
+
nangoConnectionId: connectionId,
|
|
244
|
+
workspaceId: matchedWorkspaceId, // Copy the workspaceId
|
|
245
|
+
syncStatus: 'synced',
|
|
246
|
+
lastSyncedAt: new Date(),
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// Auto-add user to workspaces
|
|
251
|
+
for (const workspaceId of workspacesToJoin) {
|
|
252
|
+
const existingMembership = await db.workspaceMembers.findMembership(workspaceId, userId);
|
|
253
|
+
if (!existingMembership) {
|
|
254
|
+
const workspace = await db.workspaces.findById(workspaceId);
|
|
255
|
+
if (workspace) {
|
|
256
|
+
console.log(`[nango-webhook] Auto-adding ${user.githubUsername} to workspace ${workspace.name}`);
|
|
257
|
+
await db.workspaceMembers.addMember({
|
|
258
|
+
workspaceId,
|
|
259
|
+
userId,
|
|
260
|
+
role: 'member',
|
|
261
|
+
invitedBy: workspace.userId,
|
|
262
|
+
});
|
|
263
|
+
await db.workspaceMembers.acceptInvite(workspaceId, userId);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
console.log(`[nango-webhook] Synced ${repositories.length} repos, auto-added ${user.githubUsername} to ${workspacesToJoin.size} workspaces`);
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
console.error(`[nango-webhook] Error checking workspace auto-add:`, error);
|
|
271
|
+
// Non-fatal - don't throw
|
|
272
|
+
}
|
|
273
|
+
}
|
|
219
274
|
/**
|
|
220
275
|
* Handle GitHub login webhook
|
|
221
276
|
*
|
|
@@ -246,6 +301,8 @@ async function handleLoginWebhook(connectionId, _endUser) {
|
|
|
246
301
|
email: newUser.email || undefined,
|
|
247
302
|
});
|
|
248
303
|
console.log(`[nango-webhook] New user created: ${githubUser.login}`);
|
|
304
|
+
// Check for auto-add to workspaces based on repo access
|
|
305
|
+
await checkAndAutoAddToWorkspaces(newUser.id, connectionId);
|
|
249
306
|
return;
|
|
250
307
|
}
|
|
251
308
|
// SCENARIO 2: Returning user with existing connection - delete temp connection
|
|
@@ -269,6 +326,8 @@ async function handleLoginWebhook(connectionId, _endUser) {
|
|
|
269
326
|
console.error(`[nango-webhook] Failed to delete temp connection:`, error);
|
|
270
327
|
// Non-fatal - continue anyway
|
|
271
328
|
}
|
|
329
|
+
// Check for auto-add using permanent connection
|
|
330
|
+
await checkAndAutoAddToWorkspaces(existingUser.id, existingUser.nangoConnectionId);
|
|
272
331
|
return;
|
|
273
332
|
}
|
|
274
333
|
// SCENARIO 3: Existing user, first connection (or same connection)
|
|
@@ -284,6 +343,192 @@ async function handleLoginWebhook(connectionId, _endUser) {
|
|
|
284
343
|
id: existingUser.id,
|
|
285
344
|
email: existingUser.email || undefined,
|
|
286
345
|
});
|
|
346
|
+
// Check for auto-add to workspaces
|
|
347
|
+
await checkAndAutoAddToWorkspaces(existingUser.id, connectionId);
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Handle Nango forward webhook (GitHub events forwarded by Nango)
|
|
351
|
+
*/
|
|
352
|
+
async function handleForwardWebhook(payload) {
|
|
353
|
+
const githubPayload = payload.payload;
|
|
354
|
+
console.log(`[nango-webhook] Forward event: action=${githubPayload.action} from ${payload.providerConfigKey}`);
|
|
355
|
+
// Only process GitHub App events
|
|
356
|
+
if (payload.providerConfigKey !== NANGO_INTEGRATIONS.GITHUB_APP) {
|
|
357
|
+
console.log('[nango-webhook] Ignoring forward event from non-GitHub-App integration');
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
try {
|
|
361
|
+
// Determine event type from payload structure
|
|
362
|
+
if (githubPayload.installation && githubPayload.action === 'created' && githubPayload.repositories) {
|
|
363
|
+
// Installation created event
|
|
364
|
+
await handleInstallationForward(githubPayload, payload.connectionId);
|
|
365
|
+
}
|
|
366
|
+
else if (githubPayload.repositories_added || githubPayload.repositories_removed) {
|
|
367
|
+
// Installation repositories added/removed
|
|
368
|
+
await handleInstallationRepositoriesForward(githubPayload, payload.connectionId);
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
console.log(`[nango-webhook] Unhandled forward event structure: action=${githubPayload.action}`);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
catch (error) {
|
|
375
|
+
console.error(`[nango-webhook] Error processing forward event:`, error);
|
|
376
|
+
throw error;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Handle GitHub installation events forwarded by Nango
|
|
381
|
+
*/
|
|
382
|
+
async function handleInstallationForward(body, connectionId) {
|
|
383
|
+
const { action, installation, repositories, sender } = body;
|
|
384
|
+
if (!installation || !sender)
|
|
385
|
+
return;
|
|
386
|
+
const installationId = String(installation.id);
|
|
387
|
+
console.log(`[nango-webhook] Installation ${action}: ${installation.account.login} (${installationId})`);
|
|
388
|
+
if (action === 'created') {
|
|
389
|
+
// Find user by GitHub ID
|
|
390
|
+
const user = await db.users.findByGithubId(String(sender.id));
|
|
391
|
+
// Create/update installation record
|
|
392
|
+
await db.githubInstallations.upsert({
|
|
393
|
+
installationId,
|
|
394
|
+
accountType: installation.account.type.toLowerCase(),
|
|
395
|
+
accountLogin: installation.account.login,
|
|
396
|
+
accountId: String(installation.account.id),
|
|
397
|
+
installedById: user?.id ?? null,
|
|
398
|
+
permissions: installation.permissions,
|
|
399
|
+
events: installation.events,
|
|
400
|
+
});
|
|
401
|
+
// Sync repositories if provided
|
|
402
|
+
if (repositories && user) {
|
|
403
|
+
const dbInstallation = await db.githubInstallations.findByInstallationId(installationId);
|
|
404
|
+
if (dbInstallation) {
|
|
405
|
+
const workspacesToJoin = new Set();
|
|
406
|
+
for (const repo of repositories) {
|
|
407
|
+
const syncedRepo = await db.repositories.upsert({
|
|
408
|
+
userId: user.id,
|
|
409
|
+
githubFullName: repo.full_name,
|
|
410
|
+
githubId: repo.id,
|
|
411
|
+
isPrivate: repo.private,
|
|
412
|
+
installationId: dbInstallation.id,
|
|
413
|
+
nangoConnectionId: connectionId,
|
|
414
|
+
syncStatus: 'synced',
|
|
415
|
+
lastSyncedAt: new Date(),
|
|
416
|
+
});
|
|
417
|
+
// Check if repo is part of an existing workspace
|
|
418
|
+
// Look for ANY user's record of this repo that has a workspaceId
|
|
419
|
+
if (syncedRepo.workspaceId) {
|
|
420
|
+
workspacesToJoin.add(syncedRepo.workspaceId);
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
// Check if other users have this repo linked to a workspace
|
|
424
|
+
const allRepoRecords = await db.repositories.findByGithubFullName(repo.full_name);
|
|
425
|
+
for (const otherRecord of allRepoRecords) {
|
|
426
|
+
if (otherRecord.workspaceId && otherRecord.userId !== user.id) {
|
|
427
|
+
workspacesToJoin.add(otherRecord.workspaceId);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
// Auto-join user to workspaces for repos they have access to
|
|
433
|
+
for (const workspaceId of workspacesToJoin) {
|
|
434
|
+
const existingMembership = await db.workspaceMembers.findMembership(workspaceId, user.id);
|
|
435
|
+
if (!existingMembership) {
|
|
436
|
+
const workspace = await db.workspaces.findById(workspaceId);
|
|
437
|
+
if (workspace) {
|
|
438
|
+
console.log(`[nango-webhook] Auto-adding ${user.githubUsername} to workspace ${workspace.name}`);
|
|
439
|
+
await db.workspaceMembers.addMember({
|
|
440
|
+
workspaceId,
|
|
441
|
+
userId: user.id,
|
|
442
|
+
role: 'member',
|
|
443
|
+
invitedBy: workspace.userId,
|
|
444
|
+
});
|
|
445
|
+
await db.workspaceMembers.acceptInvite(workspaceId, user.id);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
console.log(`[nango-webhook] Installation created for ${installation.account.login}, auto-joined ${workspacesToJoin.size} workspaces`);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Handle installation_repositories events forwarded by Nango
|
|
456
|
+
*/
|
|
457
|
+
async function handleInstallationRepositoriesForward(body, connectionId) {
|
|
458
|
+
const { action, installation, repositories_added, repositories_removed, sender } = body;
|
|
459
|
+
if (!installation || !sender)
|
|
460
|
+
return;
|
|
461
|
+
const installationId = String(installation.id);
|
|
462
|
+
console.log(`[nango-webhook] Repositories ${action} for ${installation.account.login}`);
|
|
463
|
+
// Find installation in database
|
|
464
|
+
const dbInstallation = await db.githubInstallations.findByInstallationId(installationId);
|
|
465
|
+
if (!dbInstallation) {
|
|
466
|
+
console.error(`[nango-webhook] Installation ${installationId} not found in database`);
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
// Find user who triggered this
|
|
470
|
+
const user = await db.users.findByGithubId(String(sender.id));
|
|
471
|
+
if (!user) {
|
|
472
|
+
console.error(`[nango-webhook] User ${sender.login} not found in database`);
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
if (action === 'added' && repositories_added) {
|
|
476
|
+
const workspacesToJoin = new Set();
|
|
477
|
+
for (const repo of repositories_added) {
|
|
478
|
+
const syncedRepo = await db.repositories.upsert({
|
|
479
|
+
userId: user.id,
|
|
480
|
+
githubFullName: repo.full_name,
|
|
481
|
+
githubId: repo.id,
|
|
482
|
+
isPrivate: repo.private,
|
|
483
|
+
installationId: dbInstallation.id,
|
|
484
|
+
nangoConnectionId: connectionId,
|
|
485
|
+
syncStatus: 'synced',
|
|
486
|
+
lastSyncedAt: new Date(),
|
|
487
|
+
});
|
|
488
|
+
// Check if repo is part of an existing workspace
|
|
489
|
+
// Look for ANY user's record of this repo that has a workspaceId
|
|
490
|
+
if (syncedRepo.workspaceId) {
|
|
491
|
+
workspacesToJoin.add(syncedRepo.workspaceId);
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
// Check if other users have this repo linked to a workspace
|
|
495
|
+
const allRepoRecords = await db.repositories.findByGithubFullName(repo.full_name);
|
|
496
|
+
for (const otherRecord of allRepoRecords) {
|
|
497
|
+
if (otherRecord.workspaceId && otherRecord.userId !== user.id) {
|
|
498
|
+
workspacesToJoin.add(otherRecord.workspaceId);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
// Auto-join user to workspaces for repos they have access to
|
|
504
|
+
for (const workspaceId of workspacesToJoin) {
|
|
505
|
+
const existingMembership = await db.workspaceMembers.findMembership(workspaceId, user.id);
|
|
506
|
+
if (!existingMembership) {
|
|
507
|
+
const workspace = await db.workspaces.findById(workspaceId);
|
|
508
|
+
if (workspace) {
|
|
509
|
+
console.log(`[nango-webhook] Auto-adding ${user.githubUsername} to workspace ${workspace.name}`);
|
|
510
|
+
await db.workspaceMembers.addMember({
|
|
511
|
+
workspaceId,
|
|
512
|
+
userId: user.id,
|
|
513
|
+
role: 'member',
|
|
514
|
+
invitedBy: workspace.userId,
|
|
515
|
+
});
|
|
516
|
+
await db.workspaceMembers.acceptInvite(workspaceId, user.id);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
console.log(`[nango-webhook] Added ${repositories_added.length} repositories, auto-joined ${workspacesToJoin.size} workspaces`);
|
|
521
|
+
}
|
|
522
|
+
if (action === 'removed' && repositories_removed) {
|
|
523
|
+
for (const repo of repositories_removed) {
|
|
524
|
+
const repos = await db.repositories.findByUserId(user.id);
|
|
525
|
+
const existingRepo = repos.find(r => r.githubFullName === repo.full_name);
|
|
526
|
+
if (existingRepo) {
|
|
527
|
+
await db.repositories.updateSyncStatus(existingRepo.id, 'access_removed');
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
console.log(`[nango-webhook] Removed access to ${repositories_removed.length} repositories`);
|
|
531
|
+
}
|
|
287
532
|
}
|
|
288
533
|
/**
|
|
289
534
|
* Handle GitHub App OAuth webhook (repo access)
|
|
@@ -339,9 +584,11 @@ async function handleRepoAuthWebhook(connectionId, endUser) {
|
|
|
339
584
|
}
|
|
340
585
|
// Fetch repos the user has access to
|
|
341
586
|
const { repositories: repos } = await nangoService.listGithubAppRepos(connectionId);
|
|
587
|
+
// Track workspaces to auto-join
|
|
588
|
+
const workspacesToJoin = new Set();
|
|
342
589
|
// Sync repos to database
|
|
343
590
|
for (const repo of repos) {
|
|
344
|
-
await db.repositories.upsert({
|
|
591
|
+
const syncedRepo = await db.repositories.upsert({
|
|
345
592
|
userId: user.id,
|
|
346
593
|
githubFullName: repo.full_name,
|
|
347
594
|
githubId: repo.id,
|
|
@@ -352,10 +599,44 @@ async function handleRepoAuthWebhook(connectionId, endUser) {
|
|
|
352
599
|
syncStatus: 'synced',
|
|
353
600
|
lastSyncedAt: new Date(),
|
|
354
601
|
});
|
|
602
|
+
// Check if this repo is part of an existing workspace
|
|
603
|
+
// Look for ANY user's record of this repo that has a workspaceId
|
|
604
|
+
if (syncedRepo.workspaceId) {
|
|
605
|
+
workspacesToJoin.add(syncedRepo.workspaceId);
|
|
606
|
+
}
|
|
607
|
+
else {
|
|
608
|
+
// Check if other users have this repo linked to a workspace
|
|
609
|
+
const allRepoRecords = await db.repositories.findByGithubFullName(repo.full_name);
|
|
610
|
+
for (const otherRecord of allRepoRecords) {
|
|
611
|
+
if (otherRecord.workspaceId && otherRecord.userId !== user.id) {
|
|
612
|
+
workspacesToJoin.add(otherRecord.workspaceId);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
// Auto-join user to workspaces for repos they have access to
|
|
618
|
+
for (const workspaceId of workspacesToJoin) {
|
|
619
|
+
// Check if already a member
|
|
620
|
+
const existingMembership = await db.workspaceMembers.findMembership(workspaceId, user.id);
|
|
621
|
+
if (!existingMembership) {
|
|
622
|
+
// Get workspace owner to use as invitedBy
|
|
623
|
+
const workspace = await db.workspaces.findById(workspaceId);
|
|
624
|
+
if (workspace) {
|
|
625
|
+
console.log(`[nango-webhook] Auto-adding ${user.githubUsername} to workspace ${workspace.name}`);
|
|
626
|
+
await db.workspaceMembers.addMember({
|
|
627
|
+
workspaceId,
|
|
628
|
+
userId: user.id,
|
|
629
|
+
role: 'member',
|
|
630
|
+
invitedBy: workspace.userId, // Workspace owner invited them
|
|
631
|
+
});
|
|
632
|
+
// Auto-accept since they have GitHub repo access
|
|
633
|
+
await db.workspaceMembers.acceptInvite(workspaceId, user.id);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
355
636
|
}
|
|
356
637
|
// Clear any pending installation request
|
|
357
638
|
await db.users.clearPendingInstallationRequest(user.id);
|
|
358
|
-
console.log(`[nango-webhook] Synced ${repos.length} repos for ${user.githubUsername} (installation: ${githubInstallationId || 'unknown'})`);
|
|
639
|
+
console.log(`[nango-webhook] Synced ${repos.length} repos for ${user.githubUsername} (installation: ${githubInstallationId || 'unknown'}), auto-joined ${workspacesToJoin.size} workspaces`);
|
|
359
640
|
// Note: We intentionally do NOT auto-provision workspaces here.
|
|
360
641
|
// Users should go through the onboarding flow at /app to:
|
|
361
642
|
// 1. Name their workspace
|