agent-relay 1.0.21 → 1.1.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/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 +15 -1
- package/dist/bridge/spawner.d.ts.map +1 -1
- package/dist/bridge/spawner.js +164 -4
- package/dist/bridge/spawner.js.map +1 -1
- package/dist/bridge/types.d.ts +55 -0
- package/dist/bridge/types.d.ts.map +1 -1
- package/dist/cli/index.js +796 -11
- package/dist/cli/index.js.map +1 -1
- package/dist/cloud/api/auth.d.ts +19 -0
- package/dist/cloud/api/auth.d.ts.map +1 -0
- package/dist/cloud/api/auth.js +216 -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/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/middleware/planLimits.d.ts +36 -0
- package/dist/cloud/api/middleware/planLimits.d.ts.map +1 -0
- package/dist/cloud/api/middleware/planLimits.js +164 -0
- package/dist/cloud/api/middleware/planLimits.js.map +1 -0
- package/dist/cloud/api/onboarding.d.ts +8 -0
- package/dist/cloud/api/onboarding.d.ts.map +1 -0
- package/dist/cloud/api/onboarding.js +407 -0
- package/dist/cloud/api/onboarding.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 +435 -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/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/workspaces.d.ts +7 -0
- package/dist/cloud/api/workspaces.d.ts.map +1 -0
- package/dist/cloud/api/workspaces.js +510 -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 +232 -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 +135 -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 +59 -0
- package/dist/cloud/config.d.ts.map +1 -0
- package/dist/cloud/config.js +83 -0
- package/dist/cloud/config.js.map +1 -0
- package/dist/cloud/db/drizzle.d.ts +132 -0
- package/dist/cloud/db/drizzle.d.ts.map +1 -0
- package/dist/cloud/db/drizzle.js +613 -0
- package/dist/cloud/db/drizzle.js.map +1 -0
- package/dist/cloud/db/index.d.ts +30 -0
- package/dist/cloud/db/index.d.ts.map +1 -0
- package/dist/cloud/db/index.js +44 -0
- package/dist/cloud/db/index.js.map +1 -0
- package/dist/cloud/db/schema.d.ts +1792 -0
- package/dist/cloud/db/schema.d.ts.map +1 -0
- package/dist/cloud/db/schema.js +234 -0
- package/dist/cloud/db/schema.js.map +1 -0
- package/dist/cloud/index.d.ts +11 -0
- package/dist/cloud/index.d.ts.map +1 -0
- package/dist/cloud/index.js +37 -0
- package/dist/cloud/index.js.map +1 -0
- package/dist/cloud/provisioner/index.d.ts +51 -0
- package/dist/cloud/provisioner/index.d.ts.map +1 -0
- package/dist/cloud/provisioner/index.js +676 -0
- package/dist/cloud/provisioner/index.js.map +1 -0
- package/dist/cloud/server.d.ts +16 -0
- package/dist/cloud/server.d.ts.map +1 -0
- package/dist/cloud/server.js +190 -0
- package/dist/cloud/server.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/planLimits.d.ts +110 -0
- package/dist/cloud/services/planLimits.d.ts.map +1 -0
- package/dist/cloud/services/planLimits.js +254 -0
- package/dist/cloud/services/planLimits.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/daemon/agent-manager.d.ts +87 -0
- package/dist/daemon/agent-manager.d.ts.map +1 -0
- package/dist/daemon/agent-manager.js +412 -0
- package/dist/daemon/agent-manager.js.map +1 -0
- package/dist/daemon/agent-registry.d.ts +2 -0
- package/dist/daemon/agent-registry.d.ts.map +1 -1
- package/dist/daemon/agent-registry.js +3 -0
- package/dist/daemon/agent-registry.js.map +1 -1
- package/dist/daemon/api.d.ts +69 -0
- package/dist/daemon/api.d.ts.map +1 -0
- package/dist/daemon/api.js +425 -0
- package/dist/daemon/api.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 +261 -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 +736 -0
- package/dist/daemon/orchestrator.js.map +1 -0
- package/dist/daemon/router.d.ts +24 -0
- package/dist/daemon/router.d.ts.map +1 -1
- package/dist/daemon/router.js +71 -1
- package/dist/daemon/router.js.map +1 -1
- package/dist/daemon/server.d.ts +37 -0
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +191 -16
- package/dist/daemon/server.js.map +1 -1
- package/dist/daemon/types.d.ts +127 -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/693-7b3301d8f6bc5014.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/713-f78477eb185f1f4d.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/766-e53e1cfe39b0b5b5.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/900-037c64bfd797fb2a.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/app/page-e3d9e1f4466b9bae.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/history/page-b6edd4dde8d08194.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/layout-2433bb48965f4333.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/metrics/page-e68825a81db67ba1.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/page-cc108bf68c8a657f.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/app/pricing/page-d80e03a5297f95b6.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/main-app-5d692157a8eb1fd9.js +1 -0
- package/dist/dashboard/out/_next/static/chunks/{main-e0a1f53fe0617a63.js → main-c2f423b9c9f4591b.js} +1 -1
- package/dist/dashboard/out/_next/static/chunks/{webpack-c81f7fd28659d64f.js → webpack-a5acc2831d094776.js} +1 -1
- package/dist/dashboard/out/_next/static/css/79b80143647a07d7.css +1 -0
- package/dist/dashboard/out/_next/static/css/8cf277370ad48cfe.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 +14 -0
- package/dist/dashboard/out/app.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/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-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 +1279 -56
- package/dist/dashboard-server/server.js.map +1 -1
- 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/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 +63 -0
- package/dist/resiliency/index.d.ts.map +1 -0
- package/dist/resiliency/index.js +63 -0
- package/dist/resiliency/index.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/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/supervisor.d.ts +109 -0
- package/dist/resiliency/supervisor.d.ts.map +1 -0
- package/dist/resiliency/supervisor.js +337 -0
- package/dist/resiliency/supervisor.js.map +1 -0
- package/dist/storage/adapter.d.ts +2 -0
- 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/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/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 +3 -0
- package/dist/wrapper/parser.d.ts.map +1 -1
- package/dist/wrapper/parser.js +121 -18
- package/dist/wrapper/parser.js.map +1 -1
- package/dist/wrapper/pty-wrapper.d.ts +28 -1
- package/dist/wrapper/pty-wrapper.d.ts.map +1 -1
- package/dist/wrapper/pty-wrapper.js +166 -30
- package/dist/wrapper/pty-wrapper.js.map +1 -1
- package/dist/wrapper/tmux-wrapper.d.ts +5 -0
- package/dist/wrapper/tmux-wrapper.d.ts.map +1 -1
- package/dist/wrapper/tmux-wrapper.js +58 -18
- package/dist/wrapper/tmux-wrapper.js.map +1 -1
- package/docs/CLOUD-ARCHITECTURE.md +652 -0
- package/docs/CLOUD-ONBOARDING-DESIGN.md +1983 -0
- package/docs/TESTING_PRESENCE_FEATURES.md +327 -0
- package/docs/agent-relay-snippet.md +107 -4
- package/docs/guides/CLOUD.md +236 -0
- package/docs/guides/LOCAL.md +535 -0
- package/docs/guides/SELF-HOSTED.md +494 -0
- package/docs/proposals/shadow-as-subagent.md +765 -0
- package/docs/proposals/slack-bot-integration.md +1457 -0
- package/package.json +33 -4
- 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-49055e5d2b5e34ec.js +0 -1
- package/dist/dashboard/out/_next/static/chunks/main-app-bae2e535de00de50.js +0 -1
- package/dist/dashboard/out/_next/static/css/50ed6996e3df7bdd.css +0 -1
- /package/dist/dashboard/out/_next/static/{gZXwjIKGDKJ0hiTH-HMeJ → 6HHWb2ZmnJ4OSm0zUP7h4}/_buildManifest.js +0 -0
- /package/dist/dashboard/out/_next/static/{gZXwjIKGDKJ0hiTH-HMeJ → 6HHWb2ZmnJ4OSm0zUP7h4}/_ssgManifest.js +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{117-3bef7b19f3e60751.js → 117-b2cd8d6485aacf2b.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{648-6cf686106c891ad3.js → 648-8f3f26864ce515e5.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/app/_not-found/{page-8ff6572bc7c9bc61.js → page-0b990dbb71d72a98.js} +0 -0
- /package/dist/dashboard/out/_next/static/chunks/{fd9d1056-26bd8d656b496dba.js → fd9d1056-bf46c09eb57e019c.js} +0 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plan Limits Service
|
|
3
|
+
*
|
|
4
|
+
* Defines resource limits for each plan tier and provides
|
|
5
|
+
* functions to check if users are within their limits.
|
|
6
|
+
*/
|
|
7
|
+
import { db, usageRecordsTable } from '../db/index.js';
|
|
8
|
+
import { eq, and, gte, sql } from 'drizzle-orm';
|
|
9
|
+
import { getDb } from '../db/drizzle.js';
|
|
10
|
+
/**
|
|
11
|
+
* Plan limits configuration
|
|
12
|
+
*
|
|
13
|
+
* Free: Try it out on a side project
|
|
14
|
+
* Pro: Professional developers, coordinators enabled
|
|
15
|
+
* Team: Growing teams with advanced needs
|
|
16
|
+
* Enterprise: Unlimited everything
|
|
17
|
+
*/
|
|
18
|
+
export const PLAN_LIMITS = {
|
|
19
|
+
free: {
|
|
20
|
+
maxWorkspaces: 1,
|
|
21
|
+
maxRepos: 3,
|
|
22
|
+
maxConcurrentAgents: 2,
|
|
23
|
+
maxComputeHoursPerMonth: 10,
|
|
24
|
+
coordinatorsEnabled: false,
|
|
25
|
+
},
|
|
26
|
+
pro: {
|
|
27
|
+
maxWorkspaces: 5,
|
|
28
|
+
maxRepos: 20,
|
|
29
|
+
maxConcurrentAgents: 10,
|
|
30
|
+
maxComputeHoursPerMonth: 100,
|
|
31
|
+
coordinatorsEnabled: true,
|
|
32
|
+
},
|
|
33
|
+
team: {
|
|
34
|
+
maxWorkspaces: 20,
|
|
35
|
+
maxRepos: 100,
|
|
36
|
+
maxConcurrentAgents: 50,
|
|
37
|
+
maxComputeHoursPerMonth: 500,
|
|
38
|
+
coordinatorsEnabled: true,
|
|
39
|
+
},
|
|
40
|
+
enterprise: {
|
|
41
|
+
maxWorkspaces: Infinity,
|
|
42
|
+
maxRepos: Infinity,
|
|
43
|
+
maxConcurrentAgents: Infinity,
|
|
44
|
+
maxComputeHoursPerMonth: Infinity,
|
|
45
|
+
coordinatorsEnabled: true,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Get plan limits for a given plan type
|
|
50
|
+
*/
|
|
51
|
+
export function getPlanLimits(plan) {
|
|
52
|
+
return PLAN_LIMITS[plan];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get current usage for a user
|
|
56
|
+
*/
|
|
57
|
+
export async function getUserUsage(userId) {
|
|
58
|
+
// Get workspace count
|
|
59
|
+
const workspaces = await db.workspaces.findByUserId(userId);
|
|
60
|
+
const workspaceCount = workspaces.length;
|
|
61
|
+
// Get repo count across all workspaces
|
|
62
|
+
let repoCount = 0;
|
|
63
|
+
for (const workspace of workspaces) {
|
|
64
|
+
const repos = await db.repositories.findByWorkspaceId(workspace.id);
|
|
65
|
+
repoCount += repos.length;
|
|
66
|
+
}
|
|
67
|
+
// Get concurrent agents (currently running)
|
|
68
|
+
// For now, we'll track this via usage_records with metric 'active_agents'
|
|
69
|
+
// In production, this would query the actual running agent count
|
|
70
|
+
const drizzleDb = getDb();
|
|
71
|
+
const activeAgentsResult = await drizzleDb
|
|
72
|
+
.select({ total: sql `COALESCE(MAX(${usageRecordsTable.value}), 0)` })
|
|
73
|
+
.from(usageRecordsTable)
|
|
74
|
+
.where(and(eq(usageRecordsTable.userId, userId), eq(usageRecordsTable.metric, 'active_agents')));
|
|
75
|
+
const concurrentAgents = Number(activeAgentsResult[0]?.total || 0);
|
|
76
|
+
// Get compute hours this month
|
|
77
|
+
const startOfMonth = new Date();
|
|
78
|
+
startOfMonth.setDate(1);
|
|
79
|
+
startOfMonth.setHours(0, 0, 0, 0);
|
|
80
|
+
const computeHoursResult = await drizzleDb
|
|
81
|
+
.select({ total: sql `COALESCE(SUM(${usageRecordsTable.value}), 0)` })
|
|
82
|
+
.from(usageRecordsTable)
|
|
83
|
+
.where(and(eq(usageRecordsTable.userId, userId), eq(usageRecordsTable.metric, 'compute_hours'), gte(usageRecordsTable.recordedAt, startOfMonth)));
|
|
84
|
+
const computeHoursThisMonth = Number(computeHoursResult[0]?.total || 0);
|
|
85
|
+
return {
|
|
86
|
+
workspaceCount,
|
|
87
|
+
repoCount,
|
|
88
|
+
concurrentAgents,
|
|
89
|
+
computeHoursThisMonth,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Check if user can create a new workspace
|
|
94
|
+
*/
|
|
95
|
+
export async function canCreateWorkspace(userId) {
|
|
96
|
+
const user = await db.users.findById(userId);
|
|
97
|
+
if (!user) {
|
|
98
|
+
return { allowed: false, reason: 'User not found' };
|
|
99
|
+
}
|
|
100
|
+
const plan = user.plan || 'free';
|
|
101
|
+
const limits = getPlanLimits(plan);
|
|
102
|
+
const usage = await getUserUsage(userId);
|
|
103
|
+
if (usage.workspaceCount >= limits.maxWorkspaces) {
|
|
104
|
+
return {
|
|
105
|
+
allowed: false,
|
|
106
|
+
reason: `Workspace limit reached for ${plan} plan`,
|
|
107
|
+
limit: limits.maxWorkspaces,
|
|
108
|
+
current: usage.workspaceCount,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
return { allowed: true };
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Check if user can add a new repo
|
|
115
|
+
*/
|
|
116
|
+
export async function canAddRepo(userId) {
|
|
117
|
+
const user = await db.users.findById(userId);
|
|
118
|
+
if (!user) {
|
|
119
|
+
return { allowed: false, reason: 'User not found' };
|
|
120
|
+
}
|
|
121
|
+
const plan = user.plan || 'free';
|
|
122
|
+
const limits = getPlanLimits(plan);
|
|
123
|
+
const usage = await getUserUsage(userId);
|
|
124
|
+
if (usage.repoCount >= limits.maxRepos) {
|
|
125
|
+
return {
|
|
126
|
+
allowed: false,
|
|
127
|
+
reason: `Repository limit reached for ${plan} plan`,
|
|
128
|
+
limit: limits.maxRepos,
|
|
129
|
+
current: usage.repoCount,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return { allowed: true };
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Check if user can spawn another agent (concurrent agent limit)
|
|
136
|
+
*/
|
|
137
|
+
export async function canSpawnAgent(userId, currentRunningAgents) {
|
|
138
|
+
const user = await db.users.findById(userId);
|
|
139
|
+
if (!user) {
|
|
140
|
+
return { allowed: false, reason: 'User not found' };
|
|
141
|
+
}
|
|
142
|
+
const plan = user.plan || 'free';
|
|
143
|
+
const limits = getPlanLimits(plan);
|
|
144
|
+
// Use provided count or fetch from usage
|
|
145
|
+
let concurrentAgents;
|
|
146
|
+
if (currentRunningAgents !== undefined) {
|
|
147
|
+
concurrentAgents = currentRunningAgents;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
const usage = await getUserUsage(userId);
|
|
151
|
+
concurrentAgents = usage.concurrentAgents;
|
|
152
|
+
}
|
|
153
|
+
if (concurrentAgents >= limits.maxConcurrentAgents) {
|
|
154
|
+
return {
|
|
155
|
+
allowed: false,
|
|
156
|
+
reason: `Concurrent agent limit reached for ${plan} plan`,
|
|
157
|
+
limit: limits.maxConcurrentAgents,
|
|
158
|
+
current: concurrentAgents,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return { allowed: true };
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Check if user can use coordinator agents
|
|
165
|
+
*/
|
|
166
|
+
export async function canUseCoordinator(userId) {
|
|
167
|
+
const user = await db.users.findById(userId);
|
|
168
|
+
if (!user) {
|
|
169
|
+
return { allowed: false, reason: 'User not found' };
|
|
170
|
+
}
|
|
171
|
+
const plan = user.plan || 'free';
|
|
172
|
+
const limits = getPlanLimits(plan);
|
|
173
|
+
if (!limits.coordinatorsEnabled) {
|
|
174
|
+
return {
|
|
175
|
+
allowed: false,
|
|
176
|
+
reason: 'Coordinator agents require a Pro plan or higher',
|
|
177
|
+
requiredPlan: 'pro',
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return { allowed: true };
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Check if user has compute hours available
|
|
184
|
+
*/
|
|
185
|
+
export async function hasComputeHoursAvailable(userId) {
|
|
186
|
+
const user = await db.users.findById(userId);
|
|
187
|
+
if (!user) {
|
|
188
|
+
return { available: false, reason: 'User not found' };
|
|
189
|
+
}
|
|
190
|
+
const plan = user.plan || 'free';
|
|
191
|
+
const limits = getPlanLimits(plan);
|
|
192
|
+
const usage = await getUserUsage(userId);
|
|
193
|
+
// Enterprise has unlimited
|
|
194
|
+
if (limits.maxComputeHoursPerMonth === Infinity) {
|
|
195
|
+
return { available: true };
|
|
196
|
+
}
|
|
197
|
+
if (usage.computeHoursThisMonth >= limits.maxComputeHoursPerMonth) {
|
|
198
|
+
return {
|
|
199
|
+
available: false,
|
|
200
|
+
reason: `Compute hours limit reached for ${plan} plan`,
|
|
201
|
+
limit: limits.maxComputeHoursPerMonth,
|
|
202
|
+
current: usage.computeHoursThisMonth,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return { available: true };
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Get remaining quota for a user
|
|
209
|
+
*/
|
|
210
|
+
export async function getRemainingQuota(userId) {
|
|
211
|
+
const user = await db.users.findById(userId);
|
|
212
|
+
const plan = (user?.plan || 'free');
|
|
213
|
+
const limits = getPlanLimits(plan);
|
|
214
|
+
const usage = await getUserUsage(userId);
|
|
215
|
+
const calcRemaining = (limit, current) => limit === Infinity ? Infinity : Math.max(0, limit - current);
|
|
216
|
+
return {
|
|
217
|
+
plan,
|
|
218
|
+
limits,
|
|
219
|
+
usage,
|
|
220
|
+
remaining: {
|
|
221
|
+
workspaces: calcRemaining(limits.maxWorkspaces, usage.workspaceCount),
|
|
222
|
+
repos: calcRemaining(limits.maxRepos, usage.repoCount),
|
|
223
|
+
concurrentAgents: calcRemaining(limits.maxConcurrentAgents, usage.concurrentAgents),
|
|
224
|
+
computeHours: calcRemaining(limits.maxComputeHoursPerMonth, usage.computeHoursThisMonth),
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Record compute usage
|
|
230
|
+
*/
|
|
231
|
+
export async function recordComputeUsage(userId, workspaceId, hours) {
|
|
232
|
+
const drizzleDb = getDb();
|
|
233
|
+
await drizzleDb.insert(usageRecordsTable).values({
|
|
234
|
+
userId,
|
|
235
|
+
workspaceId,
|
|
236
|
+
metric: 'compute_hours',
|
|
237
|
+
value: Math.round(hours * 100) / 100, // Round to 2 decimal places
|
|
238
|
+
recordedAt: new Date(),
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Update active agent count for a user
|
|
243
|
+
*/
|
|
244
|
+
export async function updateActiveAgentCount(userId, workspaceId, count) {
|
|
245
|
+
const drizzleDb = getDb();
|
|
246
|
+
await drizzleDb.insert(usageRecordsTable).values({
|
|
247
|
+
userId,
|
|
248
|
+
workspaceId,
|
|
249
|
+
metric: 'active_agents',
|
|
250
|
+
value: count,
|
|
251
|
+
recordedAt: new Date(),
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
//# sourceMappingURL=planLimits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planLimits.js","sourceRoot":"","sources":["../../../src/cloud/services/planLimits.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Relay Cloud - Credential Vault
|
|
3
|
+
*
|
|
4
|
+
* Secure storage for OAuth tokens with AES-256-GCM encryption.
|
|
5
|
+
*/
|
|
6
|
+
export interface StoredCredential {
|
|
7
|
+
userId: string;
|
|
8
|
+
provider: string;
|
|
9
|
+
accessToken: string;
|
|
10
|
+
refreshToken?: string;
|
|
11
|
+
tokenExpiresAt?: Date;
|
|
12
|
+
scopes?: string[];
|
|
13
|
+
providerAccountId?: string;
|
|
14
|
+
providerAccountEmail?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface DecryptedCredential {
|
|
17
|
+
accessToken: string;
|
|
18
|
+
refreshToken?: string;
|
|
19
|
+
tokenExpiresAt?: Date;
|
|
20
|
+
scopes?: string[];
|
|
21
|
+
providerAccountId?: string;
|
|
22
|
+
providerAccountEmail?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare class CredentialVault {
|
|
25
|
+
private masterKey;
|
|
26
|
+
constructor();
|
|
27
|
+
/**
|
|
28
|
+
* Encrypt a string value
|
|
29
|
+
*/
|
|
30
|
+
private encrypt;
|
|
31
|
+
/**
|
|
32
|
+
* Decrypt a string value
|
|
33
|
+
*/
|
|
34
|
+
private decrypt;
|
|
35
|
+
/**
|
|
36
|
+
* Store encrypted credential
|
|
37
|
+
*/
|
|
38
|
+
storeCredential(credential: StoredCredential): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Retrieve and decrypt credential
|
|
41
|
+
*/
|
|
42
|
+
getCredential(userId: string, provider: string): Promise<DecryptedCredential | null>;
|
|
43
|
+
/**
|
|
44
|
+
* Get all credentials for a user (decrypted)
|
|
45
|
+
*/
|
|
46
|
+
getUserCredentials(userId: string): Promise<Map<string, DecryptedCredential>>;
|
|
47
|
+
/**
|
|
48
|
+
* Update tokens (e.g., after refresh)
|
|
49
|
+
*/
|
|
50
|
+
updateTokens(userId: string, provider: string, accessToken: string, refreshToken?: string, expiresAt?: Date): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Delete credential
|
|
53
|
+
*/
|
|
54
|
+
deleteCredential(userId: string, provider: string): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Check if credential needs refresh (within 5 minutes of expiry)
|
|
57
|
+
*/
|
|
58
|
+
needsRefresh(userId: string, provider: string): Promise<boolean>;
|
|
59
|
+
/**
|
|
60
|
+
* Refresh OAuth token for a provider
|
|
61
|
+
*/
|
|
62
|
+
refreshToken(userId: string, provider: string): Promise<boolean>;
|
|
63
|
+
}
|
|
64
|
+
export declare function getVault(): CredentialVault;
|
|
65
|
+
export declare const vault: {
|
|
66
|
+
readonly instance: CredentialVault;
|
|
67
|
+
storeCredential: (cred: StoredCredential) => Promise<void>;
|
|
68
|
+
getCredential: (userId: string, provider: string) => Promise<DecryptedCredential | null>;
|
|
69
|
+
getUserCredentials: (userId: string) => Promise<Map<string, DecryptedCredential>>;
|
|
70
|
+
updateTokens: (userId: string, provider: string, accessToken: string, refreshToken?: string, expiresAt?: Date) => Promise<void>;
|
|
71
|
+
deleteCredential: (userId: string, provider: string) => Promise<void>;
|
|
72
|
+
needsRefresh: (userId: string, provider: string) => Promise<boolean>;
|
|
73
|
+
refreshToken: (userId: string, provider: string) => Promise<boolean>;
|
|
74
|
+
};
|
|
75
|
+
export declare function generateMasterKey(): string;
|
|
76
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cloud/vault/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAAS;;IAW1B;;OAEG;IACH,OAAO,CAAC,OAAO;IAgBf;;OAEG;IACH,OAAO,CAAC,OAAO;IAkBf;;OAEG;IACG,eAAe,CAAC,UAAU,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBlE;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAkB1F;;OAEG;IACG,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAoBnF;;OAEG;IACG,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,MAAM,EACrB,SAAS,CAAC,EAAE,IAAI,GACf,OAAO,CAAC,IAAI,CAAC;IAehB;;OAEG;IACG,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvE;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUtE;;OAEG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAuEvE;AAKD,wBAAgB,QAAQ,IAAI,eAAe,CAK1C;AAED,eAAO,MAAM,KAAK;;4BAIQ,gBAAgB;4BAChB,MAAM,YAAY,MAAM;iCAEnB,MAAM;2BAEzB,MAAM,YACJ,MAAM,eACH,MAAM,iBACJ,MAAM,cACT,IAAI;+BAES,MAAM,YAAY,MAAM;2BAE5B,MAAM,YAAY,MAAM;2BAExB,MAAM,YAAY,MAAM;CAEhD,CAAC;AAGF,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Relay Cloud - Credential Vault
|
|
3
|
+
*
|
|
4
|
+
* Secure storage for OAuth tokens with AES-256-GCM encryption.
|
|
5
|
+
*/
|
|
6
|
+
import crypto from 'crypto';
|
|
7
|
+
import { getConfig } from '../config.js';
|
|
8
|
+
import { db } from '../db/index.js';
|
|
9
|
+
const ALGORITHM = 'aes-256-gcm';
|
|
10
|
+
const IV_LENGTH = 12;
|
|
11
|
+
const AUTH_TAG_LENGTH = 16;
|
|
12
|
+
export class CredentialVault {
|
|
13
|
+
masterKey;
|
|
14
|
+
constructor() {
|
|
15
|
+
const config = getConfig();
|
|
16
|
+
this.masterKey = Buffer.from(config.vault.masterKey, 'base64');
|
|
17
|
+
if (this.masterKey.length !== 32) {
|
|
18
|
+
throw new Error('Vault master key must be 32 bytes (base64 encoded)');
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Encrypt a string value
|
|
23
|
+
*/
|
|
24
|
+
encrypt(plaintext) {
|
|
25
|
+
const iv = crypto.randomBytes(IV_LENGTH);
|
|
26
|
+
const cipher = crypto.createCipheriv(ALGORITHM, this.masterKey, iv);
|
|
27
|
+
const encrypted = Buffer.concat([
|
|
28
|
+
cipher.update(plaintext, 'utf8'),
|
|
29
|
+
cipher.final(),
|
|
30
|
+
]);
|
|
31
|
+
const authTag = cipher.getAuthTag();
|
|
32
|
+
// Format: base64(iv + authTag + ciphertext)
|
|
33
|
+
const combined = Buffer.concat([iv, authTag, encrypted]);
|
|
34
|
+
return combined.toString('base64');
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Decrypt a string value
|
|
38
|
+
*/
|
|
39
|
+
decrypt(ciphertext) {
|
|
40
|
+
const combined = Buffer.from(ciphertext, 'base64');
|
|
41
|
+
const iv = combined.subarray(0, IV_LENGTH);
|
|
42
|
+
const authTag = combined.subarray(IV_LENGTH, IV_LENGTH + AUTH_TAG_LENGTH);
|
|
43
|
+
const encrypted = combined.subarray(IV_LENGTH + AUTH_TAG_LENGTH);
|
|
44
|
+
const decipher = crypto.createDecipheriv(ALGORITHM, this.masterKey, iv);
|
|
45
|
+
decipher.setAuthTag(authTag);
|
|
46
|
+
const decrypted = Buffer.concat([
|
|
47
|
+
decipher.update(encrypted),
|
|
48
|
+
decipher.final(),
|
|
49
|
+
]);
|
|
50
|
+
return decrypted.toString('utf8');
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Store encrypted credential
|
|
54
|
+
*/
|
|
55
|
+
async storeCredential(credential) {
|
|
56
|
+
const encryptedAccessToken = this.encrypt(credential.accessToken);
|
|
57
|
+
const encryptedRefreshToken = credential.refreshToken
|
|
58
|
+
? this.encrypt(credential.refreshToken)
|
|
59
|
+
: undefined;
|
|
60
|
+
await db.credentials.upsert({
|
|
61
|
+
userId: credential.userId,
|
|
62
|
+
provider: credential.provider,
|
|
63
|
+
accessToken: encryptedAccessToken,
|
|
64
|
+
refreshToken: encryptedRefreshToken,
|
|
65
|
+
tokenExpiresAt: credential.tokenExpiresAt,
|
|
66
|
+
scopes: credential.scopes,
|
|
67
|
+
providerAccountId: credential.providerAccountId,
|
|
68
|
+
providerAccountEmail: credential.providerAccountEmail,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Retrieve and decrypt credential
|
|
73
|
+
*/
|
|
74
|
+
async getCredential(userId, provider) {
|
|
75
|
+
const credential = await db.credentials.findByUserAndProvider(userId, provider);
|
|
76
|
+
if (!credential) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
accessToken: this.decrypt(credential.accessToken),
|
|
81
|
+
refreshToken: credential.refreshToken
|
|
82
|
+
? this.decrypt(credential.refreshToken)
|
|
83
|
+
: undefined,
|
|
84
|
+
tokenExpiresAt: credential.tokenExpiresAt ?? undefined,
|
|
85
|
+
scopes: credential.scopes ?? undefined,
|
|
86
|
+
providerAccountId: credential.providerAccountId ?? undefined,
|
|
87
|
+
providerAccountEmail: credential.providerAccountEmail ?? undefined,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Get all credentials for a user (decrypted)
|
|
92
|
+
*/
|
|
93
|
+
async getUserCredentials(userId) {
|
|
94
|
+
const credentials = await db.credentials.findByUserId(userId);
|
|
95
|
+
const result = new Map();
|
|
96
|
+
for (const cred of credentials) {
|
|
97
|
+
result.set(cred.provider, {
|
|
98
|
+
accessToken: this.decrypt(cred.accessToken),
|
|
99
|
+
refreshToken: cred.refreshToken
|
|
100
|
+
? this.decrypt(cred.refreshToken)
|
|
101
|
+
: undefined,
|
|
102
|
+
tokenExpiresAt: cred.tokenExpiresAt ?? undefined,
|
|
103
|
+
scopes: cred.scopes ?? undefined,
|
|
104
|
+
providerAccountId: cred.providerAccountId ?? undefined,
|
|
105
|
+
providerAccountEmail: cred.providerAccountEmail ?? undefined,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Update tokens (e.g., after refresh)
|
|
112
|
+
*/
|
|
113
|
+
async updateTokens(userId, provider, accessToken, refreshToken, expiresAt) {
|
|
114
|
+
const encryptedAccessToken = this.encrypt(accessToken);
|
|
115
|
+
const encryptedRefreshToken = refreshToken
|
|
116
|
+
? this.encrypt(refreshToken)
|
|
117
|
+
: undefined;
|
|
118
|
+
await db.credentials.updateTokens(userId, provider, encryptedAccessToken, encryptedRefreshToken, expiresAt);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Delete credential
|
|
122
|
+
*/
|
|
123
|
+
async deleteCredential(userId, provider) {
|
|
124
|
+
await db.credentials.delete(userId, provider);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Check if credential needs refresh (within 5 minutes of expiry)
|
|
128
|
+
*/
|
|
129
|
+
async needsRefresh(userId, provider) {
|
|
130
|
+
const credential = await db.credentials.findByUserAndProvider(userId, provider);
|
|
131
|
+
if (!credential || !credential.tokenExpiresAt) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
const fiveMinutes = 5 * 60 * 1000;
|
|
135
|
+
return Date.now() > credential.tokenExpiresAt.getTime() - fiveMinutes;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Refresh OAuth token for a provider
|
|
139
|
+
*/
|
|
140
|
+
async refreshToken(userId, provider) {
|
|
141
|
+
const credential = await this.getCredential(userId, provider);
|
|
142
|
+
if (!credential?.refreshToken) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
// Provider-specific refresh endpoints
|
|
146
|
+
const refreshEndpoints = {
|
|
147
|
+
anthropic: 'https://api.anthropic.com/oauth/token',
|
|
148
|
+
openai: 'https://auth.openai.com/oauth/token',
|
|
149
|
+
google: 'https://oauth2.googleapis.com/token',
|
|
150
|
+
github: 'https://github.com/login/oauth/access_token',
|
|
151
|
+
};
|
|
152
|
+
const endpoint = refreshEndpoints[provider];
|
|
153
|
+
if (!endpoint) {
|
|
154
|
+
console.error(`Unknown provider for refresh: ${provider}`);
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
const config = getConfig();
|
|
159
|
+
const providerConfig = config.providers[provider];
|
|
160
|
+
const response = await fetch(endpoint, {
|
|
161
|
+
method: 'POST',
|
|
162
|
+
headers: {
|
|
163
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
164
|
+
Accept: 'application/json',
|
|
165
|
+
},
|
|
166
|
+
body: new URLSearchParams({
|
|
167
|
+
grant_type: 'refresh_token',
|
|
168
|
+
refresh_token: credential.refreshToken,
|
|
169
|
+
client_id: providerConfig?.clientId || config.github.clientId,
|
|
170
|
+
...(provider === 'google' && {
|
|
171
|
+
client_secret: providerConfig?.clientSecret,
|
|
172
|
+
}),
|
|
173
|
+
...(provider === 'github' && {
|
|
174
|
+
client_secret: config.github.clientSecret,
|
|
175
|
+
}),
|
|
176
|
+
}),
|
|
177
|
+
});
|
|
178
|
+
if (!response.ok) {
|
|
179
|
+
const error = await response.text();
|
|
180
|
+
console.error(`Token refresh failed for ${provider}:`, error);
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
const data = await response.json();
|
|
184
|
+
await this.updateTokens(userId, provider, data.access_token, data.refresh_token, data.expires_in
|
|
185
|
+
? new Date(Date.now() + data.expires_in * 1000)
|
|
186
|
+
: undefined);
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
console.error(`Error refreshing token for ${provider}:`, error);
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Singleton instance
|
|
196
|
+
let _vault = null;
|
|
197
|
+
export function getVault() {
|
|
198
|
+
if (!_vault) {
|
|
199
|
+
_vault = new CredentialVault();
|
|
200
|
+
}
|
|
201
|
+
return _vault;
|
|
202
|
+
}
|
|
203
|
+
export const vault = {
|
|
204
|
+
get instance() {
|
|
205
|
+
return getVault();
|
|
206
|
+
},
|
|
207
|
+
storeCredential: (cred) => getVault().storeCredential(cred),
|
|
208
|
+
getCredential: (userId, provider) => getVault().getCredential(userId, provider),
|
|
209
|
+
getUserCredentials: (userId) => getVault().getUserCredentials(userId),
|
|
210
|
+
updateTokens: (userId, provider, accessToken, refreshToken, expiresAt) => getVault().updateTokens(userId, provider, accessToken, refreshToken, expiresAt),
|
|
211
|
+
deleteCredential: (userId, provider) => getVault().deleteCredential(userId, provider),
|
|
212
|
+
needsRefresh: (userId, provider) => getVault().needsRefresh(userId, provider),
|
|
213
|
+
refreshToken: (userId, provider) => getVault().refreshToken(userId, provider),
|
|
214
|
+
};
|
|
215
|
+
// Generate a new master key (for setup)
|
|
216
|
+
export function generateMasterKey() {
|
|
217
|
+
return crypto.randomBytes(32).toString('base64');
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cloud/vault/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Manager
|
|
3
|
+
* Manages agents across workspaces with integrated resiliency.
|
|
4
|
+
*/
|
|
5
|
+
import { EventEmitter } from 'events';
|
|
6
|
+
import type { Agent, SpawnAgentRequest } from './types.js';
|
|
7
|
+
export declare class AgentManager extends EventEmitter {
|
|
8
|
+
private agents;
|
|
9
|
+
private supervisor;
|
|
10
|
+
private dataDir;
|
|
11
|
+
private logsDir;
|
|
12
|
+
constructor(dataDir: string);
|
|
13
|
+
/**
|
|
14
|
+
* Spawn a new agent in a workspace
|
|
15
|
+
*/
|
|
16
|
+
spawn(workspaceId: string, workspacePath: string, request: SpawnAgentRequest): Promise<Agent>;
|
|
17
|
+
/**
|
|
18
|
+
* Stop an agent
|
|
19
|
+
*/
|
|
20
|
+
stop(agentId: string): Promise<boolean>;
|
|
21
|
+
/**
|
|
22
|
+
* Stop all agents in a workspace
|
|
23
|
+
*/
|
|
24
|
+
stopAllInWorkspace(workspaceId: string): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Stop all agents
|
|
27
|
+
*/
|
|
28
|
+
stopAll(): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Get an agent by ID
|
|
31
|
+
*/
|
|
32
|
+
get(agentId: string): Agent | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Get all agents in a workspace
|
|
35
|
+
*/
|
|
36
|
+
getByWorkspace(workspaceId: string): Agent[];
|
|
37
|
+
/**
|
|
38
|
+
* Get all agents
|
|
39
|
+
*/
|
|
40
|
+
getAll(): Agent[];
|
|
41
|
+
/**
|
|
42
|
+
* Find agent by name in a workspace
|
|
43
|
+
*/
|
|
44
|
+
findByName(workspaceId: string, name: string): Agent | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Get agent output/logs
|
|
47
|
+
*/
|
|
48
|
+
getOutput(agentId: string, limit?: number): string[] | null;
|
|
49
|
+
/**
|
|
50
|
+
* Get raw output from agent
|
|
51
|
+
*/
|
|
52
|
+
getRawOutput(agentId: string): string | null;
|
|
53
|
+
/**
|
|
54
|
+
* Send input to an agent
|
|
55
|
+
*/
|
|
56
|
+
sendInput(agentId: string, input: string): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Restart an agent
|
|
59
|
+
*/
|
|
60
|
+
private restartAgent;
|
|
61
|
+
/**
|
|
62
|
+
* Handle agent exit
|
|
63
|
+
*/
|
|
64
|
+
private handleAgentExit;
|
|
65
|
+
/**
|
|
66
|
+
* Setup supervisor event handlers
|
|
67
|
+
*/
|
|
68
|
+
private setupSupervisorEvents;
|
|
69
|
+
/**
|
|
70
|
+
* Get CLI command for provider
|
|
71
|
+
*/
|
|
72
|
+
private getCliCommand;
|
|
73
|
+
/**
|
|
74
|
+
* Convert internal agent to public agent (without pty reference)
|
|
75
|
+
*/
|
|
76
|
+
private toPublicAgent;
|
|
77
|
+
/**
|
|
78
|
+
* Emit a daemon event
|
|
79
|
+
*/
|
|
80
|
+
private emitEvent;
|
|
81
|
+
/**
|
|
82
|
+
* Shutdown the agent manager
|
|
83
|
+
*/
|
|
84
|
+
shutdown(): Promise<void>;
|
|
85
|
+
}
|
|
86
|
+
export declare function getAgentManager(dataDir?: string): AgentManager;
|
|
87
|
+
//# sourceMappingURL=agent-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-manager.d.ts","sourceRoot":"","sources":["../../src/daemon/agent-manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAMtC,OAAO,KAAK,EACV,KAAK,EAGL,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAYpB,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,UAAU,CAOf;IACH,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,EAAE,MAAM;IAmB3B;;OAEG;IACG,KAAK,CACT,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,KAAK,CAAC;IA2HjB;;OAEG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA2C7C;;OAEG;IACG,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO5D;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAO9B;;OAEG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAKvC;;OAEG;IACH,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,KAAK,EAAE;IAM5C;;OAEG;IACH,MAAM,IAAI,KAAK,EAAE;IAIjB;;OAEG;IACH,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAOhE;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI;IAM3D;;OAEG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAM5C;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO;IAOlD;;OAEG;YACW,YAAY;IA0D1B;;OAEG;IACH,OAAO,CAAC,eAAe;IAmBvB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAmB7B;;OAEG;IACH,OAAO,CAAC,aAAa;IAarB;;OAEG;IACH,OAAO,CAAC,aAAa;IAgBrB;;OAEG;IACH,OAAO,CAAC,SAAS;IAIjB;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAKhC;AAID,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY,CAM9D"}
|