export const meta = {
  name: 'release',
  description: 'Relicario release lifecycle: develop features (single/multi-agent), iterate on debug, cut releases',
  phases: [
    { title: 'Discover' },
    { title: 'Plan' },
    { title: 'Execute' },
    { title: 'Verify' },
    { title: 'Generate' },
    { title: 'Finalize' },
    { title: 'Cleanup' },
  ],
}

// ── Schemas ───────────────────────────────────────────────────────────────────

const MANIFEST_SCHEMA = {
  type: 'object',
  properties: {
    plans: { type: 'array', items: { type: 'string' } },
    taskCount: { type: 'number' },
    domains: { type: 'array', items: { type: 'string' } },
  },
  required: ['plans', 'taskCount', 'domains'],
}

const TASK_LIST_SCHEMA = {
  type: 'object',
  properties: {
    tasks: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          id: { type: 'string' },
          description: { type: 'string' },
          planPath: { type: 'string' },
          techDomain: { type: 'string' },
        },
        required: ['id', 'description', 'planPath', 'techDomain'],
      },
    },
  },
  required: ['tasks'],
}

const ASSIGNMENT_SCHEMA = {
  type: 'object',
  properties: {
    devCount: { type: 'number' },
    devs: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          letter: { type: 'string' },
          scope: { type: 'string' },
          tasks: { type: 'array', items: { type: 'string' } },
          outOfScope: { type: 'array', items: { type: 'string' } },
          techDomain: { type: 'string' },
          planFiles: { type: 'array', items: { type: 'string' } },
        },
        required: ['letter', 'scope', 'tasks', 'outOfScope', 'techDomain', 'planFiles'],
      },
    },
    pmScope: { type: 'string' },
  },
  required: ['devCount', 'devs', 'pmScope'],
}

const DEBUG_RESULT_SCHEMA = {
  type: 'object',
  properties: {
    fixed: { type: 'boolean' },
    summary: { type: 'string' },
    remainingFailures: { type: 'string' },
  },
  required: ['fixed', 'summary'],
}

const VERIFY_RESULT_SCHEMA = {
  type: 'object',
  properties: {
    allPass: { type: 'boolean' },
    failures: { type: 'array', items: { type: 'string' } },
    summary: { type: 'string' },
  },
  required: ['allPass', 'failures', 'summary'],
}

const WORKTREE_STATUS_SCHEMA = {
  type: 'object',
  properties: {
    stale: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          path: { type: 'string' },
          branch: { type: 'string' },
        },
        required: ['path', 'branch'],
      },
    },
    active: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          path: { type: 'string' },
          branch: { type: 'string' },
        },
        required: ['path', 'branch'],
      },
    },
  },
  required: ['stale', 'active'],
}

const PLAN_STATE_SCHEMA = {
  type: 'object',
  properties: {
    tickedTasks: { type: 'number' },
    totalTasks: { type: 'number' },
    gitEvidence: { type: 'array', items: { type: 'string' } },
  },
  required: ['tickedTasks', 'totalTasks', 'gitEvidence'],
}

const BRANCH_CHECK_SCHEMA = {
  type: 'object',
  properties: {
    collisions: { type: 'array', items: { type: 'string' } },
  },
  required: ['collisions'],
}

const VERSION_CHECK_SCHEMA = {
  type: 'object',
  properties: {
    consistent: { type: 'boolean' },
    versions: { type: 'array', items: { type: 'string' } },
    conflicts: { type: 'array', items: { type: 'string' } },
    tagExists: { type: 'boolean' },
  },
  required: ['consistent', 'versions', 'conflicts', 'tagExists'],
}

const CLEANUP_RESULT_SCHEMA = {
  type: 'object',
  properties: {
    removed: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          path: { type: 'string' },
          branch: { type: 'string' },
        },
        required: ['path', 'branch'],
      },
    },
    kept: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          path: { type: 'string' },
          branch: { type: 'string' },
          reason: { type: 'string' },
        },
        required: ['path', 'branch', 'reason'],
      },
    },
  },
  required: ['removed', 'kept'],
}

// ── Helpers ───────────────────────────────────────────────────────────────────

const REPO = '/home/alee/Sources/relicario'
const COORD_DIR = 'docs/superpowers/coordination'

function devRole(letter) {
  return 'dev-' + letter.toLowerCase()
}

// ── Routing ───────────────────────────────────────────────────────────────────

// Support both object args {action, mode, release} and space-separated string
// "action mode release-label" (e.g. "develop multi enterprise-org-vault").
let _args = args
if (typeof args === 'string') {
  const parts = args.trim().split(/\s+/)
  // "develop multi enterprise-org-vault" → 3 parts
  // "develop enterprise-org-vault"       → 2 parts (mode defaults to single)
  if (parts.length >= 3) {
    _args = { action: parts[0], mode: parts[1], release: parts.slice(2).join(' ') }
  } else if (parts.length === 2) {
    _args = { action: parts[0], mode: 'single', release: parts[1] }
  } else {
    _args = { action: parts[0] || 'develop' }
  }
}

const action = (_args && _args.action) || 'develop'
const mode   = (_args && _args.mode)   || 'single'
const release = _args && _args.release
const context = _args && _args.context

// ── ACTION: preflight ─────────────────────────────────────────────────────────

if (action === 'preflight') {
  if (!release) throw new Error('args.release is required for action=preflight')

  const [worktrees, baseline, planState, branches] = await parallel([

    () => agent(
      `Run: git -C ${REPO} worktree list\n` +
      `Parse the output. For each worktree listed, extract its path and branch.\n` +
      `Skip the main checkout at ${REPO} itself.\n` +
      `Then run: git -C ${REPO} branch --merged main\n` +
      `A worktree is stale if its branch appears in the merged list. Otherwise it is active.\n` +
      `Return stale (merged worktrees) and active (unmerged worktrees), each as an array of {path, branch}.`,
      { schema: WORKTREE_STATUS_SCHEMA, label: 'worktree-scan', phase: 'Discover' }
    ),

    () => agent(
      `cd ${REPO} and run each of these commands, capturing the last 5 lines of output:\n` +
      `  cargo test --quiet 2>&1 | tail -5\n` +
      `  pnpm --filter extension test --run 2>&1 | tail -5\n` +
      `Report allPass=true only if both commands exit with code 0. ` +
      `List any failures with their error messages. Provide a one-line summary.`,
      { schema: VERIFY_RESULT_SCHEMA, label: 'baseline-green', phase: 'Discover' }
    ),

    () => agent(
      `Run: git -C ${REPO} log --oneline --all --grep="${release}" | head -20\n` +
      `Capture the output as gitEvidence.\n` +
      `Then scan ${REPO}/docs/superpowers/plans/ for any files whose filename contains "${release}".\n` +
      `For each matching file, count lines matching "- \\[x\\]" (ticked) and "- \\[ \\]" (unticked).\n` +
      `Sum across all matching files. Return tickedTasks, totalTasks, and gitEvidence (the git log lines).`,
      { schema: PLAN_STATE_SCHEMA, label: 'plan-state', phase: 'Discover' }
    ),

    () => agent(
      `Run: git -C ${REPO} branch --all\n` +
      `Return any branch names (local or remote) that contain the string "${release}" as collisions.`,
      { schema: BRANCH_CHECK_SCHEMA, label: 'branch-collision', phase: 'Discover' }
    ),

  ])

  const issues = []

  if (worktrees.stale.length > 0) {
    issues.push('orphaned-worktrees')
    log(`WARN [worktree-scan]: ${worktrees.stale.length} stale worktree(s) found — run action=cleanup to remove them`)
    for (const w of worktrees.stale) {
      log(`  stale: ${w.path} (${w.branch})`)
    }
  } else {
    log(`[worktree-scan]: clean`)
  }

  if (!baseline.allPass) {
    issues.push('baseline-failing')
    log(`FAIL [baseline-green]: ${baseline.failures.length} failure(s): ${baseline.failures.join(' | ')}`)
  } else {
    log(`[baseline-green]: green`)
  }

  if (planState.tickedTasks > 0) {
    issues.push('plan-partially-done')
    log(`WARN [plan-state]: ${planState.tickedTasks}/${planState.totalTasks} tasks already ticked`)
    for (const e of planState.gitEvidence) {
      log(`  evidence: ${e}`)
    }
  } else {
    log(`[plan-state]: clean slate (0 ticked tasks)`)
  }

  if (branches.collisions.length > 0) {
    issues.push('branch-collision')
    log(`WARN [branch-collision]: branches already exist for release label "${release}": ${branches.collisions.join(', ')}`)
  } else {
    log(`[branch-collision]: no collisions`)
  }

  if (issues.length === 0) {
    log(`Preflight PASS`)
  } else {
    log(`Preflight has ${issues.length} warning(s): ${issues.join(', ')}`)
  }

  return { status: issues.length === 0 ? 'pass' : 'warn', issues, worktrees, baseline, planState, branches }
}

// ── ACTION: develop ───────────────────────────────────────────────────────────

if (action === 'develop') {
  if (!release) throw new Error('args.release is required for action=develop')

  phase('Discover')
  const manifest = await agent(
    `Scan docs/superpowers/plans/ in ${REPO} for plan files belonging to release "${release}". ` +
    `A plan file belongs if its filename contains the release label, or its opening lines reference it as its target release. ` +
    `Read each matching file, count checkbox tasks (lines starting with - [ ]), and identify tech domains (rust, extension, docs, etc.). ` +
    `Return: plans (relative paths from repo root), taskCount, domains.`,
    { schema: MANIFEST_SCHEMA, label: 'discover-plans', phase: 'Discover' }
  )

  log(`Found ${manifest.plans.length} plan(s), ${manifest.taskCount} tasks — domains: ${manifest.domains.join(', ')}`)

  // ── SINGLE MODE ─────────────────────────────────────────────────────────────

  if (mode === 'single') {

    phase('Plan')
    const taskList = await agent(
      `You are the PM for the ${release} release of Relicario at ${REPO}.\n` +
      `Read these plan files:\n${manifest.plans.map(p => '  ' + p).join('\n')}\n\n` +
      `Extract every checkbox task (- [ ] items) and order them to respect dependencies ` +
      `(e.g. core Rust changes before WASM/CLI consumers, schema changes before UI). ` +
      `For each task return: id (short slug like S1-step2), description (full step text), ` +
      `planPath (which file it came from), techDomain (rust/extension/docs/cli/wasm).`,
      { schema: TASK_LIST_SCHEMA, label: 'pm-plan', phase: 'Plan' }
    )

    log(`PM ordered ${taskList.tasks.length} tasks for sequential execution`)

    phase('Execute')
    await pipeline(
      taskList.tasks,
      (task) => agent(
        `You are a senior developer on the ${release} release of Relicario.\n` +
        `Repo: ${REPO}\n\n` +
        `IMPORTANT: cd into ${REPO} before any git or cargo commands.\n\n` +
        `Your task (${task.id}): ${task.description}\n` +
        `Plan file for full context: ${task.planPath}\n` +
        `Tech domain: ${task.techDomain}\n\n` +
        `Instructions:\n` +
        `1. Read the plan file for context on this specific step.\n` +
        `2. Implement ONLY this step — do not run ahead to the next one.\n` +
        `3. Run the relevant tests after your change (cargo test -p <crate> for Rust; pnpm build for extension).\n` +
        `4. Commit with a conventional commit message scoped to the change.\n` +
        `5. Report: what you did, test result (pass/fail), any blockers.`,
        { label: task.id, phase: 'Execute' }
      )
    )

    // ── Advisory: checkbox hygiene ───────────────────────────────────────────

    await agent(
      `Read each of these plan files from ${REPO}:\n${manifest.plans.map(p => '  ' + p).join('\n')}\n\n` +
      `Count any lines still matching "- [ ]" (unticked checkboxes). ` +
      `Log each unticked item with its file and line text. ` +
      `This is advisory only — report findings but do not block or fail.`,
      { label: 'checkbox-check', phase: 'Verify' }
    )

    phase('Verify')
    const verifyResult = await agent(
      `Run the full Relicario test suite from ${REPO}. IMPORTANT: cd ${REPO} first.\n` +
      `Commands:\n` +
      `  cargo test\n` +
      `  cargo build --all-targets\n` +
      `  cargo clippy -- -D warnings\n` +
      `Report pass/fail for each command. List every failure with its error message.`,
      { schema: VERIFY_RESULT_SCHEMA, label: 'full-verify', phase: 'Verify' }
    )

    if (!verifyResult.allPass) {
      log(`Verify FAILED — ${verifyResult.failures.length} failure(s): ${verifyResult.failures.join(' | ')}`)
      log(`Fix with: Workflow({name:"release", args:{action:"debug", context:"<paste failures>"}})`)
      return { status: 'verify-failed', failures: verifyResult.failures, summary: verifyResult.summary }
    }

    // ── Advisory: debug artifact scan ────────────────────────────────────────

    await agent(
      `Run the following command from ${REPO}:\n` +
      `  git -C ${REPO} diff $(git -C ${REPO} describe --tags --abbrev=0)..HEAD\n\n` +
      `Examine lines beginning with "+" (additions) in the diff output.\n` +
      `Report any occurrences of:\n` +
      `  - dbg!( in Rust files (warn)\n` +
      `  - console.log( in TypeScript files (warn)\n` +
      `  - TODO or FIXME anywhere (warn)\n` +
      `  - .unwrap() in Rust files (advisory note only, not a hard warn)\n` +
      `Log each finding with its file and line. This is advisory only — do not block.`,
      { label: 'debug-artifact-scan', phase: 'Finalize' }
    )

    phase('Finalize')
    await agent(
      `Update ${REPO}/STATUS.md to reflect the ${release} work that just completed.\n` +
      `Mark any in-flight items as landed. Set what is now in flight next.\n` +
      `Commit the STATUS.md update with message "docs: update STATUS for ${release} develop pass".`,
      { label: 'update-status', phase: 'Finalize' }
    )

    log(`Single-mode develop complete. Run action=release when ready to tag.`)
    return { status: 'complete', mode: 'single', release }
  }

  // ── MULTI MODE ──────────────────────────────────────────────────────────────

  phase('Plan')
  const assignment = await agent(
    `You are the PM for the ${release} release of Relicario at ${REPO}.\n` +
    `Read these plan files:\n${manifest.plans.map(p => '  ' + p).join('\n')}\n\n` +
    `Decide how many dev streams are needed (one per major domain or plan, max 3). ` +
    `Minimize cross-dev dependencies. For each dev assign: ` +
    `letter (A/B/C), scope summary (2 sentences), task IDs they own, ` +
    `out-of-scope task IDs (owned by other devs), primary techDomain, and which planFiles they need to read. ` +
    `Also write a 2-sentence pmScope describing your oversight and review duties.`,
    { schema: ASSIGNMENT_SCHEMA, label: 'pm-assign', phase: 'Plan' }
  )

  log(`PM assigned ${assignment.devCount} dev stream(s)`)

  phase('Generate')
  const allRoles = ['pm', ...assignment.devs.map(d => devRole(d.letter))].join(', ')

  await parallel([

    () => agent(
      `Write a self-contained PM kickoff prompt to ${REPO}/${COORD_DIR}/${release}-pm-prompt.md.\n\n` +
      `Release: ${release}\n` +
      `PM scope: ${assignment.pmScope}\n` +
      `Plans: ${manifest.plans.join(', ')}\n` +
      `Dev roster:\n${assignment.devs.map(d => `  Dev-${d.letter}: ${d.scope}`).join('\n')}\n\n` +
      `The file must include these sections in order:\n` +
      `1. Role header ("You are the PM for the ${release} release of Relicario.")\n` +
      `2. Working directory: ${REPO}\n` +
      `3. Required reading: CLAUDE.md, all plan files listed above\n` +
      `4. Authority: approve scope changes, review dev PRs, write CHANGELOG entry, drive doc updates, tag release (with user approval only)\n` +
      `5. Boundaries: write NO feature code; NO destructive ops without user confirmation\n` +
      `6. Relay server section: localhost:7331, your from="pm", tools: post_message/read_messages/list_pending, recipients: ${allRoles}. Include Python shim fallback.\n` +
      `7. Dev roster with each dev letter, branch name (feature/${release}-dev-X), worktree path (${REPO}.dev-x), and scope\n` +
      `8. Coordination protocol: DIRECTIVE block format, RELEASE STATUS rollup format\n` +
      `9. PR review procedure (gh pr view / gh pr diff)\n` +
      `10. Pre-tag checklist (all tests pass, CHANGELOG written, STATUS.md updated, all dev PRs merged)\n` +
      `11. First action: read all required files, emit a RELEASE STATUS block confirming context absorbed, then check all dev inboxes\n` +
      `Make every section concrete — the receiving Claude has zero prior context.`,
      { label: 'gen-pm', phase: 'Generate' }
    ),

    ...assignment.devs.map((dev) => () => agent(
      `Write a self-contained Dev-${dev.letter} kickoff prompt to ${REPO}/${COORD_DIR}/${release}-dev-${dev.letter.toLowerCase()}-prompt.md.\n\n` +
      `Release: ${release}\n` +
      `Dev-${dev.letter} scope: ${dev.scope}\n` +
      `Tasks owned: ${dev.tasks.join(', ')}\n` +
      `Out of scope: ${dev.outOfScope.join(', ')}\n` +
      `Tech domain: ${dev.techDomain}\n` +
      `Plan files: ${dev.planFiles.join(', ')}\n\n` +
      `The file must include these sections in order:\n` +
      `1. Role header ("You are Dev-${dev.letter} for the ${release} release of Relicario.")\n` +
      `2. Worktree setup commands (run these FIRST before anything else):\n` +
      `   git -C ${REPO} worktree add ${REPO}.dev-${dev.letter.toLowerCase()} -b feature/${release}-dev-${dev.letter.toLowerCase()}\n` +
      `   cd ${REPO}.dev-${dev.letter.toLowerCase()}\n` +
      `3. Working directory after setup: ${REPO}.dev-${dev.letter.toLowerCase()}\n` +
      `4. CRITICAL subagent rule: every subagent prompt MUST start with "cd ${REPO}.dev-${dev.letter.toLowerCase()} &&" — never rely on working-directory headers alone\n` +
      `5. Required reading: CLAUDE.md, ${dev.planFiles.join(', ')}\n` +
      `6. Execution mode: use superpowers:subagent-driven-development\n` +
      `7. Scope: in-scope tasks (${dev.tasks.join(', ')}), out-of-scope (${dev.outOfScope.join(', ')})\n` +
      `8. Hard rules from the plan (copy any HIGH-severity or acceptance-test constraints verbatim)\n` +
      `9. Relay: localhost:7331, your from="${devRole(dev.letter)}", call read_messages before each task, post status/questions to "pm". Recipients: ${allRoles}. Include Python shim fallback.\n` +
      `10. STATUS UPDATE format: Task / Status (COMPLETE|IN-PROGRESS|BLOCKED) / Notes (what + why) / Next — print locally AND post to pm via relay\n` +
      `11. Final test commands for ${dev.techDomain}\n` +
      `12. PR procedure: gh pr create targeting main, title "feat(${release}): Dev-${dev.letter} — <scope>"\n` +
      `13. First action: run worktree setup, emit STATUS UPDATE "setup complete", start Task 1`,
      { label: `gen-dev-${dev.letter.toLowerCase()}`, phase: 'Generate' }
    )),

  ])

  // Check relay, start if needed
  await agent(
    `Check if the relay server is running on localhost:7331 by running: ` +
    `curl -sf http://127.0.0.1:7331/sse --max-time 2 > /dev/null 2>&1 && echo running || echo stopped\n\n` +
    `If the output is "stopped", start it: ` +
    `nohup npx tsx ${REPO}/tools/relay/server.ts > /tmp/relay-${release}.log 2>&1 &\n` +
    `Then poll curl -sf http://127.0.0.1:7331/sse --max-time 1 once per second for up to 10s. ` +
    `Report "relay ready" or "relay failed to start (check /tmp/relay-${release}.log)".`,
    { label: 'relay-check', phase: 'Generate' }
  )

  await agent(
    `Write a bash launch script to ${REPO}/${COORD_DIR}/${release}-launch.sh.\n\n` +
    `Header comment: # Auto-generated by release workflow — ${release}\n` +
    `set -e\n\n` +
    `Section 1 — Relay health check and auto-start:\n` +
    `  if curl -sf http://127.0.0.1:7331/sse --max-time 2 > /dev/null 2>&1; then\n` +
    `    echo "[relay] already running"\n` +
    `  else\n` +
    `    echo "[relay] starting..." && nohup npx tsx ${REPO}/tools/relay/server.ts > /tmp/relay-${release}.log 2>&1 &\n` +
    `    for i in $(seq 1 10); do sleep 1; curl -sf http://127.0.0.1:7331/sse --max-time 1 > /dev/null 2>&1 && echo "[relay] ready" && break || true; [ $i -eq 10 ] && echo "[relay] ERROR — check /tmp/relay-${release}.log" && exit 1; done\n` +
    `  fi\n\n` +
    `Section 2 — tmux session. Session name is the release label.\n` +
    `  If tmux session already exists, attach and exit.\n` +
    `  Otherwise create a new session, then for each role (pm + each dev letter) create a named window\n` +
    `  that runs: claude\n` +
    `  After creating windows, print a prompt-paste cheatsheet showing which file to paste in each window.\n` +
    `  Then attach to the session.\n\n` +
    `Devs: ${assignment.devs.map(d => 'Dev-' + d.letter).join(', ')}\n` +
    `Prompt files in ${COORD_DIR}:\n` +
    `  PM:    ${release}-pm-prompt.md\n` +
    assignment.devs.map(d => `  Dev-${d.letter}: ${release}-dev-${d.letter.toLowerCase()}-prompt.md`).join('\\n') + '\\n\\n' +
    `After writing the file, run: chmod +x ${REPO}/${COORD_DIR}/${release}-launch.sh`,
    { label: 'gen-launch-script', phase: 'Generate' }
  )

  log(`Prompts + launch script ready in ${COORD_DIR}/`)
  log(`Run: ${REPO}/${COORD_DIR}/${release}-launch.sh`)
  log(`(starts relay if needed, opens tmux session, prompts you which file to paste in each window)`)

  return { status: 'prompts-ready', devCount: assignment.devCount, coordDir: COORD_DIR }
}

// ── ACTION: debug ─────────────────────────────────────────────────────────────

if (action === 'debug') {
  if (!context) throw new Error('args.context required for action=debug — describe the failure or paste test output')

  let currentContext = context
  const MAX_ITERATIONS = 5

  for (let i = 1; i <= MAX_ITERATIONS; i++) {
    phase(`Debug iteration ${i}`)

    const result = await agent(
      `You are debugging a failure in Relicario at ${REPO}. IMPORTANT: cd ${REPO} first.\n\n` +
      `Failure context:\n${currentContext}\n\n` +
      `Use systematic debugging:\n` +
      `1. Form a specific hypothesis about the root cause.\n` +
      `2. Read the relevant source files and tests.\n` +
      `3. Implement the minimal fix — no unrelated changes.\n` +
      `4. Run the failing test(s) to confirm they now pass.\n` +
      `5. Run cargo test to confirm no regressions.\n` +
      `6. Commit the fix if clean.\n\n` +
      `Return fixed=true if all tests pass, fixed=false with remainingFailures if not.`,
      { schema: DEBUG_RESULT_SCHEMA, label: `debug-iter-${i}` }
    )

    log(`Iteration ${i}: ${result.summary}`)

    if (result.fixed) {
      log(`Fixed after ${i} iteration(s).`)
      return { status: 'fixed', iterations: i, summary: result.summary }
    }

    currentContext = result.remainingFailures || currentContext
    log(`Still failing — next iteration with updated context`)
  }

  log(`Reached max iterations (${MAX_ITERATIONS}). Manual intervention needed.`)
  return { status: 'max-iterations', lastContext: currentContext }
}

// ── ACTION: verify ────────────────────────────────────────────────────────────

if (action === 'verify') {
  phase('Verify')
  const result = await agent(
    `Run the full Relicario test suite from ${REPO}. IMPORTANT: cd ${REPO} first.\n` +
    `  cargo test\n` +
    `  cargo build --all-targets\n` +
    `  cargo clippy -- -D warnings\n` +
    `Report pass/fail for each. List every failure with its error text.`,
    { schema: VERIFY_RESULT_SCHEMA, label: 'verify' }
  )

  if (result.allPass) {
    log(`All checks pass.`)
  } else {
    log(`FAILED: ${result.failures.join(' | ')}`)
    log(`Fix with: Workflow({name:"release", args:{action:"debug", context:"<paste failures>"}})`)
  }

  return result
}

// ── ACTION: release ───────────────────────────────────────────────────────────

if (action === 'release') {
  if (!release) throw new Error('args.release is required for action=release')

  phase('Verify')
  const verifyResult = await agent(
    `Run the full Relicario test suite from ${REPO}. IMPORTANT: cd ${REPO} first.\n` +
    `  cargo test\n` +
    `  cargo build --all-targets\n` +
    `  cargo clippy -- -D warnings\n` +
    `Report pass/fail. List failures.`,
    { schema: VERIFY_RESULT_SCHEMA, label: 'pre-release-verify' }
  )

  if (!verifyResult.allPass) {
    log(`Tests failing — cannot cut release. Fix first with action=debug.`)
    return { status: 'blocked', failures: verifyResult.failures }
  }

  // ── Version + tag checks ─────────────────────────────────────────────────

  const versionCheck = await agent(
    `Read ${REPO}/Cargo.toml and all files matching ${REPO}/crates/*/Cargo.toml.\n` +
    `For each file, extract the version field from the [package] section.\n` +
    `Check whether all extracted versions are identical.\n` +
    `Then run: git -C ${REPO} tag -l "${release}"\n` +
    `Set tagExists=true if the output is non-empty (the tag already exists), false otherwise.\n` +
    `Return consistent (true if all versions match), versions (list of all extracted version strings), ` +
    `conflicts (list of "file: version" strings for any that differ from the majority), and tagExists.`,
    { schema: VERSION_CHECK_SCHEMA, label: 'version-tag-check', phase: 'Finalize' }
  )

  if (!versionCheck.consistent) {
    log(`FAIL [version-tag-check]: version mismatch across crates — ${versionCheck.conflicts.join(' | ')}`)
    return { status: 'blocked', reason: 'version-mismatch' }
  }

  if (versionCheck.tagExists) {
    log(`FAIL [version-tag-check]: tag "${release}" already exists — cannot re-tag`)
    return { status: 'blocked', reason: 'tag-exists' }
  }

  log(`[version-tag-check]: Versions consistent (${versionCheck.versions[0]}), tag available`)

  // ── Advisory: debug artifact scan ──────────────────────────────────────────

  await agent(
    `Run the following command from ${REPO}:\n` +
    `  git -C ${REPO} diff $(git -C ${REPO} describe --tags --abbrev=0)..HEAD\n\n` +
    `Examine lines beginning with "+" (additions) in the diff output.\n` +
    `Report any occurrences of:\n` +
    `  - dbg!( in Rust files (warn)\n` +
    `  - console.log( in TypeScript files (warn)\n` +
    `  - TODO or FIXME anywhere (warn)\n` +
    `  - .unwrap() in Rust files (advisory note only, not a hard warn)\n` +
    `Log each finding with its file and line. This is advisory only — do not block.`,
    { label: 'debug-artifact-scan', phase: 'Finalize' }
  )

  phase('Finalize')
  await agent(
    `Cut the ${release} release for Relicario at ${REPO}. IMPORTANT: cd ${REPO} first.\n\n` +
    `Steps (in order):\n` +
    `1. Run: git log $(git describe --tags --abbrev=0)..HEAD --oneline\n` +
    `   Use that output to write a ${release} section in CHANGELOG.md — user-facing language, grouped by type.\n` +
    `2. Update STATUS.md: mark ${release} as released, set what is next.\n` +
    `3. Update ROADMAP.md: check off the ${release} milestone.\n` +
    `4. Commit those doc updates: git commit -m "release: ${release}"\n` +
    `5. Create annotated tag: git tag -a ${release} -m "Release ${release}"\n` +
    `6. STOP. Print the tag SHA and the push command, then ask the user to confirm before pushing.\n` +
    `   Do NOT run git push or git push --tags without explicit user confirmation.`,
    { label: 'cut-release', phase: 'Finalize' }
  )

  return { status: 'tagged', release, note: 'Confirm and push manually.' }
}

// ── ACTION: cleanup ───────────────────────────────────────────────────────────

if (action === 'cleanup') {
  phase('Cleanup')

  const result = await agent(
    `Run: git -C ${REPO} worktree list\n` +
    `Run: git -C ${REPO} branch --merged main\n\n` +
    `For each worktree listed (skip the main checkout at ${REPO} itself):\n` +
    `  - If its branch appears in the merged list:\n` +
    `      Run: git -C ${REPO} worktree remove --force <path>\n` +
    `      Run: git -C ${REPO} branch -d <branch>   (lowercase -d only, never -D)\n` +
    `      Add to removed: [{path, branch}]\n` +
    `  - If its branch does NOT appear in the merged list:\n` +
    `      Add to kept: [{path, branch, reason: "unmerged"}]\n\n` +
    `Return removed (worktrees that were deleted) and kept (worktrees that were left in place).`,
    { schema: CLEANUP_RESULT_SCHEMA, label: 'cleanup', phase: 'Cleanup' }
  )

  log(`Cleanup removed ${result.removed.length} worktree(s):`)
  for (const w of result.removed) {
    log(`  removed: ${w.path} (${w.branch})`)
  }
  log(`Cleanup kept ${result.kept.length} worktree(s):`)
  for (const w of result.kept) {
    log(`  kept: ${w.path} (${w.branch}) — ${w.reason}`)
  }

  return { status: 'done', removed: result.removed.length, kept: result.kept.length }
}

log(`Unknown action: "${action}". Valid: develop, debug, verify, release, preflight, cleanup`)
return { status: 'error', action }
