import fs from "node:fs"; import path from "node:path"; import { execFileSync, spawnSync } from "node:child_process"; import { repoRoot } from "./core.mjs"; import { defaultDbPath, defaultWorkspaceRoot, readPlanFile, resolveOrchBinary, writeTaskBodyFile } from "./orch-support.mjs"; function printHelp() { process.stdout.write(`Cadence UI orchestration wrapper Usage: pnpm harness:orch -- [flags] pnpm harness:orch -- doctor [--plan-file docs/exec-plans/foo.md] pnpm harness:orch -- plan inspect --plan-file docs/exec-plans/foo.md pnpm harness:orch -- plan body --run cadence_ui_demo --task T1 --plan-file docs/exec-plans/foo.md Examples: pnpm harness:orch -- run init --run cadence_ui_demo --goal "Refine release UX" --summary "Break work into isolated tasks" pnpm harness:orch -- task add --run cadence_ui_demo --task T1 --title "Stabilize smoke tests" --summary "Fix Storybook smoke drift" pnpm harness:orch -- dispatch --run cadence_ui_demo --task T1 --to default-worker --plan-file docs/exec-plans/task-plan.md pnpm harness:orch -- doctor --plan-file docs/exec-plans/task-plan.md Defaults applied by this wrapper: --db ${path.relative(repoRoot, defaultDbPath)} dispatch --repo-path ${repoRoot} dispatch --workspace-root ${path.relative(repoRoot, defaultWorkspaceRoot)} dispatch --strict-worktree dispatch --base-ref Plan-linked helpers: doctor Resolve the orch binary, show defaults, and inspect an execution plan. plan inspect Print orchestration tasks parsed from a plan's task sketch. plan body Generate a task body file from a plan and task id. dispatch --plan-file Generate --body-file automatically from the referenced execution plan. `); } function fail(message) { process.stderr.write(`[harness:orch] ${message}\n`); process.exit(1); } function hasFlag(args, flag) { return args.includes(flag); } function getFlagValue(args, flag) { const index = args.indexOf(flag); if (index === -1) { return null; } return args[index + 1] ?? null; } function consumeFlagValue(args, flag) { const index = args.indexOf(flag); if (index === -1) { return null; } const [value] = args.splice(index, 2).slice(1); return value ?? null; } function getCurrentBranch() { try { return execFileSync("git", ["branch", "--show-current"], { cwd: repoRoot, encoding: "utf8" }).trim(); } catch { return "main"; } } function printPlanTasks(plan) { process.stdout.write(`[harness:orch] Plan: ${plan.relativePath}\n`); process.stdout.write(`[harness:orch] Title: ${plan.planTitle}\n`); if (plan.tasks.length === 0) { process.stdout.write("[harness:orch] No orchestration task sketch entries found.\n"); return; } process.stdout.write("[harness:orch] Parsed tasks:\n"); for (const task of plan.tasks) { const dependencySuffix = task.dependsOn.length > 0 ? ` (depends on ${task.dependsOn.join(", ")})` : ""; process.stdout.write(`- ${task.id}: ${task.title}${dependencySuffix}\n`); } } function findPlanTask(plan, taskId) { return plan.tasks.find((task) => task.id === taskId) ?? null; } function maybeHandleDoctor(rawArgs) { if (rawArgs[0] !== "doctor") { return false; } const planFile = getFlagValue(rawArgs, "--plan-file"); const resolution = resolveOrchBinary(); process.stdout.write("[harness:orch] Doctor\n"); process.stdout.write(`- repo root: ${repoRoot}\n`); process.stdout.write(`- default db: ${path.relative(repoRoot, defaultDbPath)}\n`); process.stdout.write(`- default workspace root: ${path.relative(repoRoot, defaultWorkspaceRoot)}\n`); process.stdout.write(`- current branch: ${getCurrentBranch()}\n`); process.stdout.write( `- orch binary: ${resolution.binaryPath ? `${resolution.binaryPath} (${resolution.source})` : "not found"}\n` ); if (!resolution.binaryPath) { process.stdout.write("- checked locations:\n"); for (const checkedPath of resolution.checkedPaths) { process.stdout.write(` - ${checkedPath}\n`); } process.stdout.write( "[harness:orch] Set CADENCE_UI_ORCH_BIN to an installed orch binary or add `orch` to PATH.\n" ); } if (planFile) { const plan = readPlanFile(planFile); printPlanTasks(plan); } process.exit(resolution.binaryPath ? 0 : 1); } function maybeHandlePlanCommand(rawArgs) { if (rawArgs[0] !== "plan") { return false; } const subcommand = rawArgs[1]; const planFile = getFlagValue(rawArgs, "--plan-file"); if (!planFile) { fail("Expected --plan-file for plan commands."); } const plan = readPlanFile(planFile); if (subcommand === "inspect") { printPlanTasks(plan); process.exit(0); } if (subcommand === "body") { const taskId = getFlagValue(rawArgs, "--task"); const runId = getFlagValue(rawArgs, "--run") ?? "adhoc"; if (!taskId) { fail("Expected --task when generating a plan-backed task body."); } const task = findPlanTask(plan, taskId); if (!task) { fail(`Task ${taskId} was not found in ${plan.relativePath}.`); } const outputPath = writeTaskBodyFile({ plan, runId, task }); process.stdout.write( `[harness:orch] Wrote ${path.relative(repoRoot, outputPath)} from ${plan.relativePath}\n` ); process.exit(0); } fail(`Unknown plan subcommand: ${subcommand ?? ""}`); } const rawArgs = process.argv.slice(2).filter((value) => value !== "--"); if ( rawArgs.length === 0 || rawArgs[0] === "help" || rawArgs[0] === "--help" || rawArgs[0] === "-h" ) { printHelp(); process.exit(0); } maybeHandleDoctor(rawArgs); maybeHandlePlanCommand(rawArgs); fs.mkdirSync(path.dirname(defaultDbPath), { recursive: true }); fs.mkdirSync(defaultWorkspaceRoot, { recursive: true }); const command = rawArgs[0]; const orchArgs = [...rawArgs]; if (!hasFlag(orchArgs, "--db")) { orchArgs.unshift(defaultDbPath); orchArgs.unshift("--db"); } if (command === "dispatch") { const planFile = consumeFlagValue(orchArgs, "--plan-file"); if (planFile && !hasFlag(orchArgs, "--body-file")) { const taskId = getFlagValue(orchArgs, "--task"); const runId = getFlagValue(orchArgs, "--run") ?? "adhoc"; if (!taskId) { fail("Expected --task when using dispatch --plan-file."); } const plan = readPlanFile(planFile); const task = findPlanTask(plan, taskId); if (!task) { fail(`Task ${taskId} was not found in ${plan.relativePath}.`); } const outputPath = writeTaskBodyFile({ plan, runId, task }); process.stdout.write( `[harness:orch] Generated ${path.relative(repoRoot, outputPath)} from ${plan.relativePath}\n` ); orchArgs.push("--body-file", outputPath); } if (!hasFlag(orchArgs, "--repo-path")) { orchArgs.push("--repo-path", repoRoot); } if (!hasFlag(orchArgs, "--workspace-root")) { orchArgs.push("--workspace-root", defaultWorkspaceRoot); } if (!hasFlag(orchArgs, "--strict-worktree")) { orchArgs.push("--strict-worktree"); } if (!hasFlag(orchArgs, "--base-ref")) { orchArgs.push("--base-ref", getCurrentBranch()); } } const resolution = resolveOrchBinary(); if (!resolution.binaryPath) { fail( `Unable to locate orch. Checked ${resolution.checkedPaths.join(", ")}. Set CADENCE_UI_ORCH_BIN or add orch to PATH.` ); } const result = spawnSync(resolution.binaryPath, orchArgs, { cwd: repoRoot, stdio: "inherit" }); process.exit(result.status ?? 1);