agent-relay 1.0.22 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/bridge/shadow-cli.d.ts +17 -0
- package/dist/bridge/shadow-cli.d.ts.map +1 -0
- package/dist/bridge/shadow-cli.js +75 -0
- package/dist/bridge/shadow-cli.js.map +1 -0
- package/dist/bridge/shadow-config.d.ts +87 -0
- package/dist/bridge/shadow-config.d.ts.map +1 -0
- package/dist/bridge/shadow-config.js +134 -0
- package/dist/bridge/shadow-config.js.map +1 -0
- package/dist/bridge/spawner.d.ts +68 -1
- package/dist/bridge/spawner.d.ts.map +1 -1
- package/dist/bridge/spawner.js +360 -16
- package/dist/bridge/spawner.js.map +1 -1
- package/dist/bridge/types.d.ts +67 -0
- package/dist/bridge/types.d.ts.map +1 -1
- package/dist/cli/index.js +1196 -15
- package/dist/cli/index.js.map +1 -1
- package/dist/cloud/api/auth.d.ts +20 -0
- package/dist/cloud/api/auth.d.ts.map +1 -0
- package/dist/cloud/api/auth.js +128 -0
- package/dist/cloud/api/auth.js.map +1 -0
- package/dist/cloud/api/billing.d.ts +17 -0
- package/dist/cloud/api/billing.d.ts.map +1 -0
- package/dist/cloud/api/billing.js +353 -0
- package/dist/cloud/api/billing.js.map +1 -0
- package/dist/cloud/api/cli-pty-runner.d.ts +54 -0
- package/dist/cloud/api/cli-pty-runner.d.ts.map +1 -0
- package/dist/cloud/api/cli-pty-runner.js +119 -0
- package/dist/cloud/api/cli-pty-runner.js.map +1 -0
- package/dist/cloud/api/coordinators.d.ts +8 -0
- package/dist/cloud/api/coordinators.d.ts.map +1 -0
- package/dist/cloud/api/coordinators.js +347 -0
- package/dist/cloud/api/coordinators.js.map +1 -0
- package/dist/cloud/api/daemons.d.ts +12 -0
- package/dist/cloud/api/daemons.d.ts.map +1 -0
- package/dist/cloud/api/daemons.js +320 -0
- package/dist/cloud/api/daemons.js.map +1 -0
- package/dist/cloud/api/generic-webhooks.d.ts +8 -0
- package/dist/cloud/api/generic-webhooks.d.ts.map +1 -0
- package/dist/cloud/api/generic-webhooks.js +129 -0
- package/dist/cloud/api/generic-webhooks.js.map +1 -0
- package/dist/cloud/api/git.d.ts +8 -0
- package/dist/cloud/api/git.d.ts.map +1 -0
- package/dist/cloud/api/git.js +131 -0
- package/dist/cloud/api/git.js.map +1 -0
- package/dist/cloud/api/github-app.d.ts +11 -0
- package/dist/cloud/api/github-app.d.ts.map +1 -0
- package/dist/cloud/api/github-app.js +189 -0
- package/dist/cloud/api/github-app.js.map +1 -0
- package/dist/cloud/api/middleware/planLimits.d.ts +43 -0
- package/dist/cloud/api/middleware/planLimits.d.ts.map +1 -0
- package/dist/cloud/api/middleware/planLimits.js +202 -0
- package/dist/cloud/api/middleware/planLimits.js.map +1 -0
- package/dist/cloud/api/monitoring.d.ts +11 -0
- package/dist/cloud/api/monitoring.d.ts.map +1 -0
- package/dist/cloud/api/monitoring.js +578 -0
- package/dist/cloud/api/monitoring.js.map +1 -0
- package/dist/cloud/api/nango-auth.d.ts +9 -0
- package/dist/cloud/api/nango-auth.d.ts.map +1 -0
- package/dist/cloud/api/nango-auth.js +377 -0
- package/dist/cloud/api/nango-auth.js.map +1 -0
- package/dist/cloud/api/onboarding.d.ts +15 -0
- package/dist/cloud/api/onboarding.d.ts.map +1 -0
- package/dist/cloud/api/onboarding.js +588 -0
- package/dist/cloud/api/onboarding.js.map +1 -0
- package/dist/cloud/api/policy.d.ts +8 -0
- package/dist/cloud/api/policy.d.ts.map +1 -0
- package/dist/cloud/api/policy.js +229 -0
- package/dist/cloud/api/policy.js.map +1 -0
- package/dist/cloud/api/providers.d.ts +7 -0
- package/dist/cloud/api/providers.d.ts.map +1 -0
- package/dist/cloud/api/providers.js +507 -0
- package/dist/cloud/api/providers.js.map +1 -0
- package/dist/cloud/api/repos.d.ts +7 -0
- package/dist/cloud/api/repos.d.ts.map +1 -0
- package/dist/cloud/api/repos.js +314 -0
- package/dist/cloud/api/repos.js.map +1 -0
- package/dist/cloud/api/teams.d.ts +7 -0
- package/dist/cloud/api/teams.d.ts.map +1 -0
- package/dist/cloud/api/teams.js +279 -0
- package/dist/cloud/api/teams.js.map +1 -0
- package/dist/cloud/api/test-helpers.d.ts +10 -0
- package/dist/cloud/api/test-helpers.d.ts.map +1 -0
- package/dist/cloud/api/test-helpers.js +575 -0
- package/dist/cloud/api/test-helpers.js.map +1 -0
- package/dist/cloud/api/usage.d.ts +7 -0
- package/dist/cloud/api/usage.d.ts.map +1 -0
- package/dist/cloud/api/usage.js +98 -0
- package/dist/cloud/api/usage.js.map +1 -0
- package/dist/cloud/api/webhooks.d.ts +7 -0
- package/dist/cloud/api/webhooks.d.ts.map +1 -0
- package/dist/cloud/api/webhooks.js +496 -0
- package/dist/cloud/api/webhooks.js.map +1 -0
- package/dist/cloud/api/workspaces.d.ts +7 -0
- package/dist/cloud/api/workspaces.d.ts.map +1 -0
- package/dist/cloud/api/workspaces.js +727 -0
- package/dist/cloud/api/workspaces.js.map +1 -0
- package/dist/cloud/billing/index.d.ts +9 -0
- package/dist/cloud/billing/index.d.ts.map +1 -0
- package/dist/cloud/billing/index.js +9 -0
- package/dist/cloud/billing/index.js.map +1 -0
- package/dist/cloud/billing/plans.d.ts +39 -0
- package/dist/cloud/billing/plans.d.ts.map +1 -0
- package/dist/cloud/billing/plans.js +245 -0
- package/dist/cloud/billing/plans.js.map +1 -0
- package/dist/cloud/billing/service.d.ts +80 -0
- package/dist/cloud/billing/service.d.ts.map +1 -0
- package/dist/cloud/billing/service.js +388 -0
- package/dist/cloud/billing/service.js.map +1 -0
- package/dist/cloud/billing/types.d.ts +141 -0
- package/dist/cloud/billing/types.d.ts.map +1 -0
- package/dist/cloud/billing/types.js +7 -0
- package/dist/cloud/billing/types.js.map +1 -0
- package/dist/cloud/config.d.ts +66 -0
- package/dist/cloud/config.d.ts.map +1 -0
- package/dist/cloud/config.js +92 -0
- package/dist/cloud/config.js.map +1 -0
- package/dist/cloud/db/drizzle.d.ts +215 -0
- package/dist/cloud/db/drizzle.d.ts.map +1 -0
- package/dist/cloud/db/drizzle.js +1083 -0
- package/dist/cloud/db/drizzle.js.map +1 -0
- package/dist/cloud/db/index.d.ts +35 -0
- package/dist/cloud/db/index.d.ts.map +1 -0
- package/dist/cloud/db/index.js +52 -0
- package/dist/cloud/db/index.js.map +1 -0
- package/dist/cloud/db/schema.d.ts +4519 -0
- package/dist/cloud/db/schema.d.ts.map +1 -0
- package/dist/cloud/db/schema.js +547 -0
- package/dist/cloud/db/schema.js.map +1 -0
- package/dist/cloud/index.d.ts +12 -0
- package/dist/cloud/index.d.ts.map +1 -0
- package/dist/cloud/index.js +39 -0
- package/dist/cloud/index.js.map +1 -0
- package/dist/cloud/provisioner/index.d.ts +75 -0
- package/dist/cloud/provisioner/index.d.ts.map +1 -0
- package/dist/cloud/provisioner/index.js +977 -0
- package/dist/cloud/provisioner/index.js.map +1 -0
- package/dist/cloud/server.d.ts +17 -0
- package/dist/cloud/server.d.ts.map +1 -0
- package/dist/cloud/server.js +534 -0
- package/dist/cloud/server.js.map +1 -0
- package/dist/cloud/services/auto-scaler.d.ts +152 -0
- package/dist/cloud/services/auto-scaler.d.ts.map +1 -0
- package/dist/cloud/services/auto-scaler.js +439 -0
- package/dist/cloud/services/auto-scaler.js.map +1 -0
- package/dist/cloud/services/capacity-manager.d.ts +148 -0
- package/dist/cloud/services/capacity-manager.d.ts.map +1 -0
- package/dist/cloud/services/capacity-manager.js +449 -0
- package/dist/cloud/services/capacity-manager.js.map +1 -0
- package/dist/cloud/services/ci-agent-spawner.d.ts +49 -0
- package/dist/cloud/services/ci-agent-spawner.d.ts.map +1 -0
- package/dist/cloud/services/ci-agent-spawner.js +373 -0
- package/dist/cloud/services/ci-agent-spawner.js.map +1 -0
- package/dist/cloud/services/coordinator.d.ts +62 -0
- package/dist/cloud/services/coordinator.d.ts.map +1 -0
- package/dist/cloud/services/coordinator.js +389 -0
- package/dist/cloud/services/coordinator.js.map +1 -0
- package/dist/cloud/services/index.d.ts +12 -0
- package/dist/cloud/services/index.d.ts.map +1 -0
- package/dist/cloud/services/index.js +15 -0
- package/dist/cloud/services/index.js.map +1 -0
- package/dist/cloud/services/mention-handler.d.ts +65 -0
- package/dist/cloud/services/mention-handler.d.ts.map +1 -0
- package/dist/cloud/services/mention-handler.js +405 -0
- package/dist/cloud/services/mention-handler.js.map +1 -0
- package/dist/cloud/services/nango.d.ts +126 -0
- package/dist/cloud/services/nango.d.ts.map +1 -0
- package/dist/cloud/services/nango.js +191 -0
- package/dist/cloud/services/nango.js.map +1 -0
- package/dist/cloud/services/persistence.d.ts +131 -0
- package/dist/cloud/services/persistence.d.ts.map +1 -0
- package/dist/cloud/services/persistence.js +200 -0
- package/dist/cloud/services/persistence.js.map +1 -0
- package/dist/cloud/services/planLimits.d.ts +125 -0
- package/dist/cloud/services/planLimits.d.ts.map +1 -0
- package/dist/cloud/services/planLimits.js +282 -0
- package/dist/cloud/services/planLimits.js.map +1 -0
- package/dist/cloud/services/scaling-orchestrator.d.ts +159 -0
- package/dist/cloud/services/scaling-orchestrator.d.ts.map +1 -0
- package/dist/cloud/services/scaling-orchestrator.js +502 -0
- package/dist/cloud/services/scaling-orchestrator.js.map +1 -0
- package/dist/cloud/services/scaling-policy.d.ts +121 -0
- package/dist/cloud/services/scaling-policy.d.ts.map +1 -0
- package/dist/cloud/services/scaling-policy.js +415 -0
- package/dist/cloud/services/scaling-policy.js.map +1 -0
- package/dist/cloud/vault/index.d.ts +76 -0
- package/dist/cloud/vault/index.d.ts.map +1 -0
- package/dist/cloud/vault/index.js +219 -0
- package/dist/cloud/vault/index.js.map +1 -0
- package/dist/cloud/webhooks/index.d.ts +24 -0
- package/dist/cloud/webhooks/index.d.ts.map +1 -0
- package/dist/cloud/webhooks/index.js +29 -0
- package/dist/cloud/webhooks/index.js.map +1 -0
- package/dist/cloud/webhooks/parsers/github.d.ts +8 -0
- package/dist/cloud/webhooks/parsers/github.d.ts.map +1 -0
- package/dist/cloud/webhooks/parsers/github.js +234 -0
- package/dist/cloud/webhooks/parsers/github.js.map +1 -0
- package/dist/cloud/webhooks/parsers/index.d.ts +23 -0
- package/dist/cloud/webhooks/parsers/index.d.ts.map +1 -0
- package/dist/cloud/webhooks/parsers/index.js +30 -0
- package/dist/cloud/webhooks/parsers/index.js.map +1 -0
- package/dist/cloud/webhooks/parsers/linear.d.ts +9 -0
- package/dist/cloud/webhooks/parsers/linear.d.ts.map +1 -0
- package/dist/cloud/webhooks/parsers/linear.js +258 -0
- package/dist/cloud/webhooks/parsers/linear.js.map +1 -0
- package/dist/cloud/webhooks/parsers/slack.d.ts +9 -0
- package/dist/cloud/webhooks/parsers/slack.d.ts.map +1 -0
- package/dist/cloud/webhooks/parsers/slack.js +214 -0
- package/dist/cloud/webhooks/parsers/slack.js.map +1 -0
- package/dist/cloud/webhooks/responders/github.d.ts +8 -0
- package/dist/cloud/webhooks/responders/github.d.ts.map +1 -0
- package/dist/cloud/webhooks/responders/github.js +73 -0
- package/dist/cloud/webhooks/responders/github.js.map +1 -0
- package/dist/cloud/webhooks/responders/index.d.ts +23 -0
- package/dist/cloud/webhooks/responders/index.d.ts.map +1 -0
- package/dist/cloud/webhooks/responders/index.js +30 -0
- package/dist/cloud/webhooks/responders/index.js.map +1 -0
- package/dist/cloud/webhooks/responders/linear.d.ts +9 -0
- package/dist/cloud/webhooks/responders/linear.d.ts.map +1 -0
- package/dist/cloud/webhooks/responders/linear.js +149 -0
- package/dist/cloud/webhooks/responders/linear.js.map +1 -0
- package/dist/cloud/webhooks/responders/slack.d.ts +20 -0
- package/dist/cloud/webhooks/responders/slack.d.ts.map +1 -0
- package/dist/cloud/webhooks/responders/slack.js +178 -0
- package/dist/cloud/webhooks/responders/slack.js.map +1 -0
- package/dist/cloud/webhooks/router.d.ts +25 -0
- package/dist/cloud/webhooks/router.d.ts.map +1 -0
- package/dist/cloud/webhooks/router.js +504 -0
- package/dist/cloud/webhooks/router.js.map +1 -0
- package/dist/cloud/webhooks/rules-engine.d.ts +24 -0
- package/dist/cloud/webhooks/rules-engine.d.ts.map +1 -0
- package/dist/cloud/webhooks/rules-engine.js +287 -0
- package/dist/cloud/webhooks/rules-engine.js.map +1 -0
- package/dist/cloud/webhooks/types.d.ts +186 -0
- package/dist/cloud/webhooks/types.d.ts.map +1 -0
- package/dist/cloud/webhooks/types.js +8 -0
- package/dist/cloud/webhooks/types.js.map +1 -0
- package/dist/continuity/formatter.d.ts +51 -0
- package/dist/continuity/formatter.d.ts.map +1 -0
- package/dist/continuity/formatter.js +313 -0
- package/dist/continuity/formatter.js.map +1 -0
- package/dist/continuity/handoff-store.d.ts +67 -0
- package/dist/continuity/handoff-store.d.ts.map +1 -0
- package/dist/continuity/handoff-store.js +472 -0
- package/dist/continuity/handoff-store.js.map +1 -0
- package/dist/continuity/index.d.ts +45 -0
- package/dist/continuity/index.d.ts.map +1 -0
- package/dist/continuity/index.js +48 -0
- package/dist/continuity/index.js.map +1 -0
- package/dist/continuity/ledger-store.d.ts +110 -0
- package/dist/continuity/ledger-store.d.ts.map +1 -0
- package/dist/continuity/ledger-store.js +500 -0
- package/dist/continuity/ledger-store.js.map +1 -0
- package/dist/continuity/manager.d.ts +178 -0
- package/dist/continuity/manager.d.ts.map +1 -0
- package/dist/continuity/manager.js +562 -0
- package/dist/continuity/manager.js.map +1 -0
- package/dist/continuity/parser.d.ts +76 -0
- package/dist/continuity/parser.d.ts.map +1 -0
- package/dist/continuity/parser.js +579 -0
- package/dist/continuity/parser.js.map +1 -0
- package/dist/continuity/types.d.ts +180 -0
- package/dist/continuity/types.d.ts.map +1 -0
- package/dist/continuity/types.js +9 -0
- package/dist/continuity/types.js.map +1 -0
- package/dist/daemon/agent-manager.d.ts +114 -0
- package/dist/daemon/agent-manager.d.ts.map +1 -0
- package/dist/daemon/agent-manager.js +513 -0
- package/dist/daemon/agent-manager.js.map +1 -0
- package/dist/daemon/agent-registry.d.ts +34 -0
- package/dist/daemon/agent-registry.d.ts.map +1 -1
- package/dist/daemon/agent-registry.js +45 -2
- package/dist/daemon/agent-registry.js.map +1 -1
- package/dist/daemon/api.d.ts +81 -0
- package/dist/daemon/api.d.ts.map +1 -0
- package/dist/daemon/api.js +554 -0
- package/dist/daemon/api.js.map +1 -0
- package/dist/daemon/cli-auth.d.ts +67 -0
- package/dist/daemon/cli-auth.d.ts.map +1 -0
- package/dist/daemon/cli-auth.js +537 -0
- package/dist/daemon/cli-auth.js.map +1 -0
- package/dist/daemon/cloud-sync.d.ts +101 -0
- package/dist/daemon/cloud-sync.d.ts.map +1 -0
- package/dist/daemon/cloud-sync.js +263 -0
- package/dist/daemon/cloud-sync.js.map +1 -0
- package/dist/daemon/index.d.ts +4 -0
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +6 -0
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/orchestrator.d.ts +155 -0
- package/dist/daemon/orchestrator.d.ts.map +1 -0
- package/dist/daemon/orchestrator.js +766 -0
- package/dist/daemon/orchestrator.js.map +1 -0
- package/dist/daemon/router.d.ts +29 -0
- package/dist/daemon/router.d.ts.map +1 -1
- package/dist/daemon/router.js +143 -21
- package/dist/daemon/router.js.map +1 -1
- package/dist/daemon/server.d.ts +42 -0
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +199 -16
- package/dist/daemon/server.js.map +1 -1
- package/dist/daemon/services/browser-testing.d.ts +88 -0
- package/dist/daemon/services/browser-testing.d.ts.map +1 -0
- package/dist/daemon/services/browser-testing.js +244 -0
- package/dist/daemon/services/browser-testing.js.map +1 -0
- package/dist/daemon/services/container-spawner.d.ts +135 -0
- package/dist/daemon/services/container-spawner.d.ts.map +1 -0
- package/dist/daemon/services/container-spawner.js +313 -0
- package/dist/daemon/services/container-spawner.js.map +1 -0
- package/dist/daemon/types.d.ts +131 -0
- package/dist/daemon/types.d.ts.map +1 -0
- package/dist/daemon/types.js +6 -0
- package/dist/daemon/types.js.map +1 -0
- package/dist/daemon/workspace-manager.d.ts +75 -0
- package/dist/daemon/workspace-manager.d.ts.map +1 -0
- package/dist/daemon/workspace-manager.js +289 -0
- package/dist/daemon/workspace-manager.js.map +1 -0
- 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/480-2d4111711d4e473c.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/724-73c1ee5f60abe860.js +9 -0
- package/dist/dashboard/out/_next/static/chunks/766-c3a14283c88d815b.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/page-7120be68bea622f3.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/connect-repos/page-dc2e3a1a22478efc.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/history/page-56a8b4616a90dc43.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/layout-2433bb48965f4333.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/login/page-3eac37ea6f5dd153.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/metrics/page-1081dd190a331a91.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/page-daf87e86f783f980.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/pricing/page-4d72d5a5d8a9b618.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/providers/page-b68a681526eb145e.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/signup/page-fee4ed1709070bcd.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/e868780c-48e5f147c90a3a41.js +18 -0
- package/dist/dashboard/out/_next/static/chunks/{main-e0a1f53fe0617a63.js → main-97850e03d723ea8c.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/main-app-5d692157a8eb1fd9.js +1 -0
- 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/411ce23ffeae9f76.css +1 -0
- package/dist/dashboard/out/alt-logos/agent-relay-logo-128.png +0 -0
- package/dist/dashboard/out/alt-logos/agent-relay-logo-256.png +0 -0
- package/dist/dashboard/out/alt-logos/agent-relay-logo-32.png +0 -0
- package/dist/dashboard/out/alt-logos/agent-relay-logo-512.png +0 -0
- package/dist/dashboard/out/alt-logos/agent-relay-logo-64.png +0 -0
- package/dist/dashboard/out/alt-logos/agent-relay-logo.svg +45 -0
- package/dist/dashboard/out/alt-logos/logo.svg +38 -0
- package/dist/dashboard/out/alt-logos/monogram-logo-128.png +0 -0
- package/dist/dashboard/out/alt-logos/monogram-logo-256.png +0 -0
- package/dist/dashboard/out/alt-logos/monogram-logo-32.png +0 -0
- package/dist/dashboard/out/alt-logos/monogram-logo-512.png +0 -0
- package/dist/dashboard/out/alt-logos/monogram-logo-64.png +0 -0
- package/dist/dashboard/out/alt-logos/monogram-logo.svg +38 -0
- package/dist/dashboard/out/app.html +1 -0
- package/dist/dashboard/out/app.txt +7 -0
- package/dist/dashboard/out/connect-repos.html +1 -0
- package/dist/dashboard/out/connect-repos.txt +7 -0
- package/dist/dashboard/out/history.html +1 -0
- package/dist/dashboard/out/history.txt +7 -0
- package/dist/dashboard/out/index.html +1 -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 -515
- package/dist/dashboard/out/metrics.txt +2 -2
- package/dist/dashboard/out/pricing.html +13 -0
- package/dist/dashboard/out/pricing.txt +7 -0
- package/dist/dashboard/out/providers.html +1 -0
- package/dist/dashboard/out/providers.txt +7 -0
- package/dist/dashboard/out/signup.html +6 -0
- package/dist/dashboard/out/signup.txt +7 -0
- package/dist/dashboard-server/metrics.d.ts.map +1 -1
- package/dist/dashboard-server/metrics.js +3 -2
- package/dist/dashboard-server/metrics.js.map +1 -1
- package/dist/dashboard-server/server.d.ts.map +1 -1
- package/dist/dashboard-server/server.js +2653 -130
- package/dist/dashboard-server/server.js.map +1 -1
- package/dist/hooks/emitter.d.ts +40 -0
- package/dist/hooks/emitter.d.ts.map +1 -0
- package/dist/hooks/emitter.js +63 -0
- package/dist/hooks/emitter.js.map +1 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/registry.d.ts +173 -0
- package/dist/hooks/registry.d.ts.map +1 -0
- package/dist/hooks/registry.js +476 -0
- package/dist/hooks/registry.js.map +1 -0
- package/dist/hooks/trajectory-hooks.d.ts +52 -0
- package/dist/hooks/trajectory-hooks.d.ts.map +1 -0
- package/dist/hooks/trajectory-hooks.js +183 -0
- package/dist/hooks/trajectory-hooks.js.map +1 -0
- package/dist/hooks/types.d.ts +141 -0
- package/dist/hooks/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/memory/adapters/index.d.ts +8 -0
- package/dist/memory/adapters/index.d.ts.map +1 -0
- package/dist/memory/adapters/index.js +8 -0
- package/dist/memory/adapters/index.js.map +1 -0
- package/dist/memory/adapters/inmemory.d.ts +59 -0
- package/dist/memory/adapters/inmemory.d.ts.map +1 -0
- package/dist/memory/adapters/inmemory.js +195 -0
- package/dist/memory/adapters/inmemory.js.map +1 -0
- package/dist/memory/adapters/supermemory.d.ts +71 -0
- package/dist/memory/adapters/supermemory.d.ts.map +1 -0
- package/dist/memory/adapters/supermemory.js +338 -0
- package/dist/memory/adapters/supermemory.js.map +1 -0
- package/dist/memory/factory.d.ts +48 -0
- package/dist/memory/factory.d.ts.map +1 -0
- package/dist/memory/factory.js +143 -0
- package/dist/memory/factory.js.map +1 -0
- package/dist/memory/index.d.ts +32 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +32 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/memory-hooks.d.ts +60 -0
- package/dist/memory/memory-hooks.d.ts.map +1 -0
- package/dist/memory/memory-hooks.js +313 -0
- package/dist/memory/memory-hooks.js.map +1 -0
- package/dist/memory/service.d.ts +49 -0
- package/dist/memory/service.d.ts.map +1 -0
- package/dist/memory/service.js +146 -0
- package/dist/memory/service.js.map +1 -0
- package/dist/memory/types.d.ts +195 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js +8 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/policy/agent-policy.d.ts +225 -0
- package/dist/policy/agent-policy.d.ts.map +1 -0
- package/dist/policy/agent-policy.js +665 -0
- package/dist/policy/agent-policy.js.map +1 -0
- package/dist/policy/cloud-policy-fetcher.d.ts +12 -0
- package/dist/policy/cloud-policy-fetcher.d.ts.map +1 -0
- package/dist/policy/cloud-policy-fetcher.js +64 -0
- package/dist/policy/cloud-policy-fetcher.js.map +1 -0
- package/dist/protocol/types.d.ts +10 -1
- package/dist/protocol/types.d.ts.map +1 -1
- package/dist/resiliency/context-persistence.d.ts +140 -0
- package/dist/resiliency/context-persistence.d.ts.map +1 -0
- package/dist/resiliency/context-persistence.js +397 -0
- package/dist/resiliency/context-persistence.js.map +1 -0
- package/dist/resiliency/crash-insights.d.ts +156 -0
- package/dist/resiliency/crash-insights.d.ts.map +1 -0
- package/dist/resiliency/crash-insights.js +492 -0
- package/dist/resiliency/crash-insights.js.map +1 -0
- package/dist/resiliency/gossip-health.d.ts +137 -0
- package/dist/resiliency/gossip-health.d.ts.map +1 -0
- package/dist/resiliency/gossip-health.js +241 -0
- package/dist/resiliency/gossip-health.js.map +1 -0
- package/dist/resiliency/health-monitor.d.ts +97 -0
- package/dist/resiliency/health-monitor.d.ts.map +1 -0
- package/dist/resiliency/health-monitor.js +291 -0
- package/dist/resiliency/health-monitor.js.map +1 -0
- package/dist/resiliency/index.d.ts +68 -0
- package/dist/resiliency/index.d.ts.map +1 -0
- package/dist/resiliency/index.js +68 -0
- package/dist/resiliency/index.js.map +1 -0
- package/dist/resiliency/leader-watchdog.d.ts +109 -0
- package/dist/resiliency/leader-watchdog.d.ts.map +1 -0
- package/dist/resiliency/leader-watchdog.js +189 -0
- package/dist/resiliency/leader-watchdog.js.map +1 -0
- package/dist/resiliency/logger.d.ts +114 -0
- package/dist/resiliency/logger.d.ts.map +1 -0
- package/dist/resiliency/logger.js +250 -0
- package/dist/resiliency/logger.js.map +1 -0
- package/dist/resiliency/memory-monitor.d.ts +172 -0
- package/dist/resiliency/memory-monitor.d.ts.map +1 -0
- package/dist/resiliency/memory-monitor.js +593 -0
- package/dist/resiliency/memory-monitor.js.map +1 -0
- package/dist/resiliency/metrics.d.ts +115 -0
- package/dist/resiliency/metrics.d.ts.map +1 -0
- package/dist/resiliency/metrics.js +239 -0
- package/dist/resiliency/metrics.js.map +1 -0
- package/dist/resiliency/provider-context.d.ts +100 -0
- package/dist/resiliency/provider-context.d.ts.map +1 -0
- package/dist/resiliency/provider-context.js +360 -0
- package/dist/resiliency/provider-context.js.map +1 -0
- package/dist/resiliency/stateless-lead.d.ts +149 -0
- package/dist/resiliency/stateless-lead.d.ts.map +1 -0
- package/dist/resiliency/stateless-lead.js +308 -0
- package/dist/resiliency/stateless-lead.js.map +1 -0
- package/dist/resiliency/supervisor.d.ts +147 -0
- package/dist/resiliency/supervisor.d.ts.map +1 -0
- package/dist/resiliency/supervisor.js +459 -0
- package/dist/resiliency/supervisor.js.map +1 -0
- package/dist/shared/cli-auth-config.d.ts +91 -0
- package/dist/shared/cli-auth-config.d.ts.map +1 -0
- package/dist/shared/cli-auth-config.js +264 -0
- package/dist/shared/cli-auth-config.js.map +1 -0
- package/dist/storage/adapter.d.ts +3 -1
- package/dist/storage/adapter.d.ts.map +1 -1
- package/dist/storage/adapter.js +12 -2
- package/dist/storage/adapter.js.map +1 -1
- package/dist/storage/sqlite-adapter.d.ts.map +1 -1
- package/dist/storage/sqlite-adapter.js +18 -14
- package/dist/storage/sqlite-adapter.js.map +1 -1
- package/dist/trajectory/config.d.ts +84 -0
- package/dist/trajectory/config.d.ts.map +1 -0
- package/dist/trajectory/config.js +163 -0
- package/dist/trajectory/config.js.map +1 -0
- package/dist/trajectory/index.d.ts +8 -0
- package/dist/trajectory/index.d.ts.map +1 -0
- package/dist/trajectory/index.js +8 -0
- package/dist/trajectory/index.js.map +1 -0
- package/dist/trajectory/integration.d.ts +292 -0
- package/dist/trajectory/integration.d.ts.map +1 -0
- package/dist/trajectory/integration.js +834 -0
- package/dist/trajectory/integration.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/logger.d.ts +40 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +84 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/project-namespace.d.ts +24 -0
- package/dist/utils/project-namespace.d.ts.map +1 -1
- package/dist/utils/project-namespace.js +84 -0
- package/dist/utils/project-namespace.js.map +1 -1
- package/dist/wrapper/client.d.ts +16 -1
- package/dist/wrapper/client.d.ts.map +1 -1
- package/dist/wrapper/client.js +32 -1
- package/dist/wrapper/client.js.map +1 -1
- package/dist/wrapper/parser.d.ts +13 -0
- package/dist/wrapper/parser.d.ts.map +1 -1
- package/dist/wrapper/parser.js +217 -47
- package/dist/wrapper/parser.js.map +1 -1
- package/dist/wrapper/pty-wrapper.d.ts +219 -17
- package/dist/wrapper/pty-wrapper.d.ts.map +1 -1
- package/dist/wrapper/pty-wrapper.js +1050 -104
- package/dist/wrapper/pty-wrapper.js.map +1 -1
- package/dist/wrapper/shared.d.ts +165 -0
- package/dist/wrapper/shared.d.ts.map +1 -0
- package/dist/wrapper/shared.js +270 -0
- package/dist/wrapper/shared.js.map +1 -0
- package/dist/wrapper/tmux-wrapper.d.ts +78 -11
- package/dist/wrapper/tmux-wrapper.d.ts.map +1 -1
- package/dist/wrapper/tmux-wrapper.js +567 -106
- package/dist/wrapper/tmux-wrapper.js.map +1 -1
- package/docs/CLOUD-ARCHITECTURE.md +804 -0
- package/docs/CLOUD-ONBOARDING-DESIGN.md +1983 -0
- package/docs/HOOKS_API.md +394 -0
- package/docs/WRAPPER_EVENTS.md +358 -0
- package/docs/agent-policy-snippet.md +40 -0
- package/docs/agent-relay-protocol.md +238 -0
- package/docs/agent-relay-snippet.md +115 -6
- package/docs/archive/EXECUTIVE_SUMMARY.md +358 -0
- package/docs/archive/ROADMAP.md +329 -0
- package/docs/archive/TESTING_PRESENCE_FEATURES.md +327 -0
- package/docs/competitive/GASTOWN.md +451 -0
- package/docs/{COMPETITIVE_ANALYSIS.md → competitive/OVERVIEW.md} +1 -0
- package/docs/competitive/README.md +34 -0
- package/docs/competitive/TMUX_ORCHESTRATOR.md +605 -0
- package/docs/dashboard.png +0 -0
- package/docs/design/ci-failure-webhooks.md +812 -0
- package/docs/design/comprehensive-integrations.md +238 -0
- package/docs/design/e2b-sandbox-integration.md +504 -0
- package/docs/design/github-app-permissions.md +264 -0
- package/docs/guides/CLOUD.md +236 -0
- package/docs/guides/LOCAL.md +535 -0
- package/docs/guides/SELF-HOSTED.md +494 -0
- package/docs/local-testing.md +428 -0
- package/docs/proposals/continuous-claude-integration.md +622 -0
- package/docs/proposals/custom-commands.md +368 -0
- package/docs/proposals/shadow-as-subagent.md +765 -0
- package/docs/proposals/slack-bot-integration.md +1457 -0
- package/docs/tasks/global-skills-system.tasks.md +230 -0
- package/docs/tasks/webhook-integrations.tasks.md +184 -0
- package/docs/tasks/workspace-capabilities.tasks.md +121 -0
- package/docs/testing/RESILIENCY-TEST-PLAN-2026-01-01.md +366 -0
- package/package.json +45 -7
- package/scripts/cloud-setup.sh +96 -0
- package/scripts/manual-qa.sh +293 -0
- package/scripts/postinstall.js +60 -0
- package/scripts/run-cloud-qa.sh +220 -0
- package/scripts/test-cli-auth/Dockerfile +44 -0
- package/scripts/test-cli-auth/Dockerfile.real +79 -0
- package/scripts/test-cli-auth/README.md +286 -0
- package/scripts/test-cli-auth/ci-test-real-clis.ts +251 -0
- package/scripts/test-cli-auth/ci-test-runner.ts +263 -0
- package/scripts/test-cli-auth/mock-cli.sh +147 -0
- package/scripts/test-cli-auth/package.json +14 -0
- package/scripts/test-cli-auth/test-oauth-flow.ts +220 -0
- package/scripts/test-pty-input-auto.js +222 -0
- package/scripts/test-pty-input.js +150 -0
- package/dist/dashboard/out/_next/static/chunks/app/layout-c9d8c5d95e48c6bf.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/metrics/page-8aa9936bc6c771ab.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/app/page-4498be09a5157759.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/main-app-bae2e535de00de50.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/webpack-c81f7fd28659d64f.js +0 -1
- package/dist/dashboard/out/_next/static/css/50ed6996e3df7bdd.css +0 -1
- /package/dist/dashboard/out/_next/static/{DXFA-jj8wb3PcY5DX2xcU → H5aWG0udPB4iOUIl_gytz}/_buildManifest.js +0 -0
- /package/dist/dashboard/out/_next/static/{DXFA-jj8wb3PcY5DX2xcU → H5aWG0udPB4iOUIl_gytz}/_ssgManifest.js +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{117-3bef7b19f3e60751.js → 117-b100311aff8d5c61.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{648-6cf686106c891ad3.js → 648-a13d3c2b1be45466.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/app/_not-found/{page-8ff6572bc7c9bc61.js → page-a4973f3e3c82fb67.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{fd9d1056-26bd8d656b496dba.js → fd9d1056-bf46c09eb57e019c.js} +0 -0
- /package/docs/{CHANGELOG.md → archive/CHANGELOG.md} +0 -0
- /package/docs/{CLI-SIMPLIFICATION-COMPLETE.md → archive/CLI-SIMPLIFICATION-COMPLETE.md} +0 -0
- /package/docs/{DESIGN_BRIDGE_STAFFING.md → archive/DESIGN_BRIDGE_STAFFING.md} +0 -0
- /package/docs/{DESIGN_V2.md → archive/DESIGN_V2.md} +0 -0
- /package/docs/{MONETIZATION.md → archive/MONETIZATION.md} +0 -0
- /package/docs/{PROPOSAL-trajectories.md → archive/PROPOSAL-trajectories.md} +0 -0
- /package/docs/{SCALING_ANALYSIS.md → archive/SCALING_ANALYSIS.md} +0 -0
- /package/docs/{TMUX_IMPLEMENTATION_NOTES.md → archive/TMUX_IMPLEMENTATION_NOTES.md} +0 -0
- /package/docs/{TMUX_IMPROVEMENTS.md → archive/TMUX_IMPROVEMENTS.md} +0 -0
- /package/docs/{dashboard-v2-plan.md → archive/dashboard-v2-plan.md} +0 -0
- /package/docs/{removable-code-analysis.md → archive/removable-code-analysis.md} +0 -0
- /package/docs/{competitive-analysis-mcp-agent-mail.md → competitive/MCP_AGENT_MAIL.md} +0 -0
|
@@ -0,0 +1,727 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspaces API Routes
|
|
3
|
+
*
|
|
4
|
+
* One-click workspace provisioning and management.
|
|
5
|
+
*/
|
|
6
|
+
import { Router } from 'express';
|
|
7
|
+
import { requireAuth } from './auth.js';
|
|
8
|
+
import { db } from '../db/index.js';
|
|
9
|
+
import { getProvisioner } from '../provisioner/index.js';
|
|
10
|
+
import { checkWorkspaceLimit } from './middleware/planLimits.js';
|
|
11
|
+
export const workspacesRouter = Router();
|
|
12
|
+
// All routes require authentication
|
|
13
|
+
workspacesRouter.use(requireAuth);
|
|
14
|
+
/**
|
|
15
|
+
* GET /api/workspaces
|
|
16
|
+
* List user's workspaces
|
|
17
|
+
*/
|
|
18
|
+
workspacesRouter.get('/', async (req, res) => {
|
|
19
|
+
const userId = req.session.userId;
|
|
20
|
+
try {
|
|
21
|
+
const workspaces = await db.workspaces.findByUserId(userId);
|
|
22
|
+
res.json({
|
|
23
|
+
workspaces: workspaces.map((w) => ({
|
|
24
|
+
id: w.id,
|
|
25
|
+
name: w.name,
|
|
26
|
+
status: w.status,
|
|
27
|
+
publicUrl: w.publicUrl,
|
|
28
|
+
providers: w.config.providers,
|
|
29
|
+
repositories: w.config.repositories,
|
|
30
|
+
createdAt: w.createdAt,
|
|
31
|
+
})),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
console.error('Error listing workspaces:', error);
|
|
36
|
+
res.status(500).json({ error: 'Failed to list workspaces' });
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* POST /api/workspaces
|
|
41
|
+
* Create (provision) a new workspace
|
|
42
|
+
*/
|
|
43
|
+
workspacesRouter.post('/', checkWorkspaceLimit, async (req, res) => {
|
|
44
|
+
const userId = req.session.userId;
|
|
45
|
+
const { name, providers, repositories, supervisorEnabled, maxAgents } = req.body;
|
|
46
|
+
// Validation
|
|
47
|
+
if (!name || typeof name !== 'string') {
|
|
48
|
+
return res.status(400).json({ error: 'Name is required' });
|
|
49
|
+
}
|
|
50
|
+
if (!providers || !Array.isArray(providers) || providers.length === 0) {
|
|
51
|
+
return res.status(400).json({ error: 'At least one provider is required' });
|
|
52
|
+
}
|
|
53
|
+
if (!repositories || !Array.isArray(repositories)) {
|
|
54
|
+
return res.status(400).json({ error: 'Repositories array is required' });
|
|
55
|
+
}
|
|
56
|
+
// Verify user has credentials for all providers
|
|
57
|
+
const credentials = await db.credentials.findByUserId(userId);
|
|
58
|
+
const connectedProviders = new Set(credentials.map((c) => c.provider));
|
|
59
|
+
for (const provider of providers) {
|
|
60
|
+
if (!connectedProviders.has(provider)) {
|
|
61
|
+
return res.status(400).json({
|
|
62
|
+
error: `Provider ${provider} not connected. Please connect it first.`,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const provisioner = getProvisioner();
|
|
68
|
+
const result = await provisioner.provision({
|
|
69
|
+
userId,
|
|
70
|
+
name,
|
|
71
|
+
providers,
|
|
72
|
+
repositories,
|
|
73
|
+
supervisorEnabled,
|
|
74
|
+
maxAgents,
|
|
75
|
+
});
|
|
76
|
+
if (result.status === 'error') {
|
|
77
|
+
return res.status(500).json({
|
|
78
|
+
error: 'Failed to provision workspace',
|
|
79
|
+
details: result.error,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
res.status(201).json({
|
|
83
|
+
workspaceId: result.workspaceId,
|
|
84
|
+
status: result.status,
|
|
85
|
+
publicUrl: result.publicUrl,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
console.error('Error creating workspace:', error);
|
|
90
|
+
res.status(500).json({ error: 'Failed to create workspace' });
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
/**
|
|
94
|
+
* GET /api/workspaces/summary
|
|
95
|
+
* Get summary of all user workspaces for dashboard status indicator
|
|
96
|
+
* NOTE: This route MUST be before /:id to avoid being caught by parameterized route
|
|
97
|
+
*/
|
|
98
|
+
workspacesRouter.get('/summary', async (req, res) => {
|
|
99
|
+
const userId = req.session.userId;
|
|
100
|
+
try {
|
|
101
|
+
const workspaces = await db.workspaces.findByUserId(userId);
|
|
102
|
+
const provisioner = getProvisioner();
|
|
103
|
+
// Get live status for each workspace
|
|
104
|
+
const workspaceSummaries = await Promise.all(workspaces.map(async (w) => {
|
|
105
|
+
let liveStatus = w.status;
|
|
106
|
+
try {
|
|
107
|
+
liveStatus = await provisioner.getStatus(w.id);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// Fall back to DB status
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
id: w.id,
|
|
114
|
+
name: w.name,
|
|
115
|
+
status: liveStatus,
|
|
116
|
+
publicUrl: w.publicUrl,
|
|
117
|
+
isStopped: liveStatus === 'stopped',
|
|
118
|
+
isRunning: liveStatus === 'running',
|
|
119
|
+
isProvisioning: liveStatus === 'provisioning',
|
|
120
|
+
hasError: liveStatus === 'error',
|
|
121
|
+
};
|
|
122
|
+
}));
|
|
123
|
+
// Overall status for quick dashboard indicator
|
|
124
|
+
const hasRunningWorkspace = workspaceSummaries.some(w => w.isRunning);
|
|
125
|
+
const hasStoppedWorkspace = workspaceSummaries.some(w => w.isStopped);
|
|
126
|
+
const hasProvisioningWorkspace = workspaceSummaries.some(w => w.isProvisioning);
|
|
127
|
+
res.json({
|
|
128
|
+
workspaces: workspaceSummaries,
|
|
129
|
+
summary: {
|
|
130
|
+
total: workspaceSummaries.length,
|
|
131
|
+
running: workspaceSummaries.filter(w => w.isRunning).length,
|
|
132
|
+
stopped: workspaceSummaries.filter(w => w.isStopped).length,
|
|
133
|
+
provisioning: workspaceSummaries.filter(w => w.isProvisioning).length,
|
|
134
|
+
error: workspaceSummaries.filter(w => w.hasError).length,
|
|
135
|
+
},
|
|
136
|
+
overallStatus: hasRunningWorkspace
|
|
137
|
+
? 'ready'
|
|
138
|
+
: hasProvisioningWorkspace
|
|
139
|
+
? 'provisioning'
|
|
140
|
+
: hasStoppedWorkspace
|
|
141
|
+
? 'stopped'
|
|
142
|
+
: workspaceSummaries.length === 0
|
|
143
|
+
? 'none'
|
|
144
|
+
: 'error',
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
console.error('Error getting workspace summary:', error);
|
|
149
|
+
res.status(500).json({ error: 'Failed to get workspace summary' });
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
/**
|
|
153
|
+
* GET /api/workspaces/primary
|
|
154
|
+
* Get the user's primary workspace (first/default) with live status
|
|
155
|
+
* Used by dashboard to show quick status indicator
|
|
156
|
+
* NOTE: This route MUST be before /:id to avoid being caught by parameterized route
|
|
157
|
+
*/
|
|
158
|
+
workspacesRouter.get('/primary', async (req, res) => {
|
|
159
|
+
const userId = req.session.userId;
|
|
160
|
+
try {
|
|
161
|
+
const workspaces = await db.workspaces.findByUserId(userId);
|
|
162
|
+
if (workspaces.length === 0) {
|
|
163
|
+
return res.json({
|
|
164
|
+
exists: false,
|
|
165
|
+
message: 'No workspace found. Connect a repository to auto-provision one.',
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
const primary = workspaces[0];
|
|
169
|
+
const provisioner = getProvisioner();
|
|
170
|
+
let liveStatus = primary.status;
|
|
171
|
+
try {
|
|
172
|
+
liveStatus = await provisioner.getStatus(primary.id);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
// Fall back to DB status
|
|
176
|
+
}
|
|
177
|
+
res.json({
|
|
178
|
+
exists: true,
|
|
179
|
+
workspace: {
|
|
180
|
+
id: primary.id,
|
|
181
|
+
name: primary.name,
|
|
182
|
+
status: liveStatus,
|
|
183
|
+
publicUrl: primary.publicUrl,
|
|
184
|
+
isStopped: liveStatus === 'stopped',
|
|
185
|
+
isRunning: liveStatus === 'running',
|
|
186
|
+
isProvisioning: liveStatus === 'provisioning',
|
|
187
|
+
hasError: liveStatus === 'error',
|
|
188
|
+
config: {
|
|
189
|
+
providers: primary.config.providers || [],
|
|
190
|
+
repositories: primary.config.repositories || [],
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
// Quick messages for UI
|
|
194
|
+
statusMessage: liveStatus === 'running'
|
|
195
|
+
? 'Workspace is running'
|
|
196
|
+
: liveStatus === 'stopped'
|
|
197
|
+
? 'Workspace is idle (will start automatically when needed)'
|
|
198
|
+
: liveStatus === 'provisioning'
|
|
199
|
+
? 'Workspace is being provisioned...'
|
|
200
|
+
: 'Workspace has an error',
|
|
201
|
+
actionNeeded: liveStatus === 'stopped'
|
|
202
|
+
? 'wakeup'
|
|
203
|
+
: liveStatus === 'error'
|
|
204
|
+
? 'check_error'
|
|
205
|
+
: null,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
console.error('Error getting primary workspace:', error);
|
|
210
|
+
res.status(500).json({ error: 'Failed to get primary workspace' });
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
/**
|
|
214
|
+
* GET /api/workspaces/:id
|
|
215
|
+
* Get workspace details
|
|
216
|
+
*/
|
|
217
|
+
workspacesRouter.get('/:id', async (req, res) => {
|
|
218
|
+
const userId = req.session.userId;
|
|
219
|
+
const { id } = req.params;
|
|
220
|
+
try {
|
|
221
|
+
const workspace = await db.workspaces.findById(id);
|
|
222
|
+
if (!workspace) {
|
|
223
|
+
return res.status(404).json({ error: 'Workspace not found' });
|
|
224
|
+
}
|
|
225
|
+
if (workspace.userId !== userId) {
|
|
226
|
+
return res.status(403).json({ error: 'Unauthorized' });
|
|
227
|
+
}
|
|
228
|
+
// Get repositories assigned to this workspace
|
|
229
|
+
const repositories = await db.repositories.findByWorkspaceId(id);
|
|
230
|
+
res.json({
|
|
231
|
+
id: workspace.id,
|
|
232
|
+
name: workspace.name,
|
|
233
|
+
status: workspace.status,
|
|
234
|
+
publicUrl: workspace.publicUrl,
|
|
235
|
+
computeProvider: workspace.computeProvider,
|
|
236
|
+
config: workspace.config,
|
|
237
|
+
errorMessage: workspace.errorMessage,
|
|
238
|
+
repositories: repositories.map((r) => ({
|
|
239
|
+
id: r.id,
|
|
240
|
+
fullName: r.githubFullName,
|
|
241
|
+
syncStatus: r.syncStatus,
|
|
242
|
+
lastSyncedAt: r.lastSyncedAt,
|
|
243
|
+
})),
|
|
244
|
+
createdAt: workspace.createdAt,
|
|
245
|
+
updatedAt: workspace.updatedAt,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
catch (error) {
|
|
249
|
+
console.error('Error getting workspace:', error);
|
|
250
|
+
res.status(500).json({ error: 'Failed to get workspace' });
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
/**
|
|
254
|
+
* GET /api/workspaces/:id/status
|
|
255
|
+
* Get current workspace status (polls compute provider)
|
|
256
|
+
*/
|
|
257
|
+
workspacesRouter.get('/:id/status', async (req, res) => {
|
|
258
|
+
const userId = req.session.userId;
|
|
259
|
+
const { id } = req.params;
|
|
260
|
+
try {
|
|
261
|
+
const workspace = await db.workspaces.findById(id);
|
|
262
|
+
if (!workspace) {
|
|
263
|
+
return res.status(404).json({ error: 'Workspace not found' });
|
|
264
|
+
}
|
|
265
|
+
if (workspace.userId !== userId) {
|
|
266
|
+
return res.status(403).json({ error: 'Unauthorized' });
|
|
267
|
+
}
|
|
268
|
+
const provisioner = getProvisioner();
|
|
269
|
+
const status = await provisioner.getStatus(id);
|
|
270
|
+
res.json({ status });
|
|
271
|
+
}
|
|
272
|
+
catch (error) {
|
|
273
|
+
console.error('Error getting workspace status:', error);
|
|
274
|
+
res.status(500).json({ error: 'Failed to get status' });
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
/**
|
|
278
|
+
* POST /api/workspaces/:id/restart
|
|
279
|
+
* Restart a workspace
|
|
280
|
+
*/
|
|
281
|
+
workspacesRouter.post('/:id/restart', async (req, res) => {
|
|
282
|
+
const userId = req.session.userId;
|
|
283
|
+
const { id } = req.params;
|
|
284
|
+
try {
|
|
285
|
+
const workspace = await db.workspaces.findById(id);
|
|
286
|
+
if (!workspace) {
|
|
287
|
+
return res.status(404).json({ error: 'Workspace not found' });
|
|
288
|
+
}
|
|
289
|
+
if (workspace.userId !== userId) {
|
|
290
|
+
return res.status(403).json({ error: 'Unauthorized' });
|
|
291
|
+
}
|
|
292
|
+
const provisioner = getProvisioner();
|
|
293
|
+
await provisioner.restart(id);
|
|
294
|
+
res.json({ success: true, message: 'Workspace restarting' });
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
console.error('Error restarting workspace:', error);
|
|
298
|
+
res.status(500).json({ error: 'Failed to restart workspace' });
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
/**
|
|
302
|
+
* POST /api/workspaces/:id/stop
|
|
303
|
+
* Stop a workspace
|
|
304
|
+
*/
|
|
305
|
+
workspacesRouter.post('/:id/stop', async (req, res) => {
|
|
306
|
+
const userId = req.session.userId;
|
|
307
|
+
const { id } = req.params;
|
|
308
|
+
try {
|
|
309
|
+
const workspace = await db.workspaces.findById(id);
|
|
310
|
+
if (!workspace) {
|
|
311
|
+
return res.status(404).json({ error: 'Workspace not found' });
|
|
312
|
+
}
|
|
313
|
+
if (workspace.userId !== userId) {
|
|
314
|
+
return res.status(403).json({ error: 'Unauthorized' });
|
|
315
|
+
}
|
|
316
|
+
const provisioner = getProvisioner();
|
|
317
|
+
await provisioner.stop(id);
|
|
318
|
+
res.json({ success: true, message: 'Workspace stopped' });
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
console.error('Error stopping workspace:', error);
|
|
322
|
+
res.status(500).json({ error: 'Failed to stop workspace' });
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
/**
|
|
326
|
+
* DELETE /api/workspaces/:id
|
|
327
|
+
* Delete (deprovision) a workspace
|
|
328
|
+
*/
|
|
329
|
+
workspacesRouter.delete('/:id', async (req, res) => {
|
|
330
|
+
const userId = req.session.userId;
|
|
331
|
+
const { id } = req.params;
|
|
332
|
+
try {
|
|
333
|
+
const workspace = await db.workspaces.findById(id);
|
|
334
|
+
if (!workspace) {
|
|
335
|
+
return res.status(404).json({ error: 'Workspace not found' });
|
|
336
|
+
}
|
|
337
|
+
if (workspace.userId !== userId) {
|
|
338
|
+
return res.status(403).json({ error: 'Unauthorized' });
|
|
339
|
+
}
|
|
340
|
+
const provisioner = getProvisioner();
|
|
341
|
+
await provisioner.deprovision(id);
|
|
342
|
+
res.json({ success: true, message: 'Workspace deleted' });
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
console.error('Error deleting workspace:', error);
|
|
346
|
+
res.status(500).json({ error: 'Failed to delete workspace' });
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
/**
|
|
350
|
+
* POST /api/workspaces/:id/repos
|
|
351
|
+
* Add repositories to a workspace
|
|
352
|
+
*/
|
|
353
|
+
workspacesRouter.post('/:id/repos', async (req, res) => {
|
|
354
|
+
const userId = req.session.userId;
|
|
355
|
+
const { id } = req.params;
|
|
356
|
+
const { repositoryIds } = req.body;
|
|
357
|
+
if (!repositoryIds || !Array.isArray(repositoryIds)) {
|
|
358
|
+
return res.status(400).json({ error: 'repositoryIds array is required' });
|
|
359
|
+
}
|
|
360
|
+
try {
|
|
361
|
+
const workspace = await db.workspaces.findById(id);
|
|
362
|
+
if (!workspace) {
|
|
363
|
+
return res.status(404).json({ error: 'Workspace not found' });
|
|
364
|
+
}
|
|
365
|
+
if (workspace.userId !== userId) {
|
|
366
|
+
return res.status(403).json({ error: 'Unauthorized' });
|
|
367
|
+
}
|
|
368
|
+
// Assign repositories to workspace
|
|
369
|
+
for (const repoId of repositoryIds) {
|
|
370
|
+
await db.repositories.assignToWorkspace(repoId, id);
|
|
371
|
+
}
|
|
372
|
+
res.json({ success: true, message: 'Repositories added' });
|
|
373
|
+
}
|
|
374
|
+
catch (error) {
|
|
375
|
+
console.error('Error adding repos to workspace:', error);
|
|
376
|
+
res.status(500).json({ error: 'Failed to add repositories' });
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
/**
|
|
380
|
+
* POST /api/workspaces/:id/domain
|
|
381
|
+
* Add or update custom domain (Premium feature - Team/Enterprise only)
|
|
382
|
+
*/
|
|
383
|
+
workspacesRouter.post('/:id/domain', async (req, res) => {
|
|
384
|
+
const userId = req.session.userId;
|
|
385
|
+
const { id } = req.params;
|
|
386
|
+
const { domain } = req.body;
|
|
387
|
+
if (!domain || typeof domain !== 'string') {
|
|
388
|
+
return res.status(400).json({ error: 'Domain is required' });
|
|
389
|
+
}
|
|
390
|
+
// Basic domain validation
|
|
391
|
+
const domainRegex = /^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
|
392
|
+
if (!domainRegex.test(domain)) {
|
|
393
|
+
return res.status(400).json({ error: 'Invalid domain format' });
|
|
394
|
+
}
|
|
395
|
+
try {
|
|
396
|
+
const workspace = await db.workspaces.findById(id);
|
|
397
|
+
if (!workspace) {
|
|
398
|
+
return res.status(404).json({ error: 'Workspace not found' });
|
|
399
|
+
}
|
|
400
|
+
if (workspace.userId !== userId) {
|
|
401
|
+
return res.status(403).json({ error: 'Unauthorized' });
|
|
402
|
+
}
|
|
403
|
+
// Check if user has premium plan (Team/Enterprise)
|
|
404
|
+
const user = await db.users.findById(userId);
|
|
405
|
+
const hasPremium = user?.plan === 'team' || user?.plan === 'enterprise';
|
|
406
|
+
if (!hasPremium) {
|
|
407
|
+
return res.status(402).json({
|
|
408
|
+
error: 'Custom domains require Team or Enterprise plan',
|
|
409
|
+
upgrade: '/settings/billing',
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
// Check if domain is already in use
|
|
413
|
+
const existing = await db.workspaces.findByCustomDomain(domain);
|
|
414
|
+
if (existing && existing.id !== id) {
|
|
415
|
+
return res.status(409).json({ error: 'Domain already in use' });
|
|
416
|
+
}
|
|
417
|
+
// Set the custom domain (pending verification)
|
|
418
|
+
await db.workspaces.setCustomDomain(id, domain, 'pending');
|
|
419
|
+
// Return DNS instructions
|
|
420
|
+
res.json({
|
|
421
|
+
success: true,
|
|
422
|
+
domain,
|
|
423
|
+
status: 'pending',
|
|
424
|
+
instructions: {
|
|
425
|
+
type: 'CNAME',
|
|
426
|
+
name: domain,
|
|
427
|
+
value: workspace.publicUrl?.replace('https://', '') || `${id}.agentrelay.dev`,
|
|
428
|
+
ttl: 300,
|
|
429
|
+
},
|
|
430
|
+
verifyEndpoint: `/api/workspaces/${id}/domain/verify`,
|
|
431
|
+
message: 'Add the CNAME record to your DNS, then call the verify endpoint',
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
catch (error) {
|
|
435
|
+
console.error('Error setting custom domain:', error);
|
|
436
|
+
res.status(500).json({ error: 'Failed to set custom domain' });
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
/**
|
|
440
|
+
* POST /api/workspaces/:id/domain/verify
|
|
441
|
+
* Verify custom domain DNS is configured correctly
|
|
442
|
+
*/
|
|
443
|
+
workspacesRouter.post('/:id/domain/verify', async (req, res) => {
|
|
444
|
+
const userId = req.session.userId;
|
|
445
|
+
const { id } = req.params;
|
|
446
|
+
try {
|
|
447
|
+
const workspace = await db.workspaces.findById(id);
|
|
448
|
+
if (!workspace) {
|
|
449
|
+
return res.status(404).json({ error: 'Workspace not found' });
|
|
450
|
+
}
|
|
451
|
+
if (workspace.userId !== userId) {
|
|
452
|
+
return res.status(403).json({ error: 'Unauthorized' });
|
|
453
|
+
}
|
|
454
|
+
if (!workspace.customDomain) {
|
|
455
|
+
return res.status(400).json({ error: 'No custom domain configured' });
|
|
456
|
+
}
|
|
457
|
+
// Verify DNS resolution
|
|
458
|
+
const dns = await import('dns').then(m => m.promises);
|
|
459
|
+
try {
|
|
460
|
+
const records = await dns.resolveCname(workspace.customDomain);
|
|
461
|
+
const expectedTarget = workspace.publicUrl?.replace('https://', '') || `${id}.agentrelay.dev`;
|
|
462
|
+
if (records.some(r => r.includes(expectedTarget) || r.includes('agentrelay'))) {
|
|
463
|
+
// DNS is configured, now provision SSL cert
|
|
464
|
+
await db.workspaces.updateCustomDomainStatus(id, 'verifying');
|
|
465
|
+
// Trigger SSL cert provisioning on compute provider
|
|
466
|
+
// For Railway/Fly, this is automatic once domain is added
|
|
467
|
+
await provisionDomainSSL(workspace);
|
|
468
|
+
await db.workspaces.updateCustomDomainStatus(id, 'active');
|
|
469
|
+
res.json({
|
|
470
|
+
success: true,
|
|
471
|
+
status: 'active',
|
|
472
|
+
domain: workspace.customDomain,
|
|
473
|
+
message: 'Custom domain verified and SSL certificate provisioned',
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
res.status(400).json({
|
|
478
|
+
success: false,
|
|
479
|
+
status: 'pending',
|
|
480
|
+
error: 'DNS not configured correctly',
|
|
481
|
+
expected: expectedTarget,
|
|
482
|
+
found: records,
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
catch (_dnsError) {
|
|
487
|
+
res.status(400).json({
|
|
488
|
+
success: false,
|
|
489
|
+
status: 'pending',
|
|
490
|
+
error: 'Could not resolve domain. DNS may not be configured yet.',
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
catch (error) {
|
|
495
|
+
console.error('Error verifying domain:', error);
|
|
496
|
+
res.status(500).json({ error: 'Failed to verify domain' });
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
/**
|
|
500
|
+
* DELETE /api/workspaces/:id/domain
|
|
501
|
+
* Remove custom domain
|
|
502
|
+
*/
|
|
503
|
+
workspacesRouter.delete('/:id/domain', async (req, res) => {
|
|
504
|
+
const userId = req.session.userId;
|
|
505
|
+
const { id } = req.params;
|
|
506
|
+
try {
|
|
507
|
+
const workspace = await db.workspaces.findById(id);
|
|
508
|
+
if (!workspace) {
|
|
509
|
+
return res.status(404).json({ error: 'Workspace not found' });
|
|
510
|
+
}
|
|
511
|
+
if (workspace.userId !== userId) {
|
|
512
|
+
return res.status(403).json({ error: 'Unauthorized' });
|
|
513
|
+
}
|
|
514
|
+
// Remove from compute provider
|
|
515
|
+
if (workspace.customDomain) {
|
|
516
|
+
await removeDomainFromCompute(workspace);
|
|
517
|
+
}
|
|
518
|
+
await db.workspaces.removeCustomDomain(id);
|
|
519
|
+
res.json({ success: true, message: 'Custom domain removed' });
|
|
520
|
+
}
|
|
521
|
+
catch (error) {
|
|
522
|
+
console.error('Error removing domain:', error);
|
|
523
|
+
res.status(500).json({ error: 'Failed to remove domain' });
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
/**
|
|
527
|
+
* Helper: Provision SSL for custom domain on compute provider
|
|
528
|
+
*/
|
|
529
|
+
async function provisionDomainSSL(workspace) {
|
|
530
|
+
const config = (await import('../config.js')).getConfig();
|
|
531
|
+
if (workspace.computeProvider === 'fly' && config.compute.fly) {
|
|
532
|
+
// Fly.io: Add certificate
|
|
533
|
+
await fetch(`https://api.machines.dev/v1/apps/ar-${workspace.id.substring(0, 8)}/certificates`, {
|
|
534
|
+
method: 'POST',
|
|
535
|
+
headers: {
|
|
536
|
+
Authorization: `Bearer ${config.compute.fly.apiToken}`,
|
|
537
|
+
'Content-Type': 'application/json',
|
|
538
|
+
},
|
|
539
|
+
body: JSON.stringify({ hostname: workspace.customDomain }),
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
else if (workspace.computeProvider === 'railway' && config.compute.railway) {
|
|
543
|
+
// Railway: Add custom domain via GraphQL
|
|
544
|
+
await fetch('https://backboard.railway.app/graphql/v2', {
|
|
545
|
+
method: 'POST',
|
|
546
|
+
headers: {
|
|
547
|
+
Authorization: `Bearer ${config.compute.railway.apiToken}`,
|
|
548
|
+
'Content-Type': 'application/json',
|
|
549
|
+
},
|
|
550
|
+
body: JSON.stringify({
|
|
551
|
+
query: `
|
|
552
|
+
mutation AddCustomDomain($input: CustomDomainCreateInput!) {
|
|
553
|
+
customDomainCreate(input: $input) { id }
|
|
554
|
+
}
|
|
555
|
+
`,
|
|
556
|
+
variables: {
|
|
557
|
+
input: {
|
|
558
|
+
projectId: workspace.computeId,
|
|
559
|
+
domain: workspace.customDomain,
|
|
560
|
+
},
|
|
561
|
+
},
|
|
562
|
+
}),
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
// Docker: Would need reverse proxy config (Caddy/nginx)
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Helper: Remove custom domain from compute provider
|
|
569
|
+
*/
|
|
570
|
+
async function removeDomainFromCompute(workspace) {
|
|
571
|
+
const config = (await import('../config.js')).getConfig();
|
|
572
|
+
if (workspace.computeProvider === 'fly' && config.compute.fly) {
|
|
573
|
+
await fetch(`https://api.machines.dev/v1/apps/ar-${workspace.id.substring(0, 8)}/certificates/${workspace.customDomain}`, {
|
|
574
|
+
method: 'DELETE',
|
|
575
|
+
headers: { Authorization: `Bearer ${config.compute.fly.apiToken}` },
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
// Railway and Docker: similar cleanup
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* POST /api/workspaces/:id/proxy/*
|
|
582
|
+
* Proxy API requests to the workspace container
|
|
583
|
+
* This allows the dashboard to make REST calls through the cloud server
|
|
584
|
+
*/
|
|
585
|
+
workspacesRouter.all('/:id/proxy/{*proxyPath}', async (req, res) => {
|
|
586
|
+
const userId = req.session.userId;
|
|
587
|
+
const { id } = req.params;
|
|
588
|
+
// Express 5 wildcard params return an array of path segments, not a slash-separated string
|
|
589
|
+
const proxyPathParam = req.params.proxyPath;
|
|
590
|
+
const proxyPath = Array.isArray(proxyPathParam) ? proxyPathParam.join('/') : proxyPathParam;
|
|
591
|
+
try {
|
|
592
|
+
const workspace = await db.workspaces.findById(id);
|
|
593
|
+
if (!workspace) {
|
|
594
|
+
return res.status(404).json({ error: 'Workspace not found' });
|
|
595
|
+
}
|
|
596
|
+
if (workspace.userId !== userId) {
|
|
597
|
+
return res.status(403).json({ error: 'Unauthorized' });
|
|
598
|
+
}
|
|
599
|
+
if (workspace.status !== 'running' || !workspace.publicUrl) {
|
|
600
|
+
return res.status(400).json({ error: 'Workspace is not running' });
|
|
601
|
+
}
|
|
602
|
+
// Determine the internal URL for proxying
|
|
603
|
+
// When running inside Docker, localhost URLs won't work - use the container name instead
|
|
604
|
+
let targetBaseUrl = workspace.publicUrl;
|
|
605
|
+
const runningInDocker = process.env.RUNNING_IN_DOCKER === 'true';
|
|
606
|
+
if (runningInDocker && workspace.computeId && targetBaseUrl.includes('localhost')) {
|
|
607
|
+
// Replace localhost URL with container name for Docker networking
|
|
608
|
+
// workspace.computeId is the container name (e.g., "ar-abc12345")
|
|
609
|
+
// The workspace port is 3888 inside the container
|
|
610
|
+
targetBaseUrl = `http://${workspace.computeId}:3888`;
|
|
611
|
+
}
|
|
612
|
+
const targetUrl = `${targetBaseUrl}/api/${proxyPath}`;
|
|
613
|
+
console.log(`[workspace-proxy] ${req.method} ${targetUrl}`);
|
|
614
|
+
// Store targetUrl for error handling
|
|
615
|
+
req._proxyTargetUrl = targetUrl;
|
|
616
|
+
// Add timeout to prevent hanging requests
|
|
617
|
+
const controller = new AbortController();
|
|
618
|
+
const timeout = setTimeout(() => controller.abort(), 15000); // 15s timeout
|
|
619
|
+
const fetchOptions = {
|
|
620
|
+
method: req.method,
|
|
621
|
+
headers: {
|
|
622
|
+
'Content-Type': 'application/json',
|
|
623
|
+
},
|
|
624
|
+
signal: controller.signal,
|
|
625
|
+
};
|
|
626
|
+
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
|
627
|
+
fetchOptions.body = JSON.stringify(req.body);
|
|
628
|
+
}
|
|
629
|
+
let proxyRes;
|
|
630
|
+
try {
|
|
631
|
+
proxyRes = await fetch(targetUrl, fetchOptions);
|
|
632
|
+
}
|
|
633
|
+
finally {
|
|
634
|
+
clearTimeout(timeout);
|
|
635
|
+
}
|
|
636
|
+
console.log(`[workspace-proxy] Response: ${proxyRes.status} ${proxyRes.statusText}`);
|
|
637
|
+
// Handle non-JSON responses gracefully
|
|
638
|
+
const contentType = proxyRes.headers.get('content-type');
|
|
639
|
+
if (contentType?.includes('application/json')) {
|
|
640
|
+
const data = await proxyRes.json();
|
|
641
|
+
res.status(proxyRes.status).json(data);
|
|
642
|
+
}
|
|
643
|
+
else {
|
|
644
|
+
const text = await proxyRes.text();
|
|
645
|
+
res.status(proxyRes.status).send(text);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
catch (error) {
|
|
649
|
+
const targetUrl = req._proxyTargetUrl || 'unknown';
|
|
650
|
+
console.error('[workspace-proxy] Error proxying to:', targetUrl);
|
|
651
|
+
console.error('[workspace-proxy] Error details:', error);
|
|
652
|
+
// Check for timeout/abort errors
|
|
653
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
654
|
+
res.status(504).json({
|
|
655
|
+
error: 'Workspace request timed out',
|
|
656
|
+
details: 'The workspace did not respond within 15 seconds',
|
|
657
|
+
targetUrl: targetUrl,
|
|
658
|
+
});
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
// Check for connection refused (workspace not running)
|
|
662
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
663
|
+
if (errorMessage.includes('ECONNREFUSED') || errorMessage.includes('fetch failed')) {
|
|
664
|
+
res.status(503).json({
|
|
665
|
+
error: 'Workspace is not reachable',
|
|
666
|
+
details: 'The workspace container may not be running or accepting connections',
|
|
667
|
+
targetUrl: targetUrl,
|
|
668
|
+
});
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
res.status(500).json({
|
|
672
|
+
error: 'Failed to proxy request to workspace',
|
|
673
|
+
details: errorMessage,
|
|
674
|
+
targetUrl: targetUrl, // Include target URL for debugging
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
});
|
|
678
|
+
/**
|
|
679
|
+
* POST /api/workspaces/quick
|
|
680
|
+
* Quick provision: one-click with defaults
|
|
681
|
+
* Providers are optional - can be connected after workspace creation via CLI login
|
|
682
|
+
*/
|
|
683
|
+
workspacesRouter.post('/quick', checkWorkspaceLimit, async (req, res) => {
|
|
684
|
+
const userId = req.session.userId;
|
|
685
|
+
const { name, repositoryFullName } = req.body;
|
|
686
|
+
if (!repositoryFullName) {
|
|
687
|
+
return res.status(400).json({ error: 'Repository name is required' });
|
|
688
|
+
}
|
|
689
|
+
try {
|
|
690
|
+
// Get user's connected providers (optional now)
|
|
691
|
+
const credentials = await db.credentials.findByUserId(userId);
|
|
692
|
+
const providers = credentials
|
|
693
|
+
.filter((c) => c.provider !== 'github')
|
|
694
|
+
.map((c) => c.provider);
|
|
695
|
+
// Create workspace with defaults
|
|
696
|
+
const provisioner = getProvisioner();
|
|
697
|
+
const workspaceName = name || `Workspace for ${repositoryFullName}`;
|
|
698
|
+
const result = await provisioner.provision({
|
|
699
|
+
userId,
|
|
700
|
+
name: workspaceName,
|
|
701
|
+
providers: providers.length > 0 ? providers : [], // Empty is OK now
|
|
702
|
+
repositories: [repositoryFullName],
|
|
703
|
+
supervisorEnabled: true,
|
|
704
|
+
maxAgents: 10,
|
|
705
|
+
});
|
|
706
|
+
if (result.status === 'error') {
|
|
707
|
+
return res.status(500).json({
|
|
708
|
+
error: 'Failed to provision workspace',
|
|
709
|
+
details: result.error,
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
res.status(201).json({
|
|
713
|
+
workspaceId: result.workspaceId,
|
|
714
|
+
status: result.status,
|
|
715
|
+
publicUrl: result.publicUrl,
|
|
716
|
+
providersConnected: providers.length > 0,
|
|
717
|
+
message: providers.length > 0
|
|
718
|
+
? 'Workspace provisioned successfully!'
|
|
719
|
+
: 'Workspace provisioned! Connect an AI provider to start using agents.',
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
catch (error) {
|
|
723
|
+
console.error('Error quick provisioning:', error);
|
|
724
|
+
res.status(500).json({ error: 'Failed to provision workspace' });
|
|
725
|
+
}
|
|
726
|
+
});
|
|
727
|
+
//# sourceMappingURL=workspaces.js.map
|