// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. accounts module for scripts/src/platform-infra-sub2api-codex.ts. // Moved mechanically from scripts/src/platform-infra-sub2api-codex.ts:4209-4264 for #903. import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs"; import { homedir } from "node:os"; import { join } from "node:path"; import type { UniDeskConfig } from "../config"; import { rootPath } from "../config"; import type { RenderedCliResult } from "../output"; import { applyPk01CaddyBlock, prepareFrpcSecret, renderFrpcManifest, type PublicServiceExposure, type PublicServiceTarget } from "../platform-infra-public-service"; import { shortSha256Fingerprint } from "../platform-infra-ops-library"; import { codexPoolSentinelSummary, codexPoolSentinelRuntimeImage, readCodexPoolSentinelConfig, renderCodexPoolSentinelManifest, type CodexPoolSentinelConfig, type CodexPoolSentinelProfileSecret, } from "../platform-infra-sub2api-codex-sentinel"; import { parseEnvFile, readTextFile, redactRepoPath, requiredEnvValue } from "../secrets"; import { runSshCommandCapture, type SshCaptureResult } from "../ssh"; import type { CodexPoolConfig, OpenAIResponsesWebSocketsV2Mode } from "./types"; import { renderSub2ApiTempUnschedulableCredentials, uniqueAccountName } from "./redaction"; export function desiredAccountNames(pool: CodexPoolConfig): string[] { return Object.keys(desiredAccountCapacityMap(pool)).sort(); } export function desiredAccountCapacityTotal(pool: CodexPoolConfig): number { return Object.values(desiredAccountCapacityMap(pool)).reduce((total, value) => total + value, 0); } export function desiredAccountCapacityMap(pool: CodexPoolConfig): Record { const codexDir = join(homedir(), ".codex"); const seenAccountNames = new Set(); const capacities: Record = {}; for (const entry of pool.profiles) { const accountName = entry.accountName ?? uniqueAccountName(entry.profile, seenAccountNames); seenAccountNames.add(accountName); capacities[accountName] = entry.capacity ?? pool.defaultAccountCapacity; } return capacities; } export function desiredAccountLoadFactorMap(pool: CodexPoolConfig): Record { const codexDir = join(homedir(), ".codex"); const seenAccountNames = new Set(); const loadFactors: Record = {}; for (const entry of pool.profiles) { const accountName = entry.accountName ?? uniqueAccountName(entry.profile, seenAccountNames); seenAccountNames.add(accountName); loadFactors[accountName] = entry.loadFactor ?? pool.defaultAccountLoadFactor; } return loadFactors; } export function desiredAccountWebSocketsV2ModeMap(pool: CodexPoolConfig): Record { const codexDir = join(homedir(), ".codex"); const seenAccountNames = new Set(); const modes: Record = {}; for (const entry of pool.profiles) { const accountName = entry.accountName ?? uniqueAccountName(entry.profile, seenAccountNames); seenAccountNames.add(accountName); modes[accountName] = entry.openaiResponsesWebSocketsV2Mode; } return modes; } export function desiredAccountTempUnschedulableMap(pool: CodexPoolConfig): Record { const codexDir = join(homedir(), ".codex"); const seenAccountNames = new Set(); const policies: Record = {}; for (const entry of pool.profiles) { const accountName = entry.accountName ?? uniqueAccountName(entry.profile, seenAccountNames); seenAccountNames.add(accountName); policies[accountName] = renderSub2ApiTempUnschedulableCredentials(entry.tempUnschedulable); } return policies; }