|
| 1 | +import path from "node:path"; |
| 2 | +import type { WorkspaceMode } from "@shared/types"; |
| 3 | +import { getCurrentBranch, getDefaultBranch } from "../git"; |
| 4 | + |
| 5 | +export interface WorkspaceEnvContext { |
| 6 | + taskId: string; |
| 7 | + folderPath: string; |
| 8 | + worktreePath: string | null; |
| 9 | + worktreeName: string | null; |
| 10 | + mode: WorkspaceMode; |
| 11 | +} |
| 12 | + |
| 13 | +const PORT_BASE = 50000; |
| 14 | +const PORTS_PER_WORKSPACE = 20; |
| 15 | +const MAX_WORKSPACES = 1000; |
| 16 | + |
| 17 | +function hashTaskId(taskId: string): number { |
| 18 | + let hash = 0; |
| 19 | + for (let i = 0; i < taskId.length; i++) { |
| 20 | + const char = taskId.charCodeAt(i); |
| 21 | + hash = (hash << 5) - hash + char; |
| 22 | + hash = hash & hash; |
| 23 | + } |
| 24 | + return Math.abs(hash); |
| 25 | +} |
| 26 | + |
| 27 | +function allocateWorkspacePorts(taskId: string): { |
| 28 | + start: number; |
| 29 | + end: number; |
| 30 | + ports: number[]; |
| 31 | +} { |
| 32 | + const workspaceIndex = hashTaskId(taskId) % MAX_WORKSPACES; |
| 33 | + const start = PORT_BASE + workspaceIndex * PORTS_PER_WORKSPACE; |
| 34 | + const end = start + PORTS_PER_WORKSPACE - 1; |
| 35 | + |
| 36 | + const ports: number[] = []; |
| 37 | + for (let port = start; port <= end; port++) { |
| 38 | + ports.push(port); |
| 39 | + } |
| 40 | + |
| 41 | + return { start, end, ports }; |
| 42 | +} |
| 43 | + |
| 44 | +export async function buildWorkspaceEnv( |
| 45 | + context: WorkspaceEnvContext, |
| 46 | +): Promise<Record<string, string>> { |
| 47 | + if (context.mode === "cloud") { |
| 48 | + return {}; |
| 49 | + } |
| 50 | + |
| 51 | + const workspaceName = |
| 52 | + context.worktreeName ?? path.basename(context.folderPath); |
| 53 | + const workspacePath = context.worktreePath ?? context.folderPath; |
| 54 | + const rootPath = context.folderPath; |
| 55 | + |
| 56 | + const defaultBranch = await getDefaultBranch(rootPath); |
| 57 | + |
| 58 | + const workspaceBranch = (await getCurrentBranch(workspacePath)) ?? ""; |
| 59 | + |
| 60 | + const portAllocation = allocateWorkspacePorts(context.taskId); |
| 61 | + |
| 62 | + return { |
| 63 | + ARRAY_WORKSPACE_NAME: workspaceName, |
| 64 | + ARRAY_WORKSPACE_PATH: workspacePath, |
| 65 | + ARRAY_ROOT_PATH: rootPath, |
| 66 | + ARRAY_DEFAULT_BRANCH: defaultBranch, |
| 67 | + ARRAY_WORKSPACE_BRANCH: workspaceBranch, |
| 68 | + ARRAY_WORKSPACE_PORTS: portAllocation.ports.join(","), |
| 69 | + ARRAY_WORKSPACE_PORTS_RANGE: String(PORTS_PER_WORKSPACE), |
| 70 | + ARRAY_WORKSPACE_PORTS_START: String(portAllocation.start), |
| 71 | + ARRAY_WORKSPACE_PORTS_END: String(portAllocation.end), |
| 72 | + }; |
| 73 | +} |
0 commit comments