agent-relay 1.1.0 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +3 -0
- package/.nvmrc +1 -0
- package/.trajectories/completed/2026-01/traj_1dviorhnkcb5.json +65 -0
- package/.trajectories/completed/2026-01/traj_1dviorhnkcb5.md +37 -0
- package/.trajectories/completed/2026-01/traj_1k5if5snst2e.json +65 -0
- package/.trajectories/completed/2026-01/traj_1k5if5snst2e.md +37 -0
- package/.trajectories/completed/2026-01/traj_1rp3rges5811.json +49 -0
- package/.trajectories/completed/2026-01/traj_1rp3rges5811.md +31 -0
- package/.trajectories/completed/2026-01/traj_22bhyulruouw.json +113 -0
- package/.trajectories/completed/2026-01/traj_22bhyulruouw.md +57 -0
- package/.trajectories/completed/2026-01/traj_2dao7ddgnta0.json +53 -0
- package/.trajectories/completed/2026-01/traj_2dao7ddgnta0.md +32 -0
- package/.trajectories/completed/2026-01/traj_3t0440mjeunc.json +26 -0
- package/.trajectories/completed/2026-01/traj_3t0440mjeunc.md +6 -0
- package/.trajectories/completed/2026-01/traj_45x9494d9xnr.json +47 -0
- package/.trajectories/completed/2026-01/traj_45x9494d9xnr.md +32 -0
- package/.trajectories/completed/2026-01/traj_4aa0bb77s4nh.json +53 -0
- package/.trajectories/completed/2026-01/traj_4aa0bb77s4nh.md +32 -0
- package/.trajectories/completed/2026-01/traj_5lhmzq8rxpqv.json +59 -0
- package/.trajectories/completed/2026-01/traj_5lhmzq8rxpqv.md +33 -0
- package/.trajectories/completed/2026-01/traj_5vr4e9erb1fs.json +53 -0
- package/.trajectories/completed/2026-01/traj_5vr4e9erb1fs.md +32 -0
- package/.trajectories/completed/2026-01/traj_6fgiwdoklvym.json +48 -0
- package/.trajectories/completed/2026-01/traj_6fgiwdoklvym.md +24 -0
- package/.trajectories/completed/2026-01/traj_7ludwvz45veh.json +209 -0
- package/.trajectories/completed/2026-01/traj_7ludwvz45veh.md +97 -0
- package/.trajectories/completed/2026-01/traj_9921cuhel0pj.json +48 -0
- package/.trajectories/completed/2026-01/traj_9921cuhel0pj.md +24 -0
- package/.trajectories/completed/2026-01/traj_ajs7zqfux4wc.json +49 -0
- package/.trajectories/completed/2026-01/traj_ajs7zqfux4wc.md +23 -0
- package/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.json +53 -0
- package/.trajectories/completed/2026-01/traj_cvtqhlwcq9s0.md +32 -0
- package/.trajectories/completed/2026-01/traj_cxofprm2m2en.json +49 -0
- package/.trajectories/completed/2026-01/traj_cxofprm2m2en.md +31 -0
- package/.trajectories/completed/2026-01/traj_d2hhz3k0vrhn.json +26 -0
- package/.trajectories/completed/2026-01/traj_d2hhz3k0vrhn.md +6 -0
- package/.trajectories/completed/2026-01/traj_dfuvww9pege5.json +59 -0
- package/.trajectories/completed/2026-01/traj_dfuvww9pege5.md +37 -0
- package/.trajectories/completed/2026-01/traj_g0fisy9h51mf.json +77 -0
- package/.trajectories/completed/2026-01/traj_g0fisy9h51mf.md +42 -0
- package/.trajectories/completed/2026-01/traj_gjdre5voouod.json +53 -0
- package/.trajectories/completed/2026-01/traj_gjdre5voouod.md +32 -0
- package/.trajectories/completed/2026-01/traj_gtlyqtta3x8l.json +25 -0
- package/.trajectories/completed/2026-01/traj_gtlyqtta3x8l.md +15 -0
- package/.trajectories/completed/2026-01/traj_h4xijiuip3w4.json +101 -0
- package/.trajectories/completed/2026-01/traj_h4xijiuip3w4.md +44 -0
- package/.trajectories/completed/2026-01/traj_hhxte7w4gjjx.json +22 -0
- package/.trajectories/completed/2026-01/traj_hhxte7w4gjjx.md +5 -0
- package/.trajectories/completed/2026-01/traj_hpungyhoj6v5.json +53 -0
- package/.trajectories/completed/2026-01/traj_hpungyhoj6v5.md +32 -0
- package/.trajectories/completed/2026-01/traj_m2xkjv0w2sq7.json +25 -0
- package/.trajectories/completed/2026-01/traj_m2xkjv0w2sq7.md +15 -0
- package/.trajectories/completed/2026-01/traj_noq5zbvnrdvz.json +53 -0
- package/.trajectories/completed/2026-01/traj_noq5zbvnrdvz.md +32 -0
- package/.trajectories/completed/2026-01/traj_ntbs6ppopf46.json +53 -0
- package/.trajectories/completed/2026-01/traj_ntbs6ppopf46.md +32 -0
- package/.trajectories/completed/2026-01/traj_ozd98si6a7ns.json +48 -0
- package/.trajectories/completed/2026-01/traj_ozd98si6a7ns.md +24 -0
- package/.trajectories/completed/2026-01/traj_prdza7a5cxp5.json +53 -0
- package/.trajectories/completed/2026-01/traj_prdza7a5cxp5.md +32 -0
- package/.trajectories/completed/2026-01/traj_qb3twvvywfwi.json +77 -0
- package/.trajectories/completed/2026-01/traj_qb3twvvywfwi.md +42 -0
- package/.trajectories/completed/2026-01/traj_qft54mi7nfor.json +53 -0
- package/.trajectories/completed/2026-01/traj_qft54mi7nfor.md +32 -0
- package/.trajectories/completed/2026-01/traj_qx9uhf8whhxo.json +83 -0
- package/.trajectories/completed/2026-01/traj_qx9uhf8whhxo.md +47 -0
- package/.trajectories/completed/2026-01/traj_rd9toccj18a0.json +59 -0
- package/.trajectories/completed/2026-01/traj_rd9toccj18a0.md +37 -0
- package/.trajectories/completed/2026-01/traj_rt4fiw3ecp50.json +48 -0
- package/.trajectories/completed/2026-01/traj_rt4fiw3ecp50.md +16 -0
- package/.trajectories/completed/2026-01/traj_st8j35b0hrlc.json +59 -0
- package/.trajectories/completed/2026-01/traj_st8j35b0hrlc.md +37 -0
- package/.trajectories/completed/2026-01/traj_t1yy8m7hbuxp.json +53 -0
- package/.trajectories/completed/2026-01/traj_t1yy8m7hbuxp.md +32 -0
- package/.trajectories/completed/2026-01/traj_tmux_orchestrator_analysis.json +84 -0
- package/.trajectories/completed/2026-01/traj_tmux_orchestrator_analysis.md +109 -0
- package/.trajectories/completed/2026-01/traj_u9n9eqasw16k.json +53 -0
- package/.trajectories/completed/2026-01/traj_u9n9eqasw16k.md +32 -0
- package/.trajectories/completed/2026-01/traj_v87hypnongqx.json +71 -0
- package/.trajectories/completed/2026-01/traj_v87hypnongqx.md +42 -0
- package/.trajectories/completed/2026-01/traj_wkp2fgzdyinb.json +53 -0
- package/.trajectories/completed/2026-01/traj_wkp2fgzdyinb.md +32 -0
- package/.trajectories/completed/2026-01/traj_x14t8w8rn7xg.json +20 -0
- package/.trajectories/completed/2026-01/traj_x14t8w8rn7xg.md +6 -0
- package/.trajectories/completed/2026-01/traj_xnwbznkvv8ua.json +175 -0
- package/.trajectories/completed/2026-01/traj_xnwbznkvv8ua.md +82 -0
- package/.trajectories/completed/2026-01/traj_ysjc8zaeqtd3.json +47 -0
- package/.trajectories/completed/2026-01/traj_ysjc8zaeqtd3.md +32 -0
- package/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.json +59 -0
- package/.trajectories/completed/2026-01/traj_yvdadtvdgnz3.md +37 -0
- package/.trajectories/completed/2026-01/traj_z0vcw1wrzide.json +53 -0
- package/.trajectories/completed/2026-01/traj_z0vcw1wrzide.md +32 -0
- package/.trajectories/index.json +314 -0
- package/ARCHITECTURE.md +1245 -0
- package/README.md +1 -1
- package/TESTING.md +278 -0
- package/deploy/init-db.sql +5 -0
- package/deploy/scripts/setup-fly-workspaces.sh +69 -0
- package/deploy/scripts/setup-railway.sh +75 -0
- package/deploy/workspace/entrypoint-browser.sh +118 -0
- package/deploy/workspace/entrypoint.sh +348 -0
- package/deploy/workspace/git-credential-relay +111 -0
- package/dist/bridge/spawner.d.ts +53 -0
- package/dist/bridge/spawner.js +203 -19
- package/dist/bridge/types.d.ts +12 -0
- package/dist/cli/index.js +618 -5
- package/dist/cloud/api/auth.d.ts +3 -2
- package/dist/cloud/api/auth.js +10 -98
- package/dist/cloud/api/billing.js +30 -9
- package/dist/cloud/api/cli-pty-runner.d.ts +54 -0
- package/dist/cloud/api/cli-pty-runner.js +119 -0
- package/dist/cloud/api/codex-auth-helper.d.ts +15 -0
- package/dist/cloud/api/codex-auth-helper.js +100 -0
- package/dist/cloud/api/generic-webhooks.d.ts +8 -0
- package/dist/cloud/api/generic-webhooks.js +129 -0
- package/dist/cloud/api/git.d.ts +8 -0
- package/dist/cloud/api/git.js +152 -0
- package/dist/cloud/api/github-app.d.ts +11 -0
- package/dist/cloud/api/github-app.js +189 -0
- package/dist/cloud/api/middleware/planLimits.d.ts +7 -0
- package/dist/cloud/api/middleware/planLimits.js +39 -1
- package/dist/cloud/api/monitoring.d.ts +11 -0
- package/dist/cloud/api/monitoring.js +578 -0
- package/dist/cloud/api/nango-auth.d.ts +9 -0
- package/dist/cloud/api/nango-auth.js +377 -0
- package/dist/cloud/api/onboarding.d.ts +8 -1
- package/dist/cloud/api/onboarding.js +313 -119
- package/dist/cloud/api/policy.d.ts +8 -0
- package/dist/cloud/api/policy.js +229 -0
- package/dist/cloud/api/providers.js +114 -42
- package/dist/cloud/api/repos.d.ts +1 -0
- package/dist/cloud/api/repos.js +186 -0
- package/dist/cloud/api/test-helpers.d.ts +10 -0
- package/dist/cloud/api/test-helpers.js +575 -0
- package/dist/cloud/api/webhooks.d.ts +8 -0
- package/dist/cloud/api/webhooks.js +645 -0
- package/dist/cloud/api/workspaces.js +320 -12
- package/dist/cloud/billing/plans.js +32 -19
- package/dist/cloud/billing/types.d.ts +9 -3
- package/dist/cloud/config.d.ts +9 -2
- package/dist/cloud/config.js +13 -4
- package/dist/cloud/db/drizzle.d.ts +84 -1
- package/dist/cloud/db/drizzle.js +470 -0
- package/dist/cloud/db/index.d.ts +9 -4
- package/dist/cloud/db/index.js +11 -3
- package/dist/cloud/db/schema.d.ts +3283 -556
- package/dist/cloud/db/schema.js +314 -1
- package/dist/cloud/index.d.ts +1 -0
- package/dist/cloud/index.js +2 -0
- package/dist/cloud/provisioner/index.d.ts +56 -0
- package/dist/cloud/provisioner/index.js +676 -34
- package/dist/cloud/server.d.ts +1 -0
- package/dist/cloud/server.js +362 -13
- package/dist/cloud/services/auto-scaler.d.ts +152 -0
- package/dist/cloud/services/auto-scaler.js +439 -0
- package/dist/cloud/services/capacity-manager.d.ts +148 -0
- package/dist/cloud/services/capacity-manager.js +449 -0
- package/dist/cloud/services/ci-agent-spawner.d.ts +49 -0
- package/dist/cloud/services/ci-agent-spawner.js +373 -0
- package/dist/cloud/services/index.d.ts +12 -0
- package/dist/cloud/services/index.js +15 -0
- package/dist/cloud/services/mention-handler.d.ts +65 -0
- package/dist/cloud/services/mention-handler.js +405 -0
- package/dist/cloud/services/nango.d.ts +186 -0
- package/dist/cloud/services/nango.js +344 -0
- package/dist/cloud/services/persistence.d.ts +131 -0
- package/dist/cloud/services/persistence.js +200 -0
- package/dist/cloud/services/planLimits.d.ts +37 -0
- package/dist/cloud/services/planLimits.js +86 -5
- package/dist/cloud/services/scaling-orchestrator.d.ts +159 -0
- package/dist/cloud/services/scaling-orchestrator.js +502 -0
- package/dist/cloud/services/scaling-policy.d.ts +121 -0
- package/dist/cloud/services/scaling-policy.js +415 -0
- package/dist/cloud/vault/index.js +1 -1
- package/dist/cloud/webhooks/index.d.ts +24 -0
- package/dist/cloud/webhooks/index.js +29 -0
- package/dist/cloud/webhooks/parsers/github.d.ts +8 -0
- package/dist/cloud/webhooks/parsers/github.js +234 -0
- package/dist/cloud/webhooks/parsers/index.d.ts +23 -0
- package/dist/cloud/webhooks/parsers/index.js +30 -0
- package/dist/cloud/webhooks/parsers/linear.d.ts +9 -0
- package/dist/cloud/webhooks/parsers/linear.js +258 -0
- package/dist/cloud/webhooks/parsers/slack.d.ts +9 -0
- package/dist/cloud/webhooks/parsers/slack.js +214 -0
- package/dist/cloud/webhooks/responders/github.d.ts +8 -0
- package/dist/cloud/webhooks/responders/github.js +73 -0
- package/dist/cloud/webhooks/responders/index.d.ts +23 -0
- package/dist/cloud/webhooks/responders/index.js +30 -0
- package/dist/cloud/webhooks/responders/linear.d.ts +9 -0
- package/dist/cloud/webhooks/responders/linear.js +149 -0
- package/dist/cloud/webhooks/responders/slack.d.ts +20 -0
- package/dist/cloud/webhooks/responders/slack.js +178 -0
- package/dist/cloud/webhooks/router.d.ts +25 -0
- package/dist/cloud/webhooks/router.js +504 -0
- package/dist/cloud/webhooks/rules-engine.d.ts +24 -0
- package/dist/cloud/webhooks/rules-engine.js +287 -0
- package/dist/cloud/webhooks/types.d.ts +186 -0
- package/dist/cloud/webhooks/types.js +8 -0
- package/dist/continuity/formatter.d.ts +51 -0
- package/dist/continuity/formatter.js +313 -0
- package/dist/continuity/handoff-store.d.ts +67 -0
- package/dist/continuity/handoff-store.js +472 -0
- package/dist/continuity/index.d.ts +45 -0
- package/dist/continuity/index.js +48 -0
- package/dist/continuity/ledger-store.d.ts +110 -0
- package/dist/continuity/ledger-store.js +500 -0
- package/dist/continuity/manager.d.ts +178 -0
- package/dist/continuity/manager.js +562 -0
- package/dist/continuity/parser.d.ts +76 -0
- package/dist/continuity/parser.js +579 -0
- package/dist/continuity/types.d.ts +180 -0
- package/dist/continuity/types.js +9 -0
- package/dist/daemon/agent-manager.d.ts +27 -0
- package/dist/daemon/agent-manager.js +107 -6
- package/dist/daemon/agent-registry.d.ts +32 -0
- package/dist/daemon/agent-registry.js +42 -2
- package/dist/daemon/api.d.ts +12 -0
- package/dist/daemon/api.js +131 -2
- package/dist/daemon/cli-auth.d.ts +67 -0
- package/dist/daemon/cli-auth.js +537 -0
- package/dist/daemon/cloud-sync.js +9 -7
- package/dist/daemon/orchestrator.js +30 -0
- package/dist/daemon/router.d.ts +5 -0
- package/dist/daemon/router.js +78 -26
- package/dist/daemon/server.d.ts +5 -0
- package/dist/daemon/server.js +9 -1
- package/dist/daemon/services/browser-testing.d.ts +88 -0
- package/dist/daemon/services/browser-testing.js +244 -0
- package/dist/daemon/services/container-spawner.d.ts +135 -0
- package/dist/daemon/services/container-spawner.js +313 -0
- package/dist/daemon/types.d.ts +5 -1
- package/dist/dashboard/out/404.html +1 -1
- package/dist/dashboard/out/_next/static/chunks/116-2502180def231162.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/282-980c2eb8fff20123.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/699-3b1cd6618a45d259.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/724-2dae7627550ab88f.js +9 -0
- package/dist/dashboard/out/_next/static/chunks/766-1f2dd8cb7f766b0b.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/onboarding/page-3fdfa60e53f2810d.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/page-e6381e5a6e1fbcfd.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/connect-repos/page-3538dfe0ffe984b8.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/history/{page-b6edd4dde8d08194.js → page-abb9ab2d329f56e9.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/app/layout-c0d118c0f92d969c.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/login/page-c22d080201cbd9fb.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/metrics/page-67a3e98d9a43a6ed.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/page-77e9c65420a06cfb.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/pricing/page-b08ed1c34d14434a.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/providers/page-e88bc117ef7671c3.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/signup/page-68d34f50baa8ab6b.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/e868780c-48e5f147c90a3a41.js +18 -0
- package/dist/dashboard/out/_next/static/chunks/{main-app-5d692157a8eb1fd9.js → main-app-6e8e8d3ef4e0192a.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/{main-c2f423b9c9f4591b.js → main-ed4e1fb6f29c34cf.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/webpack-1cdd8ed57114d5e1.js +1 -0
- package/dist/dashboard/out/_next/static/css/29852f26181969a0.css +1 -0
- package/dist/dashboard/out/_next/static/css/7c3ae9e8617d42a5.css +1 -0
- package/dist/dashboard/out/app/onboarding.html +1 -0
- package/dist/dashboard/out/app/onboarding.txt +7 -0
- package/dist/dashboard/out/app.html +1 -14
- package/dist/dashboard/out/app.txt +2 -2
- package/dist/dashboard/out/connect-repos.html +1 -0
- package/dist/dashboard/out/connect-repos.txt +7 -0
- package/dist/dashboard/out/history.html +1 -1
- package/dist/dashboard/out/history.txt +2 -2
- package/dist/dashboard/out/index.html +1 -1
- package/dist/dashboard/out/index.txt +2 -2
- package/dist/dashboard/out/login.html +6 -0
- package/dist/dashboard/out/login.txt +7 -0
- package/dist/dashboard/out/metrics.html +1 -1
- package/dist/dashboard/out/metrics.txt +2 -2
- package/dist/dashboard/out/pricing.html +3 -3
- package/dist/dashboard/out/pricing.txt +2 -2
- package/dist/dashboard/out/providers.html +1 -0
- package/dist/dashboard/out/providers.txt +7 -0
- package/dist/dashboard/out/signup.html +6 -0
- package/dist/dashboard/out/signup.txt +7 -0
- package/dist/dashboard-server/server.js +1308 -8
- package/dist/hooks/emitter.d.ts +40 -0
- package/dist/hooks/emitter.js +63 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/registry.d.ts +173 -0
- package/dist/hooks/registry.js +476 -0
- package/dist/hooks/trajectory-hooks.d.ts +52 -0
- package/dist/hooks/trajectory-hooks.js +183 -0
- package/dist/hooks/types.d.ts +141 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/memory/adapters/index.d.ts +8 -0
- package/dist/memory/adapters/index.js +8 -0
- package/dist/memory/adapters/inmemory.d.ts +59 -0
- package/dist/memory/adapters/inmemory.js +195 -0
- package/dist/memory/adapters/supermemory.d.ts +71 -0
- package/dist/memory/adapters/supermemory.js +338 -0
- package/dist/memory/factory.d.ts +48 -0
- package/dist/memory/factory.js +143 -0
- package/dist/memory/index.d.ts +32 -0
- package/dist/memory/index.js +32 -0
- package/dist/memory/memory-hooks.d.ts +60 -0
- package/dist/memory/memory-hooks.js +313 -0
- package/dist/memory/service.d.ts +49 -0
- package/dist/memory/service.js +146 -0
- package/dist/memory/types.d.ts +195 -0
- package/dist/memory/types.js +8 -0
- package/dist/policy/agent-policy.d.ts +225 -0
- package/dist/policy/agent-policy.js +665 -0
- package/dist/policy/cloud-policy-fetcher.d.ts +12 -0
- package/dist/policy/cloud-policy-fetcher.js +64 -0
- package/dist/resiliency/crash-insights.d.ts +156 -0
- package/dist/resiliency/crash-insights.js +492 -0
- package/dist/resiliency/gossip-health.d.ts +137 -0
- package/dist/resiliency/gossip-health.js +241 -0
- package/dist/resiliency/index.d.ts +5 -0
- package/dist/resiliency/index.js +5 -0
- package/dist/resiliency/leader-watchdog.d.ts +109 -0
- package/dist/resiliency/leader-watchdog.js +189 -0
- package/dist/resiliency/memory-monitor.d.ts +172 -0
- package/dist/resiliency/memory-monitor.js +593 -0
- package/dist/resiliency/stateless-lead.d.ts +149 -0
- package/dist/resiliency/stateless-lead.js +308 -0
- package/dist/resiliency/supervisor.d.ts +38 -0
- package/dist/resiliency/supervisor.js +122 -0
- package/dist/shared/cli-auth-config.d.ts +91 -0
- package/dist/shared/cli-auth-config.js +264 -0
- package/dist/storage/adapter.d.ts +1 -1
- package/dist/trajectory/config.d.ts +84 -0
- package/dist/trajectory/config.js +163 -0
- package/dist/trajectory/index.d.ts +8 -0
- package/dist/trajectory/index.js +8 -0
- package/dist/trajectory/integration.d.ts +292 -0
- package/dist/trajectory/integration.js +834 -0
- package/dist/utils/logger.js +1 -1
- package/dist/utils/project-namespace.d.ts +24 -0
- package/dist/utils/project-namespace.js +84 -0
- package/dist/wrapper/parser.d.ts +10 -0
- package/dist/wrapper/parser.js +100 -33
- package/dist/wrapper/pty-wrapper.d.ts +197 -16
- package/dist/wrapper/pty-wrapper.js +943 -106
- package/dist/wrapper/shared.d.ts +165 -0
- package/dist/wrapper/shared.js +270 -0
- package/dist/wrapper/tmux-wrapper.d.ts +73 -11
- package/dist/wrapper/tmux-wrapper.js +541 -120
- package/package.json +16 -16
- package/scripts/postinstall.js +60 -0
- package/test-push.txt +1 -0
- package/bin/tmux +0 -0
- package/dist/bridge/config.d.ts.map +0 -1
- package/dist/bridge/config.js.map +0 -1
- package/dist/bridge/index.d.ts.map +0 -1
- package/dist/bridge/index.js.map +0 -1
- package/dist/bridge/multi-project-client.d.ts.map +0 -1
- package/dist/bridge/multi-project-client.js.map +0 -1
- package/dist/bridge/shadow-cli.d.ts.map +0 -1
- package/dist/bridge/shadow-cli.js.map +0 -1
- package/dist/bridge/shadow-config.d.ts.map +0 -1
- package/dist/bridge/shadow-config.js.map +0 -1
- package/dist/bridge/spawner.d.ts.map +0 -1
- package/dist/bridge/spawner.js.map +0 -1
- package/dist/bridge/teams-config.d.ts.map +0 -1
- package/dist/bridge/teams-config.js.map +0 -1
- package/dist/bridge/types.d.ts.map +0 -1
- package/dist/bridge/types.js.map +0 -1
- package/dist/bridge/utils.d.ts.map +0 -1
- package/dist/bridge/utils.js.map +0 -1
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js.map +0 -1
- package/dist/cloud/api/auth.d.ts.map +0 -1
- package/dist/cloud/api/auth.js.map +0 -1
- package/dist/cloud/api/billing.d.ts.map +0 -1
- package/dist/cloud/api/billing.js.map +0 -1
- package/dist/cloud/api/coordinators.d.ts.map +0 -1
- package/dist/cloud/api/coordinators.js.map +0 -1
- package/dist/cloud/api/daemons.d.ts.map +0 -1
- package/dist/cloud/api/daemons.js.map +0 -1
- package/dist/cloud/api/middleware/planLimits.d.ts.map +0 -1
- package/dist/cloud/api/middleware/planLimits.js.map +0 -1
- package/dist/cloud/api/onboarding.d.ts.map +0 -1
- package/dist/cloud/api/onboarding.js.map +0 -1
- package/dist/cloud/api/providers.d.ts.map +0 -1
- package/dist/cloud/api/providers.js.map +0 -1
- package/dist/cloud/api/repos.d.ts.map +0 -1
- package/dist/cloud/api/repos.js.map +0 -1
- package/dist/cloud/api/teams.d.ts.map +0 -1
- package/dist/cloud/api/teams.js.map +0 -1
- package/dist/cloud/api/usage.d.ts.map +0 -1
- package/dist/cloud/api/usage.js.map +0 -1
- package/dist/cloud/api/workspaces.d.ts.map +0 -1
- package/dist/cloud/api/workspaces.js.map +0 -1
- package/dist/cloud/billing/index.d.ts.map +0 -1
- package/dist/cloud/billing/index.js.map +0 -1
- package/dist/cloud/billing/plans.d.ts.map +0 -1
- package/dist/cloud/billing/plans.js.map +0 -1
- package/dist/cloud/billing/service.d.ts.map +0 -1
- package/dist/cloud/billing/service.js.map +0 -1
- package/dist/cloud/billing/types.d.ts.map +0 -1
- package/dist/cloud/billing/types.js.map +0 -1
- package/dist/cloud/config.d.ts.map +0 -1
- package/dist/cloud/config.js.map +0 -1
- package/dist/cloud/db/drizzle.d.ts.map +0 -1
- package/dist/cloud/db/drizzle.js.map +0 -1
- package/dist/cloud/db/index.d.ts.map +0 -1
- package/dist/cloud/db/index.js.map +0 -1
- package/dist/cloud/db/schema.d.ts.map +0 -1
- package/dist/cloud/db/schema.js.map +0 -1
- package/dist/cloud/index.d.ts.map +0 -1
- package/dist/cloud/index.js.map +0 -1
- package/dist/cloud/provisioner/index.d.ts.map +0 -1
- package/dist/cloud/provisioner/index.js.map +0 -1
- package/dist/cloud/server.d.ts.map +0 -1
- package/dist/cloud/server.js.map +0 -1
- package/dist/cloud/services/coordinator.d.ts.map +0 -1
- package/dist/cloud/services/coordinator.js.map +0 -1
- package/dist/cloud/services/planLimits.d.ts.map +0 -1
- package/dist/cloud/services/planLimits.js.map +0 -1
- package/dist/cloud/vault/index.d.ts.map +0 -1
- package/dist/cloud/vault/index.js.map +0 -1
- package/dist/daemon/agent-manager.d.ts.map +0 -1
- package/dist/daemon/agent-manager.js.map +0 -1
- package/dist/daemon/agent-registry.d.ts.map +0 -1
- package/dist/daemon/agent-registry.js.map +0 -1
- package/dist/daemon/api.d.ts.map +0 -1
- package/dist/daemon/api.js.map +0 -1
- package/dist/daemon/auth.d.ts.map +0 -1
- package/dist/daemon/auth.js.map +0 -1
- package/dist/daemon/cloud-sync.d.ts.map +0 -1
- package/dist/daemon/cloud-sync.js.map +0 -1
- package/dist/daemon/connection.d.ts.map +0 -1
- package/dist/daemon/connection.js.map +0 -1
- package/dist/daemon/index.d.ts.map +0 -1
- package/dist/daemon/index.js.map +0 -1
- package/dist/daemon/orchestrator.d.ts.map +0 -1
- package/dist/daemon/orchestrator.js.map +0 -1
- package/dist/daemon/registry.d.ts.map +0 -1
- package/dist/daemon/registry.js.map +0 -1
- package/dist/daemon/router.d.ts.map +0 -1
- package/dist/daemon/router.js.map +0 -1
- package/dist/daemon/server.d.ts.map +0 -1
- package/dist/daemon/server.js.map +0 -1
- package/dist/daemon/types.d.ts.map +0 -1
- package/dist/daemon/types.js.map +0 -1
- package/dist/daemon/workspace-manager.d.ts.map +0 -1
- package/dist/daemon/workspace-manager.js.map +0 -1
- package/dist/dashboard/out/_next/static/chunks/693-7b3301d8f6bc5014.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/713-f78477eb185f1f4d.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/766-e53e1cfe39b0b5b5.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/900-037c64bfd797fb2a.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/app/page-e3d9e1f4466b9bae.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/layout-2433bb48965f4333.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/metrics/page-e68825a81db67ba1.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/page-cc108bf68c8a657f.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/pricing/page-d80e03a5297f95b6.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/webpack-a5acc2831d094776.js +0 -1
- package/dist/dashboard/out/_next/static/css/79b80143647a07d7.css +0 -1
- package/dist/dashboard/out/_next/static/css/8cf277370ad48cfe.css +0 -1
- package/dist/dashboard-server/metrics.d.ts.map +0 -1
- package/dist/dashboard-server/metrics.js.map +0 -1
- package/dist/dashboard-server/needs-attention.d.ts.map +0 -1
- package/dist/dashboard-server/needs-attention.js.map +0 -1
- package/dist/dashboard-server/server.d.ts.map +0 -1
- package/dist/dashboard-server/server.js.map +0 -1
- package/dist/dashboard-server/start.d.ts.map +0 -1
- package/dist/dashboard-server/start.js.map +0 -1
- package/dist/hooks/inbox-check/hook.d.ts.map +0 -1
- package/dist/hooks/inbox-check/hook.js.map +0 -1
- package/dist/hooks/inbox-check/index.d.ts.map +0 -1
- package/dist/hooks/inbox-check/index.js.map +0 -1
- package/dist/hooks/inbox-check/types.d.ts.map +0 -1
- package/dist/hooks/inbox-check/types.js.map +0 -1
- package/dist/hooks/inbox-check/utils.d.ts.map +0 -1
- package/dist/hooks/inbox-check/utils.js.map +0 -1
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/hooks/index.js.map +0 -1
- package/dist/hooks/types.d.ts.map +0 -1
- package/dist/hooks/types.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/protocol/framing.d.ts.map +0 -1
- package/dist/protocol/framing.js.map +0 -1
- package/dist/protocol/index.d.ts.map +0 -1
- package/dist/protocol/index.js.map +0 -1
- package/dist/protocol/types.d.ts.map +0 -1
- package/dist/protocol/types.js.map +0 -1
- package/dist/resiliency/context-persistence.d.ts.map +0 -1
- package/dist/resiliency/context-persistence.js.map +0 -1
- package/dist/resiliency/health-monitor.d.ts.map +0 -1
- package/dist/resiliency/health-monitor.js.map +0 -1
- package/dist/resiliency/index.d.ts.map +0 -1
- package/dist/resiliency/index.js.map +0 -1
- package/dist/resiliency/logger.d.ts.map +0 -1
- package/dist/resiliency/logger.js.map +0 -1
- package/dist/resiliency/metrics.d.ts.map +0 -1
- package/dist/resiliency/metrics.js.map +0 -1
- package/dist/resiliency/provider-context.d.ts.map +0 -1
- package/dist/resiliency/provider-context.js.map +0 -1
- package/dist/resiliency/supervisor.d.ts.map +0 -1
- package/dist/resiliency/supervisor.js.map +0 -1
- package/dist/state/agent-state.d.ts.map +0 -1
- package/dist/state/agent-state.js.map +0 -1
- package/dist/storage/adapter.d.ts.map +0 -1
- package/dist/storage/adapter.js.map +0 -1
- package/dist/storage/sqlite-adapter.d.ts.map +0 -1
- package/dist/storage/sqlite-adapter.js.map +0 -1
- package/dist/utils/agent-config.d.ts.map +0 -1
- package/dist/utils/agent-config.js.map +0 -1
- package/dist/utils/command-resolver.d.ts.map +0 -1
- package/dist/utils/command-resolver.js.map +0 -1
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/name-generator.d.ts.map +0 -1
- package/dist/utils/name-generator.js.map +0 -1
- package/dist/utils/project-namespace.d.ts.map +0 -1
- package/dist/utils/project-namespace.js.map +0 -1
- package/dist/utils/tmux-resolver.d.ts.map +0 -1
- package/dist/utils/tmux-resolver.js.map +0 -1
- package/dist/utils/update-checker.d.ts.map +0 -1
- package/dist/utils/update-checker.js.map +0 -1
- package/dist/wrapper/client.d.ts.map +0 -1
- package/dist/wrapper/client.js.map +0 -1
- package/dist/wrapper/inbox.d.ts.map +0 -1
- package/dist/wrapper/inbox.js.map +0 -1
- package/dist/wrapper/index.d.ts.map +0 -1
- package/dist/wrapper/index.js.map +0 -1
- package/dist/wrapper/parser.d.ts.map +0 -1
- package/dist/wrapper/parser.js.map +0 -1
- package/dist/wrapper/pty-wrapper.d.ts.map +0 -1
- package/dist/wrapper/pty-wrapper.js.map +0 -1
- package/dist/wrapper/tmux-wrapper.d.ts.map +0 -1
- package/dist/wrapper/tmux-wrapper.js.map +0 -1
- package/docs/AGENTS.md +0 -513
- package/docs/ARCHITECTURE_DECISIONS.md +0 -175
- package/docs/CHANGELOG.md +0 -11
- package/docs/CLI-SIMPLIFICATION-COMPLETE.md +0 -48
- package/docs/CLOUD-ARCHITECTURE.md +0 -652
- package/docs/CLOUD-ONBOARDING-DESIGN.md +0 -1983
- package/docs/COMPETITIVE_ANALYSIS.md +0 -897
- package/docs/CONTRIBUTING.md +0 -151
- package/docs/DESIGN_BRIDGE_STAFFING.md +0 -878
- package/docs/DESIGN_V2.md +0 -1079
- package/docs/INTEGRATION-GUIDE.md +0 -926
- package/docs/MONETIZATION.md +0 -1679
- package/docs/PROPOSAL-trajectories.md +0 -1582
- package/docs/PROTOCOL.md +0 -325
- package/docs/SCALING_ANALYSIS.md +0 -280
- package/docs/TESTING_PRESENCE_FEATURES.md +0 -327
- package/docs/TMUX_IMPLEMENTATION_NOTES.md +0 -364
- package/docs/TMUX_IMPROVEMENTS.md +0 -968
- package/docs/agent-relay-snippet.md +0 -168
- package/docs/competitive-analysis-mcp-agent-mail.md +0 -389
- package/docs/dashboard-v2-plan.md +0 -179
- package/docs/guides/CLOUD.md +0 -236
- package/docs/guides/LOCAL.md +0 -535
- package/docs/guides/SELF-HOSTED.md +0 -494
- package/docs/proposals/shadow-as-subagent.md +0 -765
- package/docs/proposals/slack-bot-integration.md +0 -1457
- package/docs/removable-code-analysis.md +0 -24
- package/scripts/dev/PUBLIC_RELEASE_PLAN.md +0 -88
- package/scripts/dev/dev-team-setup.sh +0 -431
- package/scripts/e2e-test.sh +0 -119
- package/scripts/games/game-protocol.md +0 -79
- package/scripts/games/hearts-setup.sh +0 -264
- package/scripts/tictactoe-setup.sh +0 -181
- /package/dist/dashboard/out/_next/static/chunks/{117-b2cd8d6485aacf2b.js → 117-f7b8ab0809342e77.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{648-8f3f26864ce515e5.js → 648-5cc6e1921389a58a.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/app/_not-found/{page-0b990dbb71d72a98.js → page-53b8a69f76db17d0.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{fd9d1056-bf46c09eb57e019c.js → fd9d1056-609918ca7b6280bb.js} +0 -0
- /package/dist/dashboard/out/_next/static/{6HHWb2ZmnJ4OSm0zUP7h4 → wPgKJtcOmTFLpUncDg16A}/_buildManifest.js +0 -0
- /package/dist/dashboard/out/_next/static/{6HHWb2ZmnJ4OSm0zUP7h4 → wPgKJtcOmTFLpUncDg16A}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Policy API Routes
|
|
3
|
+
*
|
|
4
|
+
* Provides endpoints for managing workspace-level agent policies.
|
|
5
|
+
* These policies serve as fallbacks when repos don't have .claude/policies/ files.
|
|
6
|
+
*/
|
|
7
|
+
import { Router } from 'express';
|
|
8
|
+
import { db } from '../db/index.js';
|
|
9
|
+
export const policyRouter = Router();
|
|
10
|
+
/**
|
|
11
|
+
* GET /api/policy/:workspaceId
|
|
12
|
+
* Get the agent policy for a workspace
|
|
13
|
+
*/
|
|
14
|
+
policyRouter.get('/:workspaceId', async (req, res) => {
|
|
15
|
+
const { workspaceId } = req.params;
|
|
16
|
+
const userId = req.userId;
|
|
17
|
+
if (!userId) {
|
|
18
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const workspace = await db.workspaces.findById(workspaceId);
|
|
22
|
+
if (!workspace) {
|
|
23
|
+
return res.status(404).json({ error: 'Workspace not found' });
|
|
24
|
+
}
|
|
25
|
+
// Check user has access to this workspace
|
|
26
|
+
if (workspace.userId !== userId) {
|
|
27
|
+
const members = await db.workspaceMembers.findByWorkspaceId(workspaceId);
|
|
28
|
+
const member = members.find(m => m.userId === userId);
|
|
29
|
+
if (!member) {
|
|
30
|
+
return res.status(403).json({ error: 'Access denied' });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Return the policy (or default if not set)
|
|
34
|
+
const policy = workspace.config?.agentPolicy ?? getDefaultPolicy();
|
|
35
|
+
res.json({
|
|
36
|
+
workspaceId,
|
|
37
|
+
policy,
|
|
38
|
+
source: workspace.config?.agentPolicy ? 'workspace' : 'default',
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
console.error('[policy] Error getting policy:', error);
|
|
43
|
+
res.status(500).json({ error: 'Failed to get policy' });
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
/**
|
|
47
|
+
* PUT /api/policy/:workspaceId
|
|
48
|
+
* Update the agent policy for a workspace
|
|
49
|
+
*/
|
|
50
|
+
policyRouter.put('/:workspaceId', async (req, res) => {
|
|
51
|
+
const { workspaceId } = req.params;
|
|
52
|
+
const userId = req.userId;
|
|
53
|
+
const policy = req.body.policy;
|
|
54
|
+
if (!userId) {
|
|
55
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
56
|
+
}
|
|
57
|
+
if (!policy || typeof policy !== 'object') {
|
|
58
|
+
return res.status(400).json({ error: 'Policy object is required' });
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const workspace = await db.workspaces.findById(workspaceId);
|
|
62
|
+
if (!workspace) {
|
|
63
|
+
return res.status(404).json({ error: 'Workspace not found' });
|
|
64
|
+
}
|
|
65
|
+
// Only owner can update policy
|
|
66
|
+
if (workspace.userId !== userId) {
|
|
67
|
+
const members = await db.workspaceMembers.findByWorkspaceId(workspaceId);
|
|
68
|
+
const member = members.find(m => m.userId === userId);
|
|
69
|
+
if (!member || !['owner', 'admin'].includes(member.role)) {
|
|
70
|
+
return res.status(403).json({ error: 'Only owners and admins can update policy' });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Validate policy structure
|
|
74
|
+
const validationError = validatePolicy(policy);
|
|
75
|
+
if (validationError) {
|
|
76
|
+
return res.status(400).json({ error: validationError });
|
|
77
|
+
}
|
|
78
|
+
// Update workspace config with new policy
|
|
79
|
+
const newConfig = {
|
|
80
|
+
...workspace.config,
|
|
81
|
+
agentPolicy: policy,
|
|
82
|
+
};
|
|
83
|
+
await db.workspaces.updateConfig(workspaceId, newConfig);
|
|
84
|
+
res.json({
|
|
85
|
+
success: true,
|
|
86
|
+
workspaceId,
|
|
87
|
+
policy,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
console.error('[policy] Error updating policy:', error);
|
|
92
|
+
res.status(500).json({ error: 'Failed to update policy' });
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
/**
|
|
96
|
+
* DELETE /api/policy/:workspaceId
|
|
97
|
+
* Reset workspace policy to defaults
|
|
98
|
+
*/
|
|
99
|
+
policyRouter.delete('/:workspaceId', async (req, res) => {
|
|
100
|
+
const { workspaceId } = req.params;
|
|
101
|
+
const userId = req.userId;
|
|
102
|
+
if (!userId) {
|
|
103
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
const workspace = await db.workspaces.findById(workspaceId);
|
|
107
|
+
if (!workspace) {
|
|
108
|
+
return res.status(404).json({ error: 'Workspace not found' });
|
|
109
|
+
}
|
|
110
|
+
// Only owner can reset policy
|
|
111
|
+
if (workspace.userId !== userId) {
|
|
112
|
+
const members = await db.workspaceMembers.findByWorkspaceId(workspaceId);
|
|
113
|
+
const member = members.find(m => m.userId === userId);
|
|
114
|
+
if (!member || member.role !== 'owner') {
|
|
115
|
+
return res.status(403).json({ error: 'Only owners can reset policy' });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Remove policy from config
|
|
119
|
+
const { agentPolicy: _agentPolicy, ...restConfig } = workspace.config ?? {};
|
|
120
|
+
await db.workspaces.updateConfig(workspaceId, restConfig);
|
|
121
|
+
res.json({
|
|
122
|
+
success: true,
|
|
123
|
+
workspaceId,
|
|
124
|
+
policy: getDefaultPolicy(),
|
|
125
|
+
source: 'default',
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
console.error('[policy] Error resetting policy:', error);
|
|
130
|
+
res.status(500).json({ error: 'Failed to reset policy' });
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
/**
|
|
134
|
+
* GET /api/policy/:workspaceId/internal
|
|
135
|
+
* Internal endpoint for workspace containers to fetch policy
|
|
136
|
+
* Uses workspace token authentication (not user auth)
|
|
137
|
+
*/
|
|
138
|
+
policyRouter.get('/:workspaceId/internal', async (req, res) => {
|
|
139
|
+
const { workspaceId } = req.params;
|
|
140
|
+
// This endpoint should be called with the workspace token
|
|
141
|
+
// The git.ts file has the token verification logic we can reuse
|
|
142
|
+
// For now, we'll trust the workspace ID from container requests
|
|
143
|
+
try {
|
|
144
|
+
const workspace = await db.workspaces.findById(workspaceId);
|
|
145
|
+
if (!workspace) {
|
|
146
|
+
return res.status(404).json({ error: 'Workspace not found' });
|
|
147
|
+
}
|
|
148
|
+
const policy = workspace.config?.agentPolicy ?? getDefaultPolicy();
|
|
149
|
+
res.json({
|
|
150
|
+
defaultPolicy: policy.defaultPolicy,
|
|
151
|
+
agents: policy.agents ?? [],
|
|
152
|
+
settings: policy.settings ?? {
|
|
153
|
+
requireExplicitAgents: false,
|
|
154
|
+
auditEnabled: true,
|
|
155
|
+
maxTotalAgents: 50,
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
console.error('[policy] Error getting internal policy:', error);
|
|
161
|
+
res.status(500).json({ error: 'Failed to get policy' });
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
/**
|
|
165
|
+
* Get default policy
|
|
166
|
+
*/
|
|
167
|
+
function getDefaultPolicy() {
|
|
168
|
+
return {
|
|
169
|
+
defaultPolicy: {
|
|
170
|
+
name: '*',
|
|
171
|
+
allowedTools: undefined, // All tools allowed
|
|
172
|
+
canSpawn: undefined, // Can spawn any
|
|
173
|
+
canMessage: undefined, // Can message any
|
|
174
|
+
maxSpawns: 10,
|
|
175
|
+
rateLimit: 60,
|
|
176
|
+
canBeSpawned: true,
|
|
177
|
+
},
|
|
178
|
+
agents: [],
|
|
179
|
+
settings: {
|
|
180
|
+
requireExplicitAgents: false,
|
|
181
|
+
auditEnabled: true,
|
|
182
|
+
maxTotalAgents: 50,
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Validate policy structure
|
|
188
|
+
*/
|
|
189
|
+
function validatePolicy(policy) {
|
|
190
|
+
// Validate defaultPolicy
|
|
191
|
+
if (policy.defaultPolicy && typeof policy.defaultPolicy !== 'object') {
|
|
192
|
+
return 'defaultPolicy must be an object';
|
|
193
|
+
}
|
|
194
|
+
// Validate agents array
|
|
195
|
+
if (policy.agents) {
|
|
196
|
+
if (!Array.isArray(policy.agents)) {
|
|
197
|
+
return 'agents must be an array';
|
|
198
|
+
}
|
|
199
|
+
for (let i = 0; i < policy.agents.length; i++) {
|
|
200
|
+
const agent = policy.agents[i];
|
|
201
|
+
if (!agent.name || typeof agent.name !== 'string') {
|
|
202
|
+
return `agents[${i}].name is required and must be a string`;
|
|
203
|
+
}
|
|
204
|
+
// Validate arrays
|
|
205
|
+
if (agent.allowedTools && !Array.isArray(agent.allowedTools)) {
|
|
206
|
+
return `agents[${i}].allowedTools must be an array`;
|
|
207
|
+
}
|
|
208
|
+
if (agent.canSpawn && !Array.isArray(agent.canSpawn)) {
|
|
209
|
+
return `agents[${i}].canSpawn must be an array`;
|
|
210
|
+
}
|
|
211
|
+
if (agent.canMessage && !Array.isArray(agent.canMessage)) {
|
|
212
|
+
return `agents[${i}].canMessage must be an array`;
|
|
213
|
+
}
|
|
214
|
+
// Validate numbers
|
|
215
|
+
if (agent.maxSpawns !== undefined && typeof agent.maxSpawns !== 'number') {
|
|
216
|
+
return `agents[${i}].maxSpawns must be a number`;
|
|
217
|
+
}
|
|
218
|
+
if (agent.rateLimit !== undefined && typeof agent.rateLimit !== 'number') {
|
|
219
|
+
return `agents[${i}].rateLimit must be a number`;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// Validate settings
|
|
224
|
+
if (policy.settings && typeof policy.settings !== 'object') {
|
|
225
|
+
return 'settings must be an object';
|
|
226
|
+
}
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -13,52 +13,47 @@ import { vault } from '../vault/index.js';
|
|
|
13
13
|
export const providersRouter = Router();
|
|
14
14
|
// All routes require authentication
|
|
15
15
|
providersRouter.use(requireAuth);
|
|
16
|
-
/**
|
|
17
|
-
* Provider registry with OAuth/device flow configuration
|
|
18
|
-
*
|
|
19
|
-
* Auth Strategy:
|
|
20
|
-
* - google: Real OAuth device flow (works today)
|
|
21
|
-
* - anthropic: CLI-based auth (user runs `claude login`, we detect credentials)
|
|
22
|
-
* - openai: CLI-based auth (user runs `codex auth`, we detect credentials)
|
|
23
|
-
*
|
|
24
|
-
* When providers add OAuth support, we can switch to device flow.
|
|
25
|
-
*/
|
|
26
16
|
const PROVIDERS = {
|
|
27
17
|
anthropic: {
|
|
28
18
|
name: 'Anthropic',
|
|
29
19
|
displayName: 'Claude',
|
|
30
20
|
description: 'Claude Code - recommended for code tasks',
|
|
31
|
-
// Auth strategy: CLI-based until Anthropic adds OAuth
|
|
32
21
|
authStrategy: 'cli',
|
|
33
|
-
cliCommand: 'claude
|
|
34
|
-
credentialPath: '~/.claude/credentials.json',
|
|
35
|
-
// Future OAuth endpoints (hypothetical - for when Anthropic implements)
|
|
36
|
-
deviceCodeUrl: 'https://api.anthropic.com/oauth/device/code',
|
|
37
|
-
tokenUrl: 'https://api.anthropic.com/oauth/token',
|
|
38
|
-
userInfoUrl: 'https://api.anthropic.com/v1/user',
|
|
39
|
-
scopes: ['claude-code:execute', 'user:read'],
|
|
22
|
+
cliCommand: 'claude',
|
|
23
|
+
credentialPath: '~/.claude/credentials.json',
|
|
40
24
|
color: '#D97757',
|
|
41
25
|
},
|
|
42
|
-
|
|
26
|
+
codex: {
|
|
43
27
|
name: 'OpenAI',
|
|
44
28
|
displayName: 'Codex',
|
|
45
|
-
description: 'Codex
|
|
46
|
-
// Auth strategy: CLI-based until OpenAI adds OAuth
|
|
29
|
+
description: 'Codex - OpenAI coding assistant',
|
|
47
30
|
authStrategy: 'cli',
|
|
48
|
-
cliCommand: 'codex
|
|
31
|
+
cliCommand: 'codex login',
|
|
49
32
|
credentialPath: '~/.codex/credentials.json',
|
|
50
|
-
// Future OAuth endpoints (hypothetical)
|
|
51
|
-
deviceCodeUrl: 'https://auth.openai.com/device/code',
|
|
52
|
-
tokenUrl: 'https://auth.openai.com/oauth/token',
|
|
53
|
-
userInfoUrl: 'https://api.openai.com/v1/user',
|
|
54
|
-
scopes: ['openid', 'profile', 'email', 'codex:execute'],
|
|
55
33
|
color: '#10A37F',
|
|
56
34
|
},
|
|
35
|
+
opencode: {
|
|
36
|
+
name: 'OpenCode',
|
|
37
|
+
displayName: 'OpenCode',
|
|
38
|
+
description: 'OpenCode - AI coding assistant',
|
|
39
|
+
authStrategy: 'cli',
|
|
40
|
+
cliCommand: 'opencode',
|
|
41
|
+
credentialPath: '~/.opencode/credentials.json',
|
|
42
|
+
color: '#00D4AA',
|
|
43
|
+
},
|
|
44
|
+
droid: {
|
|
45
|
+
name: 'Factory',
|
|
46
|
+
displayName: 'Droid',
|
|
47
|
+
description: 'Droid - Factory AI coding agent',
|
|
48
|
+
authStrategy: 'cli',
|
|
49
|
+
cliCommand: 'droid',
|
|
50
|
+
credentialPath: '~/.factory/credentials.json',
|
|
51
|
+
color: '#6366F1',
|
|
52
|
+
},
|
|
57
53
|
google: {
|
|
58
54
|
name: 'Google',
|
|
59
55
|
displayName: 'Gemini',
|
|
60
56
|
description: 'Gemini - multi-modal capabilities',
|
|
61
|
-
// Auth strategy: Real OAuth device flow (works today!)
|
|
62
57
|
authStrategy: 'device_flow',
|
|
63
58
|
deviceCodeUrl: 'https://oauth2.googleapis.com/device/code',
|
|
64
59
|
tokenUrl: 'https://oauth2.googleapis.com/token',
|
|
@@ -67,6 +62,10 @@ const PROVIDERS = {
|
|
|
67
62
|
color: '#4285F4',
|
|
68
63
|
},
|
|
69
64
|
};
|
|
65
|
+
// Type guard for device flow providers
|
|
66
|
+
function isDeviceFlowProvider(provider) {
|
|
67
|
+
return provider.authStrategy === 'device_flow';
|
|
68
|
+
}
|
|
70
69
|
let redisClient = null;
|
|
71
70
|
async function getRedisClient() {
|
|
72
71
|
if (!redisClient) {
|
|
@@ -171,7 +170,12 @@ providersRouter.post('/:provider/connect', async (req, res) => {
|
|
|
171
170
|
});
|
|
172
171
|
}
|
|
173
172
|
// Device flow auth (Google) - start OAuth device flow
|
|
174
|
-
|
|
173
|
+
// At this point, we know it's a device flow provider (CLI was handled above)
|
|
174
|
+
if (!isDeviceFlowProvider(providerConfig)) {
|
|
175
|
+
return res.status(400).json({ error: 'Provider does not support device flow' });
|
|
176
|
+
}
|
|
177
|
+
// Only google is configured for device flow in config
|
|
178
|
+
const clientConfig = provider === 'google' ? config.providers.google : undefined;
|
|
175
179
|
if (!clientConfig) {
|
|
176
180
|
return res.status(400).json({ error: `Provider ${provider} not configured` });
|
|
177
181
|
}
|
|
@@ -245,7 +249,7 @@ providersRouter.post('/:provider/verify', async (req, res) => {
|
|
|
245
249
|
userId,
|
|
246
250
|
provider,
|
|
247
251
|
accessToken: 'cli-authenticated', // Placeholder - real token from CLI
|
|
248
|
-
scopes:
|
|
252
|
+
scopes: [], // CLI auth doesn't use scopes
|
|
249
253
|
providerAccountEmail: req.body.email, // User can optionally provide
|
|
250
254
|
});
|
|
251
255
|
res.json({
|
|
@@ -259,6 +263,67 @@ providersRouter.post('/:provider/verify', async (req, res) => {
|
|
|
259
263
|
res.status(500).json({ error: 'Failed to verify connection' });
|
|
260
264
|
}
|
|
261
265
|
});
|
|
266
|
+
/**
|
|
267
|
+
* POST /api/providers/:provider/api-key
|
|
268
|
+
* Connect a provider using an API key (for cloud-hosted workspaces)
|
|
269
|
+
*/
|
|
270
|
+
providersRouter.post('/:provider/api-key', async (req, res) => {
|
|
271
|
+
const { provider } = req.params;
|
|
272
|
+
const userId = req.session.userId;
|
|
273
|
+
const { apiKey } = req.body;
|
|
274
|
+
if (!apiKey || typeof apiKey !== 'string') {
|
|
275
|
+
return res.status(400).json({ error: 'API key is required' });
|
|
276
|
+
}
|
|
277
|
+
const providerConfig = PROVIDERS[provider];
|
|
278
|
+
if (!providerConfig) {
|
|
279
|
+
return res.status(404).json({ error: 'Unknown provider' });
|
|
280
|
+
}
|
|
281
|
+
// Validate the API key by making a test request
|
|
282
|
+
try {
|
|
283
|
+
let isValid = false;
|
|
284
|
+
if (provider === 'anthropic') {
|
|
285
|
+
// Test Anthropic API key
|
|
286
|
+
const testRes = await fetch('https://api.anthropic.com/v1/messages', {
|
|
287
|
+
method: 'POST',
|
|
288
|
+
headers: {
|
|
289
|
+
'Content-Type': 'application/json',
|
|
290
|
+
'x-api-key': apiKey,
|
|
291
|
+
'anthropic-version': '2023-06-01',
|
|
292
|
+
},
|
|
293
|
+
body: JSON.stringify({
|
|
294
|
+
model: 'claude-3-haiku-20240307',
|
|
295
|
+
max_tokens: 1,
|
|
296
|
+
messages: [{ role: 'user', content: 'hi' }],
|
|
297
|
+
}),
|
|
298
|
+
});
|
|
299
|
+
// 200 = valid, 401 = invalid key, 400/other = might still be valid key
|
|
300
|
+
isValid = testRes.status !== 401;
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
// For other providers, just accept the key
|
|
304
|
+
isValid = true;
|
|
305
|
+
}
|
|
306
|
+
if (!isValid) {
|
|
307
|
+
return res.status(400).json({ error: 'Invalid API key' });
|
|
308
|
+
}
|
|
309
|
+
// Store the API key - use scopes from device flow providers, empty for CLI providers
|
|
310
|
+
const scopes = isDeviceFlowProvider(providerConfig) ? providerConfig.scopes : [];
|
|
311
|
+
await vault.storeCredential({
|
|
312
|
+
userId,
|
|
313
|
+
provider,
|
|
314
|
+
accessToken: apiKey,
|
|
315
|
+
scopes,
|
|
316
|
+
});
|
|
317
|
+
res.json({
|
|
318
|
+
success: true,
|
|
319
|
+
message: `${providerConfig.displayName} connected`,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
catch (error) {
|
|
323
|
+
console.error(`Error connecting ${provider} with API key:`, error);
|
|
324
|
+
res.status(500).json({ error: 'Failed to connect provider' });
|
|
325
|
+
}
|
|
326
|
+
});
|
|
262
327
|
/**
|
|
263
328
|
* GET /api/providers/:provider/status/:flowId
|
|
264
329
|
* Check status of device flow
|
|
@@ -329,6 +394,11 @@ providersRouter.delete('/:provider/flow/:flowId', (req, res) => {
|
|
|
329
394
|
*/
|
|
330
395
|
async function pollForToken(flowId, provider, clientId) {
|
|
331
396
|
const providerConfig = PROVIDERS[provider];
|
|
397
|
+
// Only device flow providers can poll for tokens
|
|
398
|
+
if (!isDeviceFlowProvider(providerConfig)) {
|
|
399
|
+
console.error(`Provider ${provider} does not support device flow polling`);
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
332
402
|
const poll = async (intervalMs) => {
|
|
333
403
|
const current = await loadFlow(flowId);
|
|
334
404
|
if (!current || current.status !== 'pending')
|
|
@@ -403,20 +473,22 @@ async function pollForToken(flowId, provider, clientId) {
|
|
|
403
473
|
*/
|
|
404
474
|
async function storeProviderTokens(userId, provider, tokens) {
|
|
405
475
|
const providerConfig = PROVIDERS[provider];
|
|
406
|
-
// Fetch user info from provider
|
|
476
|
+
// Fetch user info from provider (only device flow providers have userInfoUrl)
|
|
407
477
|
let userInfo = {};
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
478
|
+
if (isDeviceFlowProvider(providerConfig)) {
|
|
479
|
+
try {
|
|
480
|
+
const response = await fetch(providerConfig.userInfoUrl, {
|
|
481
|
+
headers: {
|
|
482
|
+
Authorization: `Bearer ${tokens.accessToken}`,
|
|
483
|
+
},
|
|
484
|
+
});
|
|
485
|
+
if (response.ok) {
|
|
486
|
+
userInfo = await response.json();
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
catch (error) {
|
|
490
|
+
console.error('Error fetching user info:', error);
|
|
416
491
|
}
|
|
417
|
-
}
|
|
418
|
-
catch (error) {
|
|
419
|
-
console.error('Error fetching user info:', error);
|
|
420
492
|
}
|
|
421
493
|
// Encrypt and store
|
|
422
494
|
await vault.storeCredential({
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Repos API Routes
|
|
3
3
|
*
|
|
4
4
|
* GitHub repository management - list, import, sync.
|
|
5
|
+
* Includes Nango-based GitHub permission checking for dashboard access control.
|
|
5
6
|
*/
|
|
6
7
|
export declare const reposRouter: import("express-serve-static-core").Router;
|
|
7
8
|
//# sourceMappingURL=repos.d.ts.map
|
package/dist/cloud/api/repos.js
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
* Repos API Routes
|
|
3
3
|
*
|
|
4
4
|
* GitHub repository management - list, import, sync.
|
|
5
|
+
* Includes Nango-based GitHub permission checking for dashboard access control.
|
|
5
6
|
*/
|
|
6
7
|
import { Router } from 'express';
|
|
7
8
|
import { requireAuth } from './auth.js';
|
|
8
9
|
import { db } from '../db/index.js';
|
|
10
|
+
import { nangoService } from '../services/nango.js';
|
|
9
11
|
export const reposRouter = Router();
|
|
10
12
|
// All routes require authentication
|
|
11
13
|
reposRouter.use(requireAuth);
|
|
@@ -311,4 +313,188 @@ reposRouter.get('/search', async (req, res) => {
|
|
|
311
313
|
res.status(500).json({ error: 'Failed to search repositories' });
|
|
312
314
|
}
|
|
313
315
|
});
|
|
316
|
+
// ============================================================================
|
|
317
|
+
// Nango-based GitHub Permission APIs (for dashboard access control)
|
|
318
|
+
// ============================================================================
|
|
319
|
+
/**
|
|
320
|
+
* GET /api/repos/check-access/:owner/:repo
|
|
321
|
+
* Check if authenticated user has access to a specific GitHub repository.
|
|
322
|
+
* Uses Nango proxy with user's GitHub OAuth token.
|
|
323
|
+
*
|
|
324
|
+
* Response:
|
|
325
|
+
* - hasAccess: boolean - Whether user can access this repo
|
|
326
|
+
* - permission: 'admin' | 'write' | 'read' | 'none' - User's permission level
|
|
327
|
+
* - repository: Repository details if user has access
|
|
328
|
+
*
|
|
329
|
+
* Use this for dashboard access control - grant access if hasAccess is true.
|
|
330
|
+
*/
|
|
331
|
+
reposRouter.get('/check-access/:owner/:repo', async (req, res) => {
|
|
332
|
+
const userId = req.session.userId;
|
|
333
|
+
const { owner, repo } = req.params;
|
|
334
|
+
if (!owner || !repo) {
|
|
335
|
+
return res.status(400).json({ error: 'Owner and repo parameters are required' });
|
|
336
|
+
}
|
|
337
|
+
try {
|
|
338
|
+
// Get user's Nango connection ID
|
|
339
|
+
const user = await db.users.findById(userId);
|
|
340
|
+
if (!user) {
|
|
341
|
+
return res.status(404).json({ error: 'User not found' });
|
|
342
|
+
}
|
|
343
|
+
if (!user.nangoConnectionId) {
|
|
344
|
+
return res.status(400).json({
|
|
345
|
+
error: 'GitHub not connected via Nango',
|
|
346
|
+
code: 'NANGO_NOT_CONNECTED',
|
|
347
|
+
message: 'Please reconnect your GitHub account',
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
// Check access via Nango proxy
|
|
351
|
+
const accessResult = await nangoService.checkUserRepoAccess(user.nangoConnectionId, owner, repo);
|
|
352
|
+
res.json({
|
|
353
|
+
hasAccess: accessResult.hasAccess,
|
|
354
|
+
permission: accessResult.permission,
|
|
355
|
+
repository: accessResult.repository,
|
|
356
|
+
// Include user info for dashboard context
|
|
357
|
+
checkedBy: {
|
|
358
|
+
userId: user.id,
|
|
359
|
+
githubUsername: user.githubUsername,
|
|
360
|
+
},
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
console.error('Error checking repo access:', error);
|
|
365
|
+
res.status(500).json({ error: 'Failed to check repository access' });
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
/**
|
|
369
|
+
* GET /api/repos/accessible
|
|
370
|
+
* List all GitHub repositories the authenticated user has access to.
|
|
371
|
+
* Uses Nango proxy with user's GitHub OAuth token.
|
|
372
|
+
*
|
|
373
|
+
* Query params:
|
|
374
|
+
* - page: Page number (default: 1)
|
|
375
|
+
* - perPage: Results per page (default: 100, max: 100)
|
|
376
|
+
* - type: Filter by type (all, owner, public, private, member)
|
|
377
|
+
* - sort: Sort by (created, updated, pushed, full_name)
|
|
378
|
+
*
|
|
379
|
+
* Use this to determine which dashboards/workspaces a user can access.
|
|
380
|
+
*/
|
|
381
|
+
reposRouter.get('/accessible', async (req, res) => {
|
|
382
|
+
const userId = req.session.userId;
|
|
383
|
+
const { page, perPage, type, sort } = req.query;
|
|
384
|
+
try {
|
|
385
|
+
// Get user's Nango connection ID
|
|
386
|
+
const user = await db.users.findById(userId);
|
|
387
|
+
if (!user) {
|
|
388
|
+
return res.status(404).json({ error: 'User not found' });
|
|
389
|
+
}
|
|
390
|
+
if (!user.nangoConnectionId) {
|
|
391
|
+
return res.status(400).json({
|
|
392
|
+
error: 'GitHub not connected via Nango',
|
|
393
|
+
code: 'NANGO_NOT_CONNECTED',
|
|
394
|
+
message: 'Please reconnect your GitHub account',
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
// List accessible repos via Nango proxy
|
|
398
|
+
const result = await nangoService.listUserAccessibleRepos(user.nangoConnectionId, {
|
|
399
|
+
page: page ? parseInt(page, 10) : undefined,
|
|
400
|
+
perPage: perPage ? Math.min(parseInt(perPage, 10), 100) : undefined,
|
|
401
|
+
type: type,
|
|
402
|
+
sort: sort,
|
|
403
|
+
});
|
|
404
|
+
res.json({
|
|
405
|
+
repositories: result.repositories,
|
|
406
|
+
pagination: {
|
|
407
|
+
page: page ? parseInt(page, 10) : 1,
|
|
408
|
+
perPage: perPage ? Math.min(parseInt(perPage, 10), 100) : 100,
|
|
409
|
+
hasMore: result.hasMore,
|
|
410
|
+
},
|
|
411
|
+
// Include user info for context
|
|
412
|
+
checkedBy: {
|
|
413
|
+
userId: user.id,
|
|
414
|
+
githubUsername: user.githubUsername,
|
|
415
|
+
},
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
catch (error) {
|
|
419
|
+
console.error('Error listing accessible repos:', error);
|
|
420
|
+
res.status(500).json({ error: 'Failed to list accessible repositories' });
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
/**
|
|
424
|
+
* POST /api/repos/check-access-bulk
|
|
425
|
+
* Check access to multiple repositories at once.
|
|
426
|
+
* Useful for determining which workspaces a user can view.
|
|
427
|
+
*
|
|
428
|
+
* Body:
|
|
429
|
+
* - repositories: Array of "owner/repo" strings
|
|
430
|
+
*
|
|
431
|
+
* Response:
|
|
432
|
+
* - results: Array of { fullName, hasAccess, permission }
|
|
433
|
+
*/
|
|
434
|
+
reposRouter.post('/check-access-bulk', async (req, res) => {
|
|
435
|
+
const userId = req.session.userId;
|
|
436
|
+
const { repositories } = req.body;
|
|
437
|
+
if (!repositories || !Array.isArray(repositories)) {
|
|
438
|
+
return res.status(400).json({ error: 'repositories array is required' });
|
|
439
|
+
}
|
|
440
|
+
if (repositories.length > 50) {
|
|
441
|
+
return res.status(400).json({ error: 'Maximum 50 repositories per request' });
|
|
442
|
+
}
|
|
443
|
+
try {
|
|
444
|
+
// Get user's Nango connection ID
|
|
445
|
+
const user = await db.users.findById(userId);
|
|
446
|
+
if (!user) {
|
|
447
|
+
return res.status(404).json({ error: 'User not found' });
|
|
448
|
+
}
|
|
449
|
+
if (!user.nangoConnectionId) {
|
|
450
|
+
return res.status(400).json({
|
|
451
|
+
error: 'GitHub not connected via Nango',
|
|
452
|
+
code: 'NANGO_NOT_CONNECTED',
|
|
453
|
+
message: 'Please reconnect your GitHub account',
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
// Check access for each repo (in parallel with concurrency limit)
|
|
457
|
+
const results = [];
|
|
458
|
+
// Process in batches of 10 to avoid rate limiting
|
|
459
|
+
const batchSize = 10;
|
|
460
|
+
for (let i = 0; i < repositories.length; i += batchSize) {
|
|
461
|
+
const batch = repositories.slice(i, i + batchSize);
|
|
462
|
+
const batchResults = await Promise.all(batch.map(async (fullName) => {
|
|
463
|
+
try {
|
|
464
|
+
const [owner, repo] = fullName.split('/');
|
|
465
|
+
if (!owner || !repo) {
|
|
466
|
+
return { fullName, hasAccess: false, error: 'Invalid repository format' };
|
|
467
|
+
}
|
|
468
|
+
const accessResult = await nangoService.checkUserRepoAccess(user.nangoConnectionId, owner, repo);
|
|
469
|
+
return {
|
|
470
|
+
fullName,
|
|
471
|
+
hasAccess: accessResult.hasAccess,
|
|
472
|
+
permission: accessResult.permission,
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
catch (_err) {
|
|
476
|
+
return { fullName, hasAccess: false, error: 'Check failed' };
|
|
477
|
+
}
|
|
478
|
+
}));
|
|
479
|
+
results.push(...batchResults);
|
|
480
|
+
}
|
|
481
|
+
const accessibleCount = results.filter(r => r.hasAccess).length;
|
|
482
|
+
res.json({
|
|
483
|
+
results,
|
|
484
|
+
summary: {
|
|
485
|
+
total: repositories.length,
|
|
486
|
+
accessible: accessibleCount,
|
|
487
|
+
denied: repositories.length - accessibleCount,
|
|
488
|
+
},
|
|
489
|
+
checkedBy: {
|
|
490
|
+
userId: user.id,
|
|
491
|
+
githubUsername: user.githubUsername,
|
|
492
|
+
},
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
catch (error) {
|
|
496
|
+
console.error('Error checking bulk repo access:', error);
|
|
497
|
+
res.status(500).json({ error: 'Failed to check repository access' });
|
|
498
|
+
}
|
|
499
|
+
});
|
|
314
500
|
//# sourceMappingURL=repos.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Helper API Routes
|
|
3
|
+
*
|
|
4
|
+
* These endpoints are ONLY available in test/development mode.
|
|
5
|
+
* They allow integration tests to create users and daemons without OAuth.
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT: These routes are disabled in production (NODE_ENV=production).
|
|
8
|
+
*/
|
|
9
|
+
export declare const testHelpersRouter: import("express-serve-static-core").Router;
|
|
10
|
+
//# sourceMappingURL=test-helpers.d.ts.map
|