import { readConfig } from "./src/config"; import { debugDispatch, debugHealth, debugTask, isDebugDispatchCommand, type DebugDispatchCommand } from "./src/debug"; import { isRebuildableService, rebuildService, stackLogs, stackStatus, startStack, stopStack, unsupportedRebuildService } from "./src/docker"; import { parseE2ERunOptions, runE2E } from "./src/e2e"; import { emitError, emitJson } from "./src/output"; import { jobWithTail, listJobs, listJobsSummary, readJob, runJob } from "./src/jobs"; import { checkHelp, parseCheckOptions, runChecks, runRecoveryGuardrailsCheck } from "./src/check"; import { runSsh } from "./src/ssh"; import { autoRemoteCiPublishUserServiceDryRunPlan, extractRemoteCliOptions, runRemoteCli } from "./src/remote"; import { runMicroserviceCommand } from "./src/microservices"; import { runCodeQueueCommand } from "./src/code-queue"; import { runDecisionCenterCommand } from "./src/decision-center"; import { deployHelp, runCodeQueueDeployCompatCommand, runDeployCommand } from "./src/deploy"; import { runProviderCommand } from "./src/provider-attach"; import { runScheduleCommand } from "./src/schedules"; import { parseNetworkPerfOptions, runNetworkPerf } from "./src/network-perf"; import { ciHelp, runCiCommand } from "./src/ci"; import { runSwapCommand } from "./src/swap"; import { runDevEnvCommand } from "./src/dev-env"; import { runArtifactRegistryCommand } from "./src/artifact-registry"; import { runAuthBrokerCommand } from "./src/auth-broker"; import { runGhCommand } from "./src/gh"; import { runCommanderCommand } from "./src/commander"; import { isHelpToken, rootHelp, serverHelp, sshHelp, staticNamespaceHelp } from "./src/help"; import { runServerCleanupCommand } from "./src/server-cleanup"; import { runHwlabCdCommand } from "./src/hwlab-cd"; const remoteOptions = extractRemoteCliOptions(process.argv.slice(2)); const args = remoteOptions.args; const commandName = displayCommandName(args); function displayCommandName(parts: string[]): string { if (parts.length === 0) return "help"; if (parts[0] === "codex" && (parts[1] === "submit" || parts[1] === "enqueue")) { const shown = ["codex", parts[1]]; const shownValueOptions = new Set([ "--prompt-file", "--file", "--queue", "--queue-id", "--provider", "--provider-id", "--cwd", "--workdir", "--model", "--reasoning-effort", "--execution-mode", "--mode", "--max-attempts", "--reference-task-id", "--reference", "--ref", ]); const hasPromptFile = parts.includes("--prompt-file") || parts.includes("--file"); const hasPromptStdin = parts.includes("--prompt-stdin") || parts.includes("--stdin"); const hasHelp = parts.slice(2).some(isHelpToken); if (!hasPromptFile && !hasPromptStdin && !hasHelp) shown.push(""); for (let index = 2; index < parts.length; index += 1) { const part = parts[index] ?? ""; if (!part.startsWith("--")) continue; shown.push(part); if (shownValueOptions.has(part)) { shown.push(parts[index + 1] ?? ""); index += 1; } } return shown.join(" "); } if (parts[0] === "codex" && parts[1] === "steer" && parts[2] !== undefined) { const shown = ["codex", "steer", parts[2]]; const shownValueOptions = new Set(["--prompt-file", "--file", "--retry-attempts", "--retry-delay-ms", "--steer-id", "--steerId"]); const hasPromptFile = parts.includes("--prompt-file") || parts.includes("--file"); const hasPromptStdin = parts.includes("--prompt-stdin") || parts.includes("--stdin"); const hasHelp = parts.slice(3).some(isHelpToken); if (!hasPromptFile && !hasPromptStdin && !hasHelp) shown.push(""); for (let index = 3; index < parts.length; index += 1) { const part = parts[index] ?? ""; if (!part.startsWith("--")) continue; shown.push(part); if (shownValueOptions.has(part)) { shown.push(parts[index + 1] ?? ""); index += 1; } } return shown.join(" "); } if (parts[0] === "codex" && parts[1] === "resume" && parts[2] !== undefined) { const shown = ["codex", "resume", parts[2]]; const shownValueOptions = new Set(["--prompt-file", "--file", "--resume-id", "--resumeId"]); const hasPromptFile = parts.includes("--prompt-file") || parts.includes("--file"); const hasPromptStdin = parts.includes("--prompt-stdin") || parts.includes("--stdin"); const hasHelp = parts.slice(3).some(isHelpToken); if (!hasPromptFile && !hasPromptStdin && !hasHelp) shown.push(""); for (let index = 3; index < parts.length; index += 1) { const part = parts[index] ?? ""; if (!part.startsWith("--")) continue; shown.push(part); if (shownValueOptions.has(part)) { shown.push(parts[index + 1] ?? ""); index += 1; } } return shown.join(" "); } if (parts[0] === "commander" && parts[1] === "approval" && parts[2] === "request") { const shown: string[] = []; for (let index = 0; index < parts.length; index += 1) { const part = parts[index] ?? ""; shown.push(part); if (part === "--reason") { shown.push(""); index += 1; } } return shown.join(" "); } if (parts[0] === "gh") { const shown: string[] = []; for (let index = 0; index < parts.length; index += 1) { const part = parts[index] ?? ""; shown.push(part); if (part === "--body") { shown.push(""); index += 1; } } return shown.join(" "); } return parts.join(" "); } function numberOption(name: string, defaultValue: number): number { const index = args.indexOf(name); if (index === -1) return defaultValue; const raw = args[index + 1]; const value = Number(raw); if (!Number.isInteger(value) || value <= 0) throw new Error(`${name} must be a positive integer`); return value; } function boundedNumberOption(name: string, defaultValue: number, maxValue: number): number { return Math.min(numberOption(name, defaultValue), maxValue); } function stringOption(name: string): string | undefined { const index = args.indexOf(name); if (index === -1) return undefined; const raw = args[index + 1]; if (raw === undefined || raw.length === 0) throw new Error(`${name} requires a non-empty value`); return raw; } function jsonOption(name: string): Record | undefined { const raw = stringOption(name); if (raw === undefined) return undefined; const parsed = JSON.parse(raw) as unknown; if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new Error(`${name} must be a JSON object`); return parsed as Record; } function dispatchPayload(command: DebugDispatchCommand): Record { const explicit = jsonOption("--payload-json") ?? {}; if (command === "provider.upgrade") { return { source: "cli-debug", mode: stringOption("--mode") ?? stringOption("--upgrade-mode") ?? "plan", ...explicit }; } if (command === "host.ssh") { const sshCommand = stringOption("--ssh-command"); return { source: "cli-debug", mode: sshCommand === undefined ? "probe" : "exec", ...(sshCommand === undefined ? {} : { command: sshCommand }), ...(stringOption("--cwd") === undefined ? {} : { cwd: stringOption("--cwd") }), ...(args.includes("--timeout-ms") ? { timeoutMs: numberOption("--timeout-ms", 8000) } : {}), ...explicit, }; } return { source: "cli-debug", ...explicit }; } function resultOk(result: unknown): boolean { return typeof result !== "object" || result === null || !("ok" in result) || (result as { ok?: unknown }).ok !== false; } function latestJobId(): string { const jobs = listJobs(); if (jobs.length === 0) throw new Error("No jobs found"); return jobs[0].id; } async function main(): Promise { if (remoteOptions.host !== null) { process.exitCode = await runRemoteCli(remoteOptions, readConfig()); return; } const [top, sub, third, fourth] = args; if (top === undefined || top === "help" || top === "--help" || top === "-h") { emitJson(commandName, rootHelp()); return; } if (top === "ssh" && (sub === undefined || isHelpToken(sub) || (isHelpToken(third) && args.length === 3))) { emitJson(commandName, sshHelp()); return; } if (top === "check" && isHelpToken(sub)) { emitJson(commandName, checkHelp()); return; } if (top === "server" && (isHelpToken(sub) || args.slice(2).some(isHelpToken))) { emitJson(commandName, serverHelp(isHelpToken(sub) ? undefined : sub)); return; } if (top === "deploy" && args.slice(1).some(isHelpToken)) { emitJson(commandName, deployHelp(isHelpToken(sub) ? undefined : sub)); return; } if (top === "ci" && (isHelpToken(sub) || args.slice(1).some(isHelpToken))) { emitJson(commandName, ciHelp()); return; } const namespaceHelp = staticNamespaceHelp(args); if (namespaceHelp !== null) { emitJson(commandName, namespaceHelp); return; } if (top === "internal" && sub === "run-job") { if (!third) throw new Error("internal run-job requires job id"); emitJson(commandName, await runJob(third)); return; } if (top === "dev-env") { const result = runDevEnvCommand(args.slice(1)); const ok = (result as { ok?: unknown }).ok !== false; emitJson(commandName, result, ok); if (!ok) process.exitCode = 1; return; } if (top === "artifact-registry") { const result = await runArtifactRegistryCommand(args.slice(1)); const ok = (result as { ok?: unknown }).ok !== false; emitJson(commandName, result, ok); if (!ok) process.exitCode = 1; return; } if (top === "auth-broker") { const result = runAuthBrokerCommand(args.slice(1)); const ok = (result as { ok?: unknown }).ok !== false; emitJson(commandName, result, ok); if (!ok) process.exitCode = 1; return; } if (top === "gh") { const result = await runGhCommand(args.slice(1)); const ok = (result as { ok?: unknown }).ok !== false; emitJson(commandName, result, ok); if (!ok) process.exitCode = 1; return; } if (top === "commander") { const result = runCommanderCommand(args.slice(1)); if (sub === "prompt-lint") { emitJson(commandName, result, true); return; } const ok = (result as { ok?: unknown }).ok !== false; emitJson(commandName, result, ok); if (!ok) process.exitCode = 1; return; } if (top === "hwlab") { const result = await runHwlabCdCommand(args.slice(1)); const ok = (result as { ok?: unknown }).ok !== false; emitJson(commandName, result, ok); if (!ok) process.exitCode = 1; return; } const config = readConfig(); const autoRemoteCiPublishPlan = autoRemoteCiPublishUserServiceDryRunPlan(config, args); if (autoRemoteCiPublishPlan.enabled && autoRemoteCiPublishPlan.host !== null) { process.exitCode = await runRemoteCli({ ...remoteOptions, host: autoRemoteCiPublishPlan.host, transport: "frontend", args, }, config); return; } if (top === "ssh") { const exitCode = await runSsh(config, sub ?? "", args.slice(2)); process.exitCode = exitCode; return; } if (top === "config" && sub === "show") { emitJson(commandName, { config }); return; } if (top === "check") { if (isHelpToken(sub)) { emitJson(commandName, checkHelp()); return; } if (sub === "recovery-guardrails") { const result = runRecoveryGuardrailsCheck(config); emitJson(commandName, result, result.ok); if (!result.ok) process.exitCode = 1; return; } const result = runChecks(config, parseCheckOptions(args.slice(1))); emitJson(commandName, result, result.ok); if (!result.ok) process.exitCode = 1; return; } if (top === "server") { if (isHelpToken(sub) || args.slice(2).some(isHelpToken)) { emitJson(commandName, serverHelp(isHelpToken(sub) ? undefined : sub)); return; } if (sub === "start") { emitJson(commandName, startStack(config)); return; } if (sub === "stop") { emitJson(commandName, stopStack(config)); return; } if (sub === "status") { emitJson(commandName, await stackStatus(config)); return; } if (sub === "swap") { const result = runSwapCommand(args.slice(2)); const ok = (result as { ok?: unknown }).ok !== false; emitJson(commandName, result, ok); if (!ok) process.exitCode = 1; return; } if (sub === "logs") { emitJson(commandName, stackLogs(config, boundedNumberOption("--tail-bytes", 3000, 500_000))); return; } if (sub === "cleanup") { const result = await runServerCleanupCommand(config, args.slice(2)); const ok = (result as { ok?: unknown }).ok !== false; emitJson(commandName, result, ok); if (!ok) process.exitCode = 1; return; } if (sub === "rebuild") { if (!isRebuildableService(third)) { const result = unsupportedRebuildService(third); emitJson(commandName, result, false); process.exitCode = 1; return; } emitJson(commandName, rebuildService(config, third)); return; } } if (top === "microservice") { const result = await runMicroserviceCommand(config, args.slice(1)); const ok = resultOk(result); emitJson(commandName, result, ok); if (!ok) process.exitCode = 1; return; } if (top === "decision" || top === "decision-center") { const result = await runDecisionCenterCommand(config, args.slice(1)); const ok = resultOk(result); emitJson(commandName, result, ok); if (!ok) process.exitCode = 1; return; } if (top === "deploy") { const result = await runDeployCommand(config, args.slice(1)); const ok = (result as { ok?: unknown }).ok !== false; emitJson(commandName, result, ok); if (!ok) process.exitCode = 1; return; } if (top === "provider") { emitJson(commandName, await runProviderCommand(config, args.slice(1))); return; } if (top === "schedule") { const result = await runScheduleCommand(config, args.slice(1)); const ok = resultOk(result); emitJson(commandName, result, ok); if (!ok) process.exitCode = 1; return; } if (top === "codex") { if (sub === "deploy") { const result = await runCodeQueueDeployCompatCommand(config, args.slice(2)); const ok = (result as { ok?: unknown }).ok !== false; emitJson(commandName, result, ok); if (!ok) process.exitCode = 1; return; } const result = await runCodeQueueCommand(config, args.slice(1)); const ok = (result as { ok?: unknown }).ok !== false; emitJson(commandName, result, ok); if (!ok) process.exitCode = 1; return; } if (top === "job") { if (sub === "list") { emitJson(commandName, listJobsSummary({ limit: boundedNumberOption("--limit", 50, 500), includeCommand: args.includes("--include-command") })); return; } if (sub === "status") { const id = third === "latest" || third === undefined ? latestJobId() : third; emitJson(commandName, { job: jobWithTail(readJob(id), boundedNumberOption("--tail-bytes", 12000, 500_000)) }); return; } } if (top === "debug") { if (sub === "health") { emitJson(commandName, await debugHealth(config)); return; } if (sub === "dispatch") { const providerId = isDebugDispatchCommand(third) ? config.providerGateway.id : third ?? config.providerGateway.id; const commandArg = isDebugDispatchCommand(third) ? third : fourth; const dispatchCommand = isDebugDispatchCommand(commandArg) ? commandArg : "docker.ps"; emitJson(commandName, await debugDispatch(config, providerId, dispatchCommand, dispatchPayload(dispatchCommand), numberOption("--wait-ms", 0))); return; } if (sub === "task") { emitJson(commandName, await debugTask(config, third ?? "latest")); return; } } if (top === "network" && sub === "perf") { emitJson(commandName, await runNetworkPerf(parseNetworkPerfOptions(config, args.slice(2)))); return; } if (top === "ci") { const result = await runCiCommand(config, args.slice(1)); const ok = (result as { ok?: unknown }).ok !== false; emitJson(commandName, result, ok); if (!ok) process.exitCode = 1; return; } if (top === "e2e" && sub === "run") { const result = await runE2E(config, parseE2ERunOptions(args.slice(2))); const ok = (result as { ok?: unknown }).ok === true; emitJson(commandName, result, ok); if (!ok) process.exitCode = 1; return; } throw new Error(`Unknown command: ${commandName}`); } main().catch((error) => { emitError(commandName, error); process.exitCode = 1; });