@geteigen/cli 0.0.0-stage → 3.0.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 +154 -2
- package/dist/agent.d.ts +32 -0
- package/dist/agent.js +246 -0
- package/dist/auth.d.ts +5 -0
- package/dist/auth.js +33 -0
- package/dist/cli/src/agent.d.ts +24 -0
- package/dist/cli/src/agent.js +260 -0
- package/dist/cli/src/agentTools.d.ts +10 -0
- package/dist/cli/src/agentTools.js +70 -0
- package/dist/cli/src/auth.d.ts +5 -0
- package/dist/cli/src/auth.js +33 -0
- package/dist/cli/src/config.d.ts +11 -0
- package/dist/cli/src/config.js +51 -0
- package/dist/cli/src/cursorAuth.d.ts +10 -0
- package/dist/cli/src/cursorAuth.js +92 -0
- package/dist/cli/src/index.d.ts +2 -0
- package/dist/cli/src/index.js +244 -0
- package/dist/cli/src/listModels.d.ts +14 -0
- package/dist/cli/src/listModels.js +196 -0
- package/dist/cli/src/listSessions.d.ts +9 -0
- package/dist/cli/src/listSessions.js +37 -0
- package/dist/cli/src/machineConfig.d.ts +20 -0
- package/dist/cli/src/machineConfig.js +66 -0
- package/dist/cli/src/pickFolder.d.ts +5 -0
- package/dist/cli/src/pickFolder.js +65 -0
- package/dist/cli/src/proc.d.ts +23 -0
- package/dist/cli/src/proc.js +77 -0
- package/dist/cli/src/service.d.ts +17 -0
- package/dist/cli/src/service.js +246 -0
- package/dist/cli/src/workRoots.d.ts +30 -0
- package/dist/cli/src/workRoots.js +221 -0
- package/dist/cli/src/worker.d.ts +8 -0
- package/dist/cli/src/worker.js +51 -0
- package/dist/cli/src/workerCore.d.ts +47 -0
- package/dist/cli/src/workerCore.js +702 -0
- package/dist/cli/src/workspace.d.ts +8 -0
- package/dist/cli/src/workspace.js +269 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.js +51 -0
- package/dist/cursorAuth.d.ts +10 -0
- package/dist/cursorAuth.js +95 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +108 -0
- package/dist/listModels.d.ts +6 -0
- package/dist/listModels.js +62 -0
- package/dist/listSessions.d.ts +9 -0
- package/dist/listSessions.js +37 -0
- package/dist/pickFolder.d.ts +5 -0
- package/dist/pickFolder.js +65 -0
- package/dist/shared/actionDrafts.d.ts +83 -0
- package/dist/shared/actionDrafts.js +169 -0
- package/dist/shared/agentArtifacts.d.ts +49 -0
- package/dist/shared/agentArtifacts.js +169 -0
- package/dist/shared/agentLabel.d.ts +18 -0
- package/dist/shared/agentLabel.js +22 -0
- package/dist/shared/agentMentions.d.ts +38 -0
- package/dist/shared/agentMentions.js +110 -0
- package/dist/shared/agentRepos.d.ts +28 -0
- package/dist/shared/agentRepos.js +60 -0
- package/dist/shared/agentRunStatus.d.ts +12 -0
- package/dist/shared/agentRunStatus.js +17 -0
- package/dist/shared/agentUsage.d.ts +24 -0
- package/dist/shared/agentUsage.js +139 -0
- package/dist/shared/approvals.d.ts +44 -0
- package/dist/shared/approvals.js +97 -0
- package/dist/shared/askEigen.d.ts +190 -0
- package/dist/shared/askEigen.js +76 -0
- package/dist/shared/attribution.d.ts +25 -0
- package/dist/shared/attribution.js +63 -0
- package/dist/shared/automations.d.ts +136 -0
- package/dist/shared/automations.js +546 -0
- package/dist/shared/backends/claudeCode.d.ts +42 -0
- package/dist/shared/backends/claudeCode.js +540 -0
- package/dist/shared/backends/codex.d.ts +15 -0
- package/dist/shared/backends/codex.js +287 -0
- package/dist/shared/backends/cursor.d.ts +102 -0
- package/dist/shared/backends/cursor.js +1197 -0
- package/dist/shared/backends/index.d.ts +18 -0
- package/dist/shared/backends/index.js +58 -0
- package/dist/shared/backends/opencode.d.ts +40 -0
- package/dist/shared/backends/opencode.js +397 -0
- package/dist/shared/backends/types.d.ts +171 -0
- package/dist/shared/backends/types.js +19 -0
- package/dist/shared/backends/usage.d.ts +8 -0
- package/dist/shared/backends/usage.js +71 -0
- package/dist/shared/billingPlans.d.ts +60 -0
- package/dist/shared/billingPlans.js +262 -0
- package/dist/shared/brain.d.ts +353 -0
- package/dist/shared/brain.js +487 -0
- package/dist/shared/clarifyingQuestions.d.ts +13 -0
- package/dist/shared/clarifyingQuestions.js +207 -0
- package/dist/shared/claudeModels.d.ts +10 -0
- package/dist/shared/claudeModels.js +52 -0
- package/dist/shared/cloudBackends.d.ts +21 -0
- package/dist/shared/cloudBackends.js +29 -0
- package/dist/shared/codexModels.d.ts +10 -0
- package/dist/shared/codexModels.js +28 -0
- package/dist/shared/contextWindows.d.ts +2 -0
- package/dist/shared/contextWindows.js +30 -0
- package/dist/shared/cursorMcpConfig.d.ts +14 -0
- package/dist/shared/cursorMcpConfig.js +43 -0
- package/dist/shared/cursorProjectMcp.d.ts +10 -0
- package/dist/shared/cursorProjectMcp.js +42 -0
- package/dist/shared/docs.d.ts +59 -0
- package/dist/shared/docs.js +87 -0
- package/dist/shared/events.d.ts +929 -0
- package/dist/shared/events.js +59 -0
- package/dist/shared/integrations.d.ts +266 -0
- package/dist/shared/integrations.js +449 -0
- package/dist/shared/issueTranscript.d.ts +64 -0
- package/dist/shared/issueTranscript.js +387 -0
- package/dist/shared/issues.d.ts +139 -0
- package/dist/shared/issues.js +217 -0
- package/dist/shared/machines.d.ts +115 -0
- package/dist/shared/machines.js +58 -0
- package/dist/shared/markdownMedia.d.ts +13 -0
- package/dist/shared/markdownMedia.js +41 -0
- package/dist/shared/notificationText.d.ts +6 -0
- package/dist/shared/notificationText.js +38 -0
- package/dist/shared/opencodeModels.d.ts +19 -0
- package/dist/shared/opencodeModels.js +62 -0
- package/dist/shared/opencodeSession.d.ts +7 -0
- package/dist/shared/opencodeSession.js +30 -0
- package/dist/shared/orchestration.d.ts +58 -0
- package/dist/shared/orchestration.js +12 -0
- package/dist/shared/orgs.d.ts +47 -0
- package/dist/shared/orgs.js +49 -0
- package/dist/shared/personalOrg.d.ts +5 -0
- package/dist/shared/personalOrg.js +12 -0
- package/dist/shared/plans.d.ts +3 -0
- package/dist/shared/plans.js +19 -0
- package/dist/shared/providerModels.d.ts +40 -0
- package/dist/shared/providerModels.js +503 -0
- package/dist/shared/roomAttention.d.ts +17 -0
- package/dist/shared/roomAttention.js +36 -0
- package/dist/shared/roomContext.d.ts +120 -0
- package/dist/shared/roomContext.js +133 -0
- package/dist/shared/roomPermissions.d.ts +56 -0
- package/dist/shared/roomPermissions.js +133 -0
- package/dist/shared/sessionSeats.d.ts +29 -0
- package/dist/shared/sessionSeats.js +57 -0
- package/dist/shared/slashCommands.d.ts +39 -0
- package/dist/shared/slashCommands.js +166 -0
- package/dist/shared/space.d.ts +33 -0
- package/dist/shared/space.js +54 -0
- package/dist/shared/spaceFeed.d.ts +78 -0
- package/dist/shared/spaceFeed.js +194 -0
- package/dist/shared/stringifyUnknown.d.ts +1 -0
- package/dist/shared/stringifyUnknown.js +1 -0
- package/dist/shared/swarm.d.ts +320 -0
- package/dist/shared/swarm.js +328 -0
- package/dist/shared/swarmVisual.d.ts +79 -0
- package/dist/shared/swarmVisual.js +212 -0
- package/dist/shared/terminalFilter.d.ts +13 -0
- package/dist/shared/terminalFilter.js +46 -0
- package/dist/shared/toolIntegration.d.ts +56 -0
- package/dist/shared/toolIntegration.js +180 -0
- package/dist/shared/typing.d.ts +9 -0
- package/dist/shared/typing.js +37 -0
- package/dist/shared/uploads.d.ts +31 -0
- package/dist/shared/uploads.js +65 -0
- package/dist/shared/voiceApprovals.d.ts +36 -0
- package/dist/shared/voiceApprovals.js +229 -0
- package/dist/shared/workspace.d.ts +47 -0
- package/dist/shared/workspace.js +40 -0
- package/dist/worker.d.ts +1 -0
- package/dist/worker.js +266 -0
- package/package.json +51 -4
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** Claude Code, Codex, and OpenCode share the local-CLI + Blaxel-sandbox path. */
|
|
2
|
+
export const CLI_SANDBOX_BACKENDS = ["claude-code", "codex", "opencode"];
|
|
3
|
+
export function isCliSandboxBackend(kind) {
|
|
4
|
+
return kind === "claude-code" || kind === "codex" || kind === "opencode";
|
|
5
|
+
}
|
|
6
|
+
export function parseAgentBackendKind(raw) {
|
|
7
|
+
if (raw === "claude-code" || raw === "codex" || raw === "opencode")
|
|
8
|
+
return raw;
|
|
9
|
+
return "cursor";
|
|
10
|
+
}
|
|
11
|
+
export function backendShortLabel(kind) {
|
|
12
|
+
if (kind === "claude-code")
|
|
13
|
+
return "Claude";
|
|
14
|
+
if (kind === "codex")
|
|
15
|
+
return "Codex";
|
|
16
|
+
if (kind === "opencode")
|
|
17
|
+
return "OpenCode";
|
|
18
|
+
return "Cursor";
|
|
19
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AgentBackendKind, RunUsage } from "./types.js";
|
|
2
|
+
/** Claude Code `result` line: `usage` plus `total_cost_usd`. */
|
|
3
|
+
export declare function claudeResultUsage(ev: Record<string, unknown>): RunUsage | undefined;
|
|
4
|
+
/** Codex `turn.completed`: `usage` with input / cached / output tokens. */
|
|
5
|
+
export declare function codexTurnUsage(ev: Record<string, unknown>): RunUsage | undefined;
|
|
6
|
+
export declare function runUsageCostUsd(backend: AgentBackendKind, usage: RunUsage): number;
|
|
7
|
+
export declare function addRunUsage(total: RunUsage, next: RunUsage, backend: AgentBackendKind): RunUsage;
|
|
8
|
+
export declare const EMPTY_RUN_USAGE: RunUsage;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
function num(value) {
|
|
2
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
3
|
+
return Number.isFinite(n) && n > 0 ? n : 0;
|
|
4
|
+
}
|
|
5
|
+
function record(value) {
|
|
6
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
7
|
+
? value
|
|
8
|
+
: null;
|
|
9
|
+
}
|
|
10
|
+
/** Claude Code `result` line: `usage` plus `total_cost_usd`. */
|
|
11
|
+
export function claudeResultUsage(ev) {
|
|
12
|
+
const usage = record(ev.usage);
|
|
13
|
+
const cost = num(ev.total_cost_usd);
|
|
14
|
+
if (!usage && !cost)
|
|
15
|
+
return undefined;
|
|
16
|
+
return {
|
|
17
|
+
inputTokens: num(usage?.input_tokens),
|
|
18
|
+
outputTokens: num(usage?.output_tokens),
|
|
19
|
+
cacheReadTokens: num(usage?.cache_read_input_tokens),
|
|
20
|
+
cacheWriteTokens: num(usage?.cache_creation_input_tokens),
|
|
21
|
+
...(cost ? { costUsd: cost } : {}),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** Codex `turn.completed`: `usage` with input / cached / output tokens. */
|
|
25
|
+
export function codexTurnUsage(ev) {
|
|
26
|
+
const usage = record(ev.usage);
|
|
27
|
+
if (!usage)
|
|
28
|
+
return undefined;
|
|
29
|
+
const cached = num(usage.cached_input_tokens);
|
|
30
|
+
return {
|
|
31
|
+
// OpenAI counts cached tokens inside input_tokens.
|
|
32
|
+
inputTokens: Math.max(0, num(usage.input_tokens) - cached),
|
|
33
|
+
outputTokens: num(usage.output_tokens),
|
|
34
|
+
cacheReadTokens: cached,
|
|
35
|
+
cacheWriteTokens: 0,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** USD per million tokens, used only when the CLI doesn't report cost. */
|
|
39
|
+
const ESTIMATE_RATES = {
|
|
40
|
+
"claude-code": { input: 3, cached: 0.3, output: 15 },
|
|
41
|
+
codex: { input: 1.25, cached: 0.125, output: 10 },
|
|
42
|
+
// OpenCode reports cost directly; model-specific fallback rates would be wrong.
|
|
43
|
+
opencode: { input: 0, cached: 0, output: 0 },
|
|
44
|
+
};
|
|
45
|
+
export function runUsageCostUsd(backend, usage) {
|
|
46
|
+
if (usage.costUsd != null)
|
|
47
|
+
return usage.costUsd;
|
|
48
|
+
if (backend === "cursor")
|
|
49
|
+
return 0;
|
|
50
|
+
const rate = ESTIMATE_RATES[backend];
|
|
51
|
+
return ((usage.inputTokens * rate.input +
|
|
52
|
+
(usage.cacheReadTokens + usage.cacheWriteTokens) * rate.cached +
|
|
53
|
+
usage.outputTokens * rate.output) /
|
|
54
|
+
1_000_000);
|
|
55
|
+
}
|
|
56
|
+
export function addRunUsage(total, next, backend) {
|
|
57
|
+
return {
|
|
58
|
+
inputTokens: total.inputTokens + next.inputTokens,
|
|
59
|
+
outputTokens: total.outputTokens + next.outputTokens,
|
|
60
|
+
cacheReadTokens: total.cacheReadTokens + next.cacheReadTokens,
|
|
61
|
+
cacheWriteTokens: total.cacheWriteTokens + next.cacheWriteTokens,
|
|
62
|
+
costUsd: (total.costUsd ?? 0) + runUsageCostUsd(backend, next),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export const EMPTY_RUN_USAGE = {
|
|
66
|
+
inputTokens: 0,
|
|
67
|
+
outputTokens: 0,
|
|
68
|
+
cacheReadTokens: 0,
|
|
69
|
+
cacheWriteTokens: 0,
|
|
70
|
+
costUsd: 0,
|
|
71
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace billing plans. `null` on a numeric limit means unlimited.
|
|
3
|
+
* Effective limits are PLAN_DEFAULTS, then BILLING_PLAN_OVERRIDES, then a
|
|
4
|
+
* per-organization override stored by an admin.
|
|
5
|
+
*/
|
|
6
|
+
export type PlanId = "free" | "team" | "business";
|
|
7
|
+
export declare const PLAN_IDS: PlanId[];
|
|
8
|
+
export declare const PLAN_RANK: Record<PlanId, number>;
|
|
9
|
+
export declare const PLAN_LABELS: Record<PlanId, string>;
|
|
10
|
+
/** Runner safety cap when a plan leaves concurrent issues unlimited. */
|
|
11
|
+
export declare const ABSOLUTE_MAX_CONCURRENT_ISSUES = 64;
|
|
12
|
+
export interface PlanLimits {
|
|
13
|
+
maxWorkspaces: number | null;
|
|
14
|
+
maxDrivers: number | null;
|
|
15
|
+
maxViewers: number | null;
|
|
16
|
+
maxConcurrentRooms: number | null;
|
|
17
|
+
maxConcurrentIssues: number | null;
|
|
18
|
+
maxQueuedIssues: number | null;
|
|
19
|
+
issuesPerDay: number | null;
|
|
20
|
+
swarmsPerWeek: number | null;
|
|
21
|
+
maxSwarmAgents: number | null;
|
|
22
|
+
swarmBudgetUsd: number | null;
|
|
23
|
+
maxIntegrations: number | null;
|
|
24
|
+
/**
|
|
25
|
+
* Included hosted-tool spend per calendar month, in USD.
|
|
26
|
+
* `0` blocks hosted calls. `null` means unlimited. Not per seat.
|
|
27
|
+
*/
|
|
28
|
+
hostedToolsUsdPerMonth: number | null;
|
|
29
|
+
/** Included hosted minutes per calendar month. Team multiplies by driver seats. */
|
|
30
|
+
sandboxMinutesPerMonth: number | null;
|
|
31
|
+
sandboxMinutesPerSeat: boolean;
|
|
32
|
+
maxConcurrentSandboxes: number | null;
|
|
33
|
+
sandboxMaxRunMinutes: number | null;
|
|
34
|
+
sandboxMemoryMb: number;
|
|
35
|
+
allowOverage: boolean;
|
|
36
|
+
policy: boolean;
|
|
37
|
+
/** Days of audit-log history kept and shown. `null` keeps everything. */
|
|
38
|
+
auditRetentionDays: number | null;
|
|
39
|
+
auditExport: boolean;
|
|
40
|
+
sso: boolean;
|
|
41
|
+
customMcpAllowlist: boolean;
|
|
42
|
+
hostedSandbox: boolean;
|
|
43
|
+
}
|
|
44
|
+
export type PlanLimitKey = keyof PlanLimits;
|
|
45
|
+
export declare const PLAN_DEFAULTS: Record<PlanId, PlanLimits>;
|
|
46
|
+
export declare const LIMIT_LABELS: Record<PlanLimitKey, string>;
|
|
47
|
+
export declare function isPlanId(value: unknown): value is PlanId;
|
|
48
|
+
export declare function higherPlan(a: PlanId, b: PlanId): PlanId;
|
|
49
|
+
export declare function parsePlanId(value: unknown, fallback?: PlanId): PlanId;
|
|
50
|
+
/** Keep only known limit fields. `null` is preserved and means unlimited. */
|
|
51
|
+
export declare function parseLimitsOverride(raw: unknown): Partial<PlanLimits> | null;
|
|
52
|
+
export declare function mergePlanLimits(base: PlanLimits, ...overrides: Array<Partial<PlanLimits> | null | undefined>): PlanLimits;
|
|
53
|
+
export declare function envPlanOverrides(): Partial<Record<PlanId, Partial<PlanLimits>>>;
|
|
54
|
+
export declare function limitsForPlan(plan: PlanId, orgOverride?: Partial<PlanLimits> | null): PlanLimits;
|
|
55
|
+
/** Oldest audit row a plan keeps/shows (ms epoch), or null for full history. */
|
|
56
|
+
export declare function auditCutoffMs(limits: PlanLimits, now?: number): number | null;
|
|
57
|
+
export declare function monthStartMs(now?: number): number;
|
|
58
|
+
export declare function dayStartMs(now?: number): number;
|
|
59
|
+
export declare function weekStartMs(now?: number): number;
|
|
60
|
+
export declare function includedSandboxSeconds(limits: PlanLimits, driverSeats: number): number | null;
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace billing plans. `null` on a numeric limit means unlimited.
|
|
3
|
+
* Effective limits are PLAN_DEFAULTS, then BILLING_PLAN_OVERRIDES, then a
|
|
4
|
+
* per-organization override stored by an admin.
|
|
5
|
+
*/
|
|
6
|
+
export const PLAN_IDS = ["free", "team", "business"];
|
|
7
|
+
export const PLAN_RANK = {
|
|
8
|
+
free: 0,
|
|
9
|
+
team: 1,
|
|
10
|
+
business: 2,
|
|
11
|
+
};
|
|
12
|
+
export const PLAN_LABELS = {
|
|
13
|
+
free: "Free",
|
|
14
|
+
team: "Team",
|
|
15
|
+
business: "Business",
|
|
16
|
+
};
|
|
17
|
+
/** Runner safety cap when a plan leaves concurrent issues unlimited. */
|
|
18
|
+
export const ABSOLUTE_MAX_CONCURRENT_ISSUES = 64;
|
|
19
|
+
export const PLAN_DEFAULTS = {
|
|
20
|
+
free: {
|
|
21
|
+
maxWorkspaces: 2,
|
|
22
|
+
maxDrivers: 3,
|
|
23
|
+
maxViewers: 5,
|
|
24
|
+
maxConcurrentRooms: 3,
|
|
25
|
+
maxConcurrentIssues: 3,
|
|
26
|
+
maxQueuedIssues: 25,
|
|
27
|
+
issuesPerDay: 20,
|
|
28
|
+
swarmsPerWeek: 1,
|
|
29
|
+
maxSwarmAgents: 8,
|
|
30
|
+
swarmBudgetUsd: 25,
|
|
31
|
+
maxIntegrations: 10,
|
|
32
|
+
hostedToolsUsdPerMonth: 0,
|
|
33
|
+
sandboxMinutesPerMonth: 60,
|
|
34
|
+
sandboxMinutesPerSeat: false,
|
|
35
|
+
maxConcurrentSandboxes: 1,
|
|
36
|
+
sandboxMaxRunMinutes: 20,
|
|
37
|
+
sandboxMemoryMb: 2048,
|
|
38
|
+
allowOverage: false,
|
|
39
|
+
policy: false,
|
|
40
|
+
auditRetentionDays: 7,
|
|
41
|
+
auditExport: false,
|
|
42
|
+
sso: false,
|
|
43
|
+
customMcpAllowlist: false,
|
|
44
|
+
hostedSandbox: true,
|
|
45
|
+
},
|
|
46
|
+
team: {
|
|
47
|
+
maxWorkspaces: 10,
|
|
48
|
+
maxDrivers: null,
|
|
49
|
+
maxViewers: null,
|
|
50
|
+
maxConcurrentRooms: 25,
|
|
51
|
+
maxConcurrentIssues: 15,
|
|
52
|
+
maxQueuedIssues: 200,
|
|
53
|
+
issuesPerDay: null,
|
|
54
|
+
swarmsPerWeek: 20,
|
|
55
|
+
maxSwarmAgents: 20,
|
|
56
|
+
swarmBudgetUsd: 100,
|
|
57
|
+
maxIntegrations: null,
|
|
58
|
+
hostedToolsUsdPerMonth: 0,
|
|
59
|
+
sandboxMinutesPerMonth: 600,
|
|
60
|
+
sandboxMinutesPerSeat: true,
|
|
61
|
+
maxConcurrentSandboxes: 10,
|
|
62
|
+
sandboxMaxRunMinutes: 120,
|
|
63
|
+
sandboxMemoryMb: 4096,
|
|
64
|
+
allowOverage: true,
|
|
65
|
+
policy: true,
|
|
66
|
+
auditRetentionDays: 90,
|
|
67
|
+
auditExport: false,
|
|
68
|
+
sso: false,
|
|
69
|
+
customMcpAllowlist: false,
|
|
70
|
+
hostedSandbox: true,
|
|
71
|
+
},
|
|
72
|
+
business: {
|
|
73
|
+
maxWorkspaces: null,
|
|
74
|
+
maxDrivers: null,
|
|
75
|
+
maxViewers: null,
|
|
76
|
+
maxConcurrentRooms: null,
|
|
77
|
+
maxConcurrentIssues: null,
|
|
78
|
+
maxQueuedIssues: null,
|
|
79
|
+
issuesPerDay: null,
|
|
80
|
+
swarmsPerWeek: null,
|
|
81
|
+
maxSwarmAgents: null,
|
|
82
|
+
swarmBudgetUsd: null,
|
|
83
|
+
maxIntegrations: null,
|
|
84
|
+
hostedToolsUsdPerMonth: 0,
|
|
85
|
+
sandboxMinutesPerMonth: null,
|
|
86
|
+
sandboxMinutesPerSeat: false,
|
|
87
|
+
maxConcurrentSandboxes: null,
|
|
88
|
+
sandboxMaxRunMinutes: 240,
|
|
89
|
+
sandboxMemoryMb: 8192,
|
|
90
|
+
allowOverage: true,
|
|
91
|
+
policy: true,
|
|
92
|
+
auditRetentionDays: null,
|
|
93
|
+
auditExport: true,
|
|
94
|
+
sso: true,
|
|
95
|
+
customMcpAllowlist: true,
|
|
96
|
+
hostedSandbox: true,
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
const NUMERIC_KEYS = [
|
|
100
|
+
"maxWorkspaces",
|
|
101
|
+
"maxDrivers",
|
|
102
|
+
"maxViewers",
|
|
103
|
+
"maxConcurrentRooms",
|
|
104
|
+
"maxConcurrentIssues",
|
|
105
|
+
"maxQueuedIssues",
|
|
106
|
+
"issuesPerDay",
|
|
107
|
+
"swarmsPerWeek",
|
|
108
|
+
"maxSwarmAgents",
|
|
109
|
+
"swarmBudgetUsd",
|
|
110
|
+
"maxIntegrations",
|
|
111
|
+
"hostedToolsUsdPerMonth",
|
|
112
|
+
"sandboxMinutesPerMonth",
|
|
113
|
+
"maxConcurrentSandboxes",
|
|
114
|
+
"sandboxMaxRunMinutes",
|
|
115
|
+
"sandboxMemoryMb",
|
|
116
|
+
"auditRetentionDays",
|
|
117
|
+
];
|
|
118
|
+
const BOOLEAN_KEYS = [
|
|
119
|
+
"sandboxMinutesPerSeat",
|
|
120
|
+
"allowOverage",
|
|
121
|
+
"policy",
|
|
122
|
+
"auditExport",
|
|
123
|
+
"sso",
|
|
124
|
+
"customMcpAllowlist",
|
|
125
|
+
"hostedSandbox",
|
|
126
|
+
];
|
|
127
|
+
export const LIMIT_LABELS = {
|
|
128
|
+
maxWorkspaces: "workspaces",
|
|
129
|
+
maxDrivers: "drivers",
|
|
130
|
+
maxViewers: "viewers",
|
|
131
|
+
maxConcurrentRooms: "concurrent rooms",
|
|
132
|
+
maxConcurrentIssues: "concurrent issues",
|
|
133
|
+
maxQueuedIssues: "queued issues",
|
|
134
|
+
issuesPerDay: "issue runs per day",
|
|
135
|
+
swarmsPerWeek: "swarms per week",
|
|
136
|
+
maxSwarmAgents: "swarm agents",
|
|
137
|
+
swarmBudgetUsd: "swarm budget",
|
|
138
|
+
maxIntegrations: "integrations",
|
|
139
|
+
hostedToolsUsdPerMonth: "hosted tools",
|
|
140
|
+
sandboxMinutesPerMonth: "hosted sandbox minutes",
|
|
141
|
+
sandboxMinutesPerSeat: "sandbox minutes per seat",
|
|
142
|
+
maxConcurrentSandboxes: "concurrent sandboxes",
|
|
143
|
+
sandboxMaxRunMinutes: "sandbox run length",
|
|
144
|
+
sandboxMemoryMb: "sandbox memory",
|
|
145
|
+
allowOverage: "sandbox overage",
|
|
146
|
+
policy: "integration policy",
|
|
147
|
+
auditRetentionDays: "audit log history",
|
|
148
|
+
auditExport: "audit export",
|
|
149
|
+
sso: "SSO",
|
|
150
|
+
customMcpAllowlist: "custom MCP allowlist",
|
|
151
|
+
hostedSandbox: "hosted sandboxes",
|
|
152
|
+
};
|
|
153
|
+
export function isPlanId(value) {
|
|
154
|
+
return value === "free" || value === "team" || value === "business";
|
|
155
|
+
}
|
|
156
|
+
export function higherPlan(a, b) {
|
|
157
|
+
return PLAN_RANK[a] >= PLAN_RANK[b] ? a : b;
|
|
158
|
+
}
|
|
159
|
+
export function parsePlanId(value, fallback = "free") {
|
|
160
|
+
return isPlanId(value) ? value : fallback;
|
|
161
|
+
}
|
|
162
|
+
function asLimitNumber(value) {
|
|
163
|
+
if (value === null)
|
|
164
|
+
return null;
|
|
165
|
+
if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
168
|
+
if (typeof value === "string" && value.trim()) {
|
|
169
|
+
const n = Number(value);
|
|
170
|
+
if (Number.isFinite(n) && n >= 0)
|
|
171
|
+
return n;
|
|
172
|
+
}
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
/** Keep only known limit fields. `null` is preserved and means unlimited. */
|
|
176
|
+
export function parseLimitsOverride(raw) {
|
|
177
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
178
|
+
return null;
|
|
179
|
+
const src = raw;
|
|
180
|
+
const out = {};
|
|
181
|
+
let any = false;
|
|
182
|
+
for (const key of NUMERIC_KEYS) {
|
|
183
|
+
if (!(key in src))
|
|
184
|
+
continue;
|
|
185
|
+
const n = asLimitNumber(src[key]);
|
|
186
|
+
if (n === undefined)
|
|
187
|
+
continue;
|
|
188
|
+
out[key] = n;
|
|
189
|
+
any = true;
|
|
190
|
+
}
|
|
191
|
+
for (const key of BOOLEAN_KEYS) {
|
|
192
|
+
if (typeof src[key] === "boolean") {
|
|
193
|
+
out[key] = src[key];
|
|
194
|
+
any = true;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return any ? out : null;
|
|
198
|
+
}
|
|
199
|
+
export function mergePlanLimits(base, ...overrides) {
|
|
200
|
+
const out = { ...base };
|
|
201
|
+
for (const over of overrides) {
|
|
202
|
+
if (!over)
|
|
203
|
+
continue;
|
|
204
|
+
for (const key of NUMERIC_KEYS) {
|
|
205
|
+
if (over[key] !== undefined) {
|
|
206
|
+
out[key] = over[key];
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
for (const key of BOOLEAN_KEYS) {
|
|
210
|
+
if (over[key] !== undefined)
|
|
211
|
+
out[key] = over[key];
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (!Number.isFinite(out.sandboxMemoryMb) || out.sandboxMemoryMb < 512) {
|
|
215
|
+
out.sandboxMemoryMb = base.sandboxMemoryMb;
|
|
216
|
+
}
|
|
217
|
+
return out;
|
|
218
|
+
}
|
|
219
|
+
export function envPlanOverrides() {
|
|
220
|
+
const raw = process.env.BILLING_PLAN_OVERRIDES?.trim();
|
|
221
|
+
if (!raw)
|
|
222
|
+
return {};
|
|
223
|
+
try {
|
|
224
|
+
const parsed = JSON.parse(raw);
|
|
225
|
+
const out = {};
|
|
226
|
+
for (const id of PLAN_IDS) {
|
|
227
|
+
const patch = parseLimitsOverride(parsed[id]);
|
|
228
|
+
if (patch)
|
|
229
|
+
out[id] = patch;
|
|
230
|
+
}
|
|
231
|
+
return out;
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
return {};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
export function limitsForPlan(plan, orgOverride) {
|
|
238
|
+
return mergePlanLimits(PLAN_DEFAULTS[plan], envPlanOverrides()[plan], orgOverride);
|
|
239
|
+
}
|
|
240
|
+
/** Oldest audit row a plan keeps/shows (ms epoch), or null for full history. */
|
|
241
|
+
export function auditCutoffMs(limits, now = Date.now()) {
|
|
242
|
+
if (limits.auditRetentionDays == null)
|
|
243
|
+
return null;
|
|
244
|
+
return now - limits.auditRetentionDays * 24 * 60 * 60 * 1000;
|
|
245
|
+
}
|
|
246
|
+
export function monthStartMs(now = Date.now()) {
|
|
247
|
+
const d = new Date(now);
|
|
248
|
+
return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1);
|
|
249
|
+
}
|
|
250
|
+
export function dayStartMs(now = Date.now()) {
|
|
251
|
+
const d = new Date(now);
|
|
252
|
+
return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
|
|
253
|
+
}
|
|
254
|
+
export function weekStartMs(now = Date.now()) {
|
|
255
|
+
return now - 7 * 24 * 60 * 60 * 1000;
|
|
256
|
+
}
|
|
257
|
+
export function includedSandboxSeconds(limits, driverSeats) {
|
|
258
|
+
if (limits.sandboxMinutesPerMonth == null)
|
|
259
|
+
return null;
|
|
260
|
+
const seats = limits.sandboxMinutesPerSeat ? Math.max(1, driverSeats) : 1;
|
|
261
|
+
return Math.round(limits.sandboxMinutesPerMonth * seats * 60);
|
|
262
|
+
}
|