{"version":3,"file":"run-CaD4IuDl.mjs","names":["short","parseYaml"],"sources":["../src/workers/edit-assist.ts","../src/workers/note-delivery.ts","../src/router/supervisor.ts","../src/workers/loop-stop.ts","../src/workers/run-events.ts","../src/workers/worker-trouble.ts","../src/workers/usage.ts","../src/workers/run-lock.ts","../src/workers/plan.ts","../src/workers/plan-runner.ts","../src/workers/plan-deps.ts","../src/workers/run-report-wiring.ts","../src/workers/slim-profile.ts","../src/workers/controls.ts","../src/workers/policy.ts","../src/workers/session-name.ts","../src/workers/session-profile.ts","../src/workers/engines/image.ts","../src/workers/pane.ts","../src/workers/tree.ts","../src/workers/handoff.ts","../src/workers/denials.ts","../src/workers/contract-addendum.ts","../src/workers/result-grace.ts","../src/workers/deadline.ts","../src/workers/browser-tools.ts","../src/workers/project-config.ts","../src/workers/codex.ts","../src/workers/run.ts"],"sourcesContent":["export interface EditAssistInput {\n  oldString: string;\n  newString: string;\n  errorText: string;\n  fileText: string | null;\n}\n\n/**\n * Returns a human-readable hint for an edit error, or null if the error is not\n * one that this helper knows how to handle.\n */\nexport function editAssist(i: EditAssistInput): string | null {\n  if (i.errorText.includes(\"No changes to make: old_string and new_string are exactly the same\")) {\n    return \"old_string and new_string are identical: the file already contains your intended text; check whether this step is done (grep for it) before editing again.\";\n  }\n\n  if (i.errorText.includes(\"String to replace not found in file\") && i.fileText !== null) {\n    // Split oldString into lines, drop blank (whitespace-only) lines; if none, return null.\n    const lines = i.oldString.split(\"\\n\");\n    const nonBlankLines = lines.filter(line => line.trim() !== \"\");\n    if (nonBlankLines.length === 0) {\n      return null;\n    }\n\n    // first = trimmed first non-blank line, last = trimmed last non-blank line.\n    const first = nonBlankLines[0].trim();\n    const last = nonBlankLines[nonBlankLines.length - 1].trim();\n\n    // Split fileText into lines.\n    const fileLines = i.fileText.split(\"\\n\");\n\n    // Find the best matching file line index for `first` and for `last`\n    const findBestMatch = (target: string): number | null => {\n      let bestIndex: number | null = null;\n      let bestSimilarity = -1;\n\n      for (let i = 0; i < fileLines.length; i++) {\n        const trimmedLine = fileLines[i].trim();\n        if (trimmedLine === target) {\n          return i; // Exact match wins\n        }\n\n        const similarity = computeSimilarity(target, trimmedLine);\n        if (similarity >= 0.5 && similarity > bestSimilarity) {\n          bestSimilarity = similarity;\n          bestIndex = i;\n        }\n      }\n\n      return bestIndex;\n    };\n\n    const firstIndex = findBestMatch(first);\n    const lastIndex = findBestMatch(last);\n\n    // Check if we're deleting\n    const deleting = i.newString.trim() === \"\";\n\n    // If neither anchor is found return \"old_string not found and no similar line exists in the file\"\n    if (firstIndex === null && lastIndex === null) {\n      let result = \"old_string not found and no similar line exists in the file; re-read the file (Read) before editing again.\";\n      if (deleting) {\n        result += \"\\nif you are deleting this, grep for it first: it may already be gone.\";\n      }\n      return result;\n    }\n\n    // Otherwise, determine the region\n    let startIndex: number = firstIndex !== null ? firstIndex : lastIndex!;\n    let endIndex: number = lastIndex !== null ? lastIndex : firstIndex!;\n\n    // For `last`, prefer a match at an index >= the first's index when several tie\n    if (lastIndex !== null && firstIndex !== null && lastIndex < firstIndex) {\n      startIndex = lastIndex;\n      endIndex = firstIndex;\n    }\n\n    // Widen by 3 lines of context each side (clamped), cap at 40 lines\n    const context = 3;\n    startIndex = Math.max(0, startIndex - context);\n    endIndex = Math.min(fileLines.length - 1, endIndex + context);\n\n    // Cap at 40 lines\n    const regionLength = endIndex - startIndex + 1;\n    if (regionLength > 40) {\n      const half = Math.floor(40 / 2);\n      startIndex = Math.max(0, (firstIndex ?? lastIndex ?? 0) - half);\n      endIndex = Math.min(fileLines.length - 1, startIndex + 39);\n    }\n\n    // Render the region\n    const regionLines = [];\n    for (let i = startIndex; i <= endIndex; i++) {\n      regionLines.push(`${i + 1}\\t${fileLines[i]}`);\n    }\n\n    const header = `closest region of the file (lines ${startIndex + 1}-${endIndex + 1}), copy old_string from here exactly, including whitespace:`;\n    return `${header}\\n${regionLines.join(\"\\n\")}${deleting ? \"\\nif you are deleting this, grep for it first: it may already be gone.\" : \"\"}`;\n  }\n\n  // Deletion hint for when the edit is a deletion\n  if (i.errorText.includes(\"String to replace not found in file\") && i.fileText === null) {\n    if (i.newString.trim() === \"\") {\n      return \"if you are deleting this, grep for it first: it may already be gone.\";\n    }\n    return null;\n  }\n\n  // Any other errorText returns null\n  return null;\n}\n\n/**\n * Computes similarity between two strings based on longest common prefix and suffix.\n * Similarity = (length of longest common prefix + length of longest common suffix) / max(length of both strings)\n */\nfunction computeSimilarity(s1: string, s2: string): number {\n  if (s1 === s2) return 1;\n  if (s1.length === 0 || s2.length === 0) return 0;\n\n  // Longest common prefix\n  let prefixLength = 0;\n  const minLength = Math.min(s1.length, s2.length);\n  for (let i = 0; i < minLength; i++) {\n    if (s1[i] === s2[i]) {\n      prefixLength++;\n    } else {\n      break;\n    }\n  }\n\n  // Longest common suffix\n  let suffixLength = 0;\n  const s1Reversed = s1.split('').reverse().join('');\n  const s2Reversed = s2.split('').reverse().join('');\n  for (let i = 0; i < minLength; i++) {\n    if (s1Reversed[i] === s2Reversed[i]) {\n      suffixLength++;\n    } else {\n      break;\n    }\n  }\n\n  const totalLength = Math.max(s1.length, s2.length);\n  return totalLength > 0 ? (prefixLength + suffixLength) / totalLength : 0;\n}\n\n/**\n * Checks if an error text is one that editAssist can handle.\n */\nimport { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\nexport function isEditAssistError(errorText: string): boolean {\n  return errorText.includes(\"No changes to make: old_string and new_string are exactly the same\") ||\n         errorText.includes(\"String to replace not found in file\");\n}\n\n/** Hint for a failed Edit tool call: reads the target file under cwd and delegates to editAssist; null when it has nothing to add. */\nexport function editHintFor(input: unknown, errorText: string, cwd: string): string | null {\n  if (!isEditAssistError(errorText) || typeof input !== \"object\" || input === null) return null;\n  const i = input as Record<string, unknown>;\n  const oldString = typeof i.old_string === \"string\" ? i.old_string : \"\";\n  const newString = typeof i.new_string === \"string\" ? i.new_string : \"\";\n  let fileText: string | null = null;\n  if (typeof i.file_path === \"string\") {\n    try { fileText = readFileSync(resolve(cwd, i.file_path), \"utf8\"); } catch { fileText = null; }\n  }\n  return editAssist({ oldString, newString, errorText, fileText });\n}","/**\n * note-delivery.ts — hand `pai worker goal` notes to the running worker.\n *\n * `goal` only stores the note in the status file; nothing reads it back into\n * the worker's conversation. The PostToolUse hook (hooks/ts/post-tool-use/\n * worker-note.ts) calls takePendingNotes after every tool call: each note is\n * returned exactly once and the delivery time is recorded for `pai worker ps`.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport { loadStatus, nowStamp, saveStatus } from \"./status.js\";\n\n/** The pending notes of a worker, cleared and stamped as delivered; null when there are none. */\nexport function takePendingNotes(logDir: string, id: string, d: Date = new Date()): string[] | null {\n  const status = loadStatus(logDir, id);\n  if (!status?.notePending?.length) return null;\n  const notes = status.notePending;\n  status.notePending = [];\n  status.noteDeliveredAt = nowStamp(d);\n  saveStatus(logDir, status, d, true);\n  return notes;\n}\n\n/** Env var carrying the per-run note token from the runner to the worker's hooks. */\nexport const NOTE_TOKEN_ENV = \"PAI_WORKER_NOTE_TOKEN\";\n\n/** A fresh random per-run token (8 hex chars). */\nexport function newNoteToken(): string {\n  return randomBytes(4).toString(\"hex\");\n}\n\n/** The additionalContext text for the delivered notes, each authenticated with the run's token. */\nexport function noteContext(notes: string[], token: string): string {\n  return notes.map((n) => `PAI note [${token}]: ${n}`).join(\"\\n\");\n}\n","/**\n * Keeps `pai router` running under the daemon: probe the port each tick and\n * start the router when it is down. Opt-in via `router.enabled` (config).\n */\n\nimport { spawn } from \"node:child_process\";\nimport { closeSync, existsSync, mkdirSync, openSync, readFileSync } from \"node:fs\";\nimport { paiHomePath } from \"../config/pai-home.js\";\nimport { dirname } from \"node:path\";\nimport { connect } from \"node:net\";\nimport { pidAlive } from \"../workers/status.js\";\nimport { ROUTER_PORT } from \"./router.js\";\n\nexport const routerPidFile = (): string => paiHomePath(\"router.pid\");\nexport const routerLogFile = (): string => paiHomePath(\"logs\", \"router.log\");\n\nexport function routerRunningPid(): number | null {\n  if (!existsSync(routerPidFile())) return null;\n  const pid = parseInt(readFileSync(routerPidFile(), \"utf8\"), 10);\n  if (!pid) return null;\n  return pidAlive(pid) ? pid : null;\n}\n\n/** Spawn `<cli> router run` detached, logging to the router log. Returns the child pid. */\nexport function spawnRouter(cliEntry: string, extraArgs: string[] = []): number | undefined {\n  mkdirSync(dirname(routerLogFile()), { recursive: true });\n  const fd = openSync(routerLogFile(), \"a\");\n  const child = spawn(process.execPath, [cliEntry, \"router\", \"run\", ...extraArgs], {\n    detached: true,\n    stdio: [\"ignore\", fd, fd],\n  });\n  closeSync(fd);\n  child.unref();\n  return child.pid;\n}\n\n/** True when something accepts TCP connections on the router port. */\nexport function probeRouter(port = ROUTER_PORT, timeoutMs = 2000): Promise<boolean> {\n  return new Promise((resolve) => {\n    const sock = connect({ host: \"127.0.0.1\", port });\n    const done = (up: boolean) => {\n      sock.destroy();\n      resolve(up);\n    };\n    sock.setTimeout(timeoutMs, () => done(false));\n    sock.once(\"connect\", () => done(true));\n    sock.once(\"error\", () => done(false));\n  });\n}\n\nexport interface RouterTickDeps {\n  probe: () => Promise<boolean>;\n  start: () => void;\n}\n\n/** One health check: starts the router when down, never replaces a live router. */\nexport async function runRouterTick(deps: RouterTickDeps): Promise<\"up\" | \"started\"> {\n  if (await deps.probe()) {\n    return \"up\";\n  }\n  deps.start();\n  return \"started\";\n}\n","/**\n * loop-stop.ts — the loop guard's hard stop, made independent of Claude Code.\n *\n * `\"continue\": false` from a PreToolUse hook does not end a headless\n * (`claude -p`) session, so the hook also leaves a marker the run's finalise\n * step reads (the worker then ends failed with reason \"loop-stopped\") and\n * signals the worker's own claude process.\n */\nimport { execFileSync } from \"node:child_process\";\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { loadStatus, saveStatus } from \"./status.js\";\n\nexport const loopStopMarkerPath = (logDir: string, id: string): string => join(logDir, `${id}.loop-stop`);\n\nexport interface LoopStopMarker {\n  ts: string;\n  reason: string;\n}\n\nexport interface LoopStopDeps {\n  kill?: (pid: number, signal: NodeJS.Signals) => void;\n  /** Pid of the claude process the hook runs under; default: the hook's parent, skipping a wrapping shell. */\n  claudePid?: () => number | undefined;\n}\n\nconst SHELLS = new Set([\"sh\", \"bash\", \"zsh\", \"dash\"]);\n\nfunction psField(pid: number, field: \"comm\" | \"ppid\"): string | undefined {\n  try {\n    return execFileSync(\"ps\", [\"-o\", `${field}=`, \"-p\", String(pid)], { encoding: \"utf8\" }).trim() || undefined;\n  } catch {\n    return undefined;\n  }\n}\n\n/** The hook's parent, or its parent's parent when the hook was started through a shell. */\nexport function defaultClaudePid(): number | undefined {\n  let pid = process.ppid;\n  const comm = psField(pid, \"comm\")?.split(\"/\").pop() ?? \"\";\n  if (SHELLS.has(comm.replace(/^-/, \"\"))) {\n    const up = Number(psField(pid, \"ppid\"));\n    if (up > 1) pid = up;\n  }\n  return pid > 1 ? pid : undefined;\n}\n\n/** Mark the worker loop-stopped (marker file + status note) and SIGTERM its claude process. Never throws. */\nexport function requestLoopStop(logDir: string, id: string, reason: string, deps: LoopStopDeps = {}): void {\n  const { kill = (pid, sig) => process.kill(pid, sig), claudePid = defaultClaudePid } = deps;\n  try {\n    const m: LoopStopMarker = { ts: new Date().toISOString(), reason };\n    writeFileSync(loopStopMarkerPath(logDir, id), JSON.stringify(m));\n  } catch {\n    // the signal below still ends the run\n  }\n  try {\n    const st = loadStatus(logDir, id);\n    if (st && st.state === \"running\") saveStatus(logDir, { ...st, last: `loop-stopped: ${reason}` });\n  } catch {\n    // best effort\n  }\n  try {\n    const pid = claudePid();\n    if (pid) kill(pid, \"SIGTERM\");\n  } catch {\n    // process already gone\n  }\n}\n\n/** The marker of a loop-stopped worker, consumed on read; null when there is none. */\nexport function takeLoopStop(logDir: string, id: string): LoopStopMarker | null {\n  const p = loopStopMarkerPath(logDir, id);\n  if (!existsSync(p)) return null;\n  try {\n    return JSON.parse(readFileSync(p, \"utf8\")) as LoopStopMarker;\n  } catch {\n    return { ts: \"\", reason: \"loop guard\" };\n  } finally {\n    try {\n      unlinkSync(p);\n    } catch {\n      // already gone\n    }\n  }\n}\n\n/** The marker without consuming it. */\nexport function peekLoopStop(logDir: string, id: string): LoopStopMarker | null {\n  const p = loopStopMarkerPath(logDir, id);\n  if (!existsSync(p)) return null;\n  try {\n    return JSON.parse(readFileSync(p, \"utf8\")) as LoopStopMarker;\n  } catch {\n    return { ts: \"\", reason: \"loop guard\" };\n  }\n}\n","/**\n * run-events.ts — report plan and queue runs back into the conversation.\n *\n * The operator never polls: a run reports the moments that need them to the\n * session that started it (AIBroker send_to_session, so the session wakes and\n * can talk to the operator) and, for blocked/finished, to PAILot. A run\n * started with --detach is registered under <logDir>/runs and keeps going\n * after the starting session ends. Everything outside the process (AIBroker,\n * clock, spawning) goes through injected functions; tests never send.\n */\n\nimport { spawn } from \"node:child_process\";\nimport { existsSync, mkdirSync, openSync, readdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { RunLogEntry } from \"./plan-runner.js\";\nimport type { QueueItem } from \"./queue.js\";\n\n/** The session that started a run: where its events go. */\nexport interface RunOrigin {\n  claudeSession?: string;\n  /** iTerm2 session uuid (AIBroker target). */\n  iterm?: string;\n  /** PAI / AIBroker session name. */\n  name?: string;\n}\n\nexport interface Messenger {\n  /** Type a message into the originating session. */\n  toSession(origin: RunOrigin, text: string): Promise<boolean>;\n  /** Short plain sentence to the operator's phone. */\n  toPailot(text: string): Promise<boolean>;\n}\n\nexport const PLAN_GROUP_THROTTLE_MS = 15 * 60_000;\nexport const QUEUE_READY_BATCH_MS = 10 * 60_000;\n\n/** The origin of the calling session, from its environment. */\nexport function originFromEnv(env: NodeJS.ProcessEnv = process.env): RunOrigin {\n  if (env.PAI_RUN_ORIGIN) {\n    try {\n      return JSON.parse(env.PAI_RUN_ORIGIN) as RunOrigin;\n    } catch {\n      /* fall through to the live environment */\n    }\n  }\n  const o: RunOrigin = {};\n  if (env.CLAUDE_CODE_SESSION_ID) o.claudeSession = env.CLAUDE_CODE_SESSION_ID;\n  const iterm = env.ITERM_SESSION_ID?.split(\":\").pop();\n  if (iterm) o.iterm = iterm;\n  const name = env.PAI_WORKER_PARENT ?? env.PAI_SESSION_NAME ?? env.AIBROKER_SESSION_NAME ?? env.AIBROKER_SESSION;\n  if (name) o.name = name;\n  return o;\n}\n\n/** Real messenger over AIBroker's socket; unreachable AIBroker is logged and ignored. */\nexport function aibrokerMessenger(logDir: string, warn: (s: string) => void = (s) => process.stderr.write(s + \"\\n\")): Messenger {\n  return {\n    async toSession(origin, text) {\n      try {\n        const { sendToSession } = await import(\"../cli/lib/aibroker-client.js\");\n        let target = origin.iterm;\n        if (!target && origin.claudeSession) {\n          const { itermForClaudeSession } = await import(\"./scope.js\");\n          target = itermForClaudeSession(logDir, origin.claudeSession) ?? undefined;\n        }\n        target = target ?? origin.name;\n        if (!target) {\n          warn(\"run report not delivered: the run has no originating session\");\n          return false;\n        }\n        const r = await sendToSession(target, text);\n        if (!r.ok && !r.timedOut) warn(`run report not delivered to the session: ${r.error}`);\n        return r.ok || r.timedOut === true;\n      } catch (e) {\n        warn(`run report not delivered to the session: ${String(e)}`);\n        return false;\n      }\n    },\n    async toPailot(text) {\n      try {\n        const { callAiBroker } = await import(\"../cli/lib/aibroker-client.js\");\n        await callAiBroker(\"pailot_send\", { text }, 8_000);\n        return true;\n      } catch (e) {\n        warn(`run report not delivered to PAILot: ${String(e)}`);\n        return false;\n      }\n    },\n  };\n}\n\nconst short = (s: string | undefined, n = 160): string => (s ?? \"\").replace(/\\s+/g, \" \").trim().slice(0, n);\nconst mins = (ms: number): string => {\n  const m = Math.round(ms / 60_000);\n  return m < 1 ? `${Math.round(ms / 1000)}s` : `${m} min`;\n};\nconst fmtTok = (n: number): string => (n >= 1000 ? `${Math.round(n / 100) / 10}k` : String(n));\n\n/** AG2-style kind line plus a plain sentence, one line (it is typed into a terminal). */\nexport function eventLine(id: string, kind: string, fields: Record<string, string | number>, sentence: string): string {\n  const kv = Object.entries(fields).map(([k, v]) => `${k}=${String(v).replace(/[|\\n]/g, \" \")}`);\n  return `S i=${id} z=${kind}${kv.length ? \" | \" + kv.join(\" | \") : \"\"} — ${sentence}`;\n}\n\nabstract class Reporter {\n  private chain: Promise<unknown> = Promise.resolve();\n  constructor(protected readonly msg: Messenger, protected readonly origin: RunOrigin, protected readonly now: () => number) {}\n  protected send(text: string, pailot?: string): void {\n    this.chain = this.chain.then(async () => {\n      await this.msg.toSession(this.origin, text).catch(() => false);\n      if (pailot) await this.msg.toPailot(pailot).catch(() => false);\n    });\n  }\n  /** Wait for every queued message; call before the process exits. */\n  async flush(): Promise<void> {\n    await this.chain;\n  }\n}\n\n/** Turns the plan runner's log entries into messages. Feed it every entry via `onLog`. */\nexport class PlanReporter extends Reporter {\n  private readonly start: number;\n  private tokens = 0;\n  private escalations = 0;\n  private merged = 0;\n  private readonly nd: string[] = [];\n  private lastGroup = -Infinity;\n  private pendingGroups: string[] = [];\n\n  constructor(private readonly job: string, private readonly totalParts: number, msg: Messenger, origin: RunOrigin, now: () => number = Date.now) {\n    super(msg, origin, now);\n    this.start = now();\n  }\n\n  private get id(): string {\n    return `plan:${this.job}`;\n  }\n\n  onLog(e: RunLogEntry): void {\n    if (e.event === \"part-end\" && typeof e.tokens === \"number\") this.tokens += e.tokens;\n    if (e.event === \"escalate\") this.escalations++;\n    if (e.event === \"merge\" && e.ok) this.merged++;\n    if (e.event === \"needs-decision\" && e.part) {\n      this.nd.push(e.part);\n      this.send(\n        eventLine(this.id, \"needs-decision\", { part: e.part }, `Part ${e.part} of ${this.job} failed twice and needs your decision: ${short(e.note)}`),\n      );\n    }\n    if (e.event === \"unit-check\" && e.ok === false) {\n      this.send(eventLine(this.id, \"unit-check-failed\", { unit: e.unit ?? \"?\" }, `The check after unit ${e.unit} of ${this.job} failed: ${short(e.note)}`));\n    }\n    if (e.event === \"unit-done\" && e.unit) this.unitDone(e.unit);\n    if (e.event === \"run-end\") this.runEnd(e);\n  }\n\n  private unitDone(unit: string): void {\n    this.pendingGroups.push(unit);\n    const t = this.now();\n    if (t - this.lastGroup < PLAN_GROUP_THROTTLE_MS) return;\n    this.lastGroup = t;\n    const units = this.pendingGroups.splice(0);\n    this.send(eventLine(this.id, \"unit-done\", { units: units.join(\",\") }, `${this.job}: ${units.length === 1 ? \"unit\" : \"units\"} ${units.join(\", \")} finished; ${this.merged} of ${this.totalParts} parts merged so far.`));\n  }\n\n  private runEnd(e: RunLogEntry): void {\n    const outcome = e.ok ? \"merged\" : e.status === \"blocked\" ? \"blocked\" : \"failed\";\n    const wall = mins(this.now() - this.start);\n    const stats = { outcome, wall, merged: `${this.merged}/${this.totalParts}`, escalations: this.escalations, cloud_tokens: this.tokens };\n    const what =\n      outcome === \"merged\"\n        ? `${this.job} is done: all ${this.totalParts} parts merged in ${wall}.`\n        : outcome === \"blocked\"\n          ? `${this.job} is blocked after ${wall}: ${this.merged} of ${this.totalParts} parts merged, the rest wait on ${this.nd.join(\", \") || \"a failed check\"}. It needs your decision.`\n          : `${this.job} ended with failures after ${wall}: ${this.merged} of ${this.totalParts} parts merged${this.nd.length ? `, ${this.nd.join(\", \")} need your decision` : \"\"}.`;\n    const extra = ` Escalations ${this.escalations}, ${fmtTok(this.tokens)} tokens.`;\n    this.send(eventLine(this.id, \"run-\" + outcome, stats, what + extra), what);\n  }\n}\n\n/** Queue events: needs-decision at once, ready items batched. */\nexport class QueueReporter extends Reporter {\n  private readyBatch: QueueItem[] = [];\n  private lastReady = -Infinity;\n\n  constructor(private readonly project: string, msg: Messenger, origin: RunOrigin, now: () => number = Date.now) {\n    super(msg, origin, now);\n  }\n\n  private get id(): string {\n    return `queue:${this.project}`;\n  }\n\n  onReady(item: QueueItem): void {\n    this.readyBatch.push(item);\n    if (this.now() - this.lastReady >= QUEUE_READY_BATCH_MS) this.sendReady();\n  }\n\n  onNeedsDecision(item: QueueItem): void {\n    this.send(eventLine(this.id, \"needs-decision\", { item: item.id }, `Queue item ${item.id} (\"${short(item.text, 80)}\") failed twice and needs your decision: ${short(item.why)}`));\n  }\n\n  private sendReady(): void {\n    const items = this.readyBatch.splice(0);\n    if (!items.length) return;\n    this.lastReady = this.now();\n    const list = items.map((i) => `${i.id} \"${short(i.text, 60)}\"`).join(\", \");\n    this.send(eventLine(this.id, \"ready\", { items: items.map((i) => i.id).join(\",\") }, `${items.length === 1 ? \"One queue item is\" : `${items.length} queue items are`} ready for review: ${list}.`));\n  }\n\n  /** Send what the throttle held back; call once the run is over. */\n  async finish(): Promise<void> {\n    this.sendReady();\n    await this.flush();\n  }\n}\n\n// ---------------------------------------------------------------------------\n// detach: registry of runs that outlive their session\n\nexport interface RunRecord {\n  id: string;\n  kind: \"plan\" | \"queue\";\n  pid: number;\n  argv: string[];\n  cwd: string;\n  origin: RunOrigin;\n  started: string;\n  output: string;\n}\n\nexport const runsDir = (logDir: string): string => join(logDir, \"runs\");\nexport const runRecordPath = (logDir: string, id: string): string => join(runsDir(logDir), `${id}.json`);\n\nexport interface DetachDeps {\n  /** Start `bin args` detached with stdout/stderr to `outFd`; returns the pid. */\n  spawnDetached(bin: string, args: string[], opts: { cwd: string; env: NodeJS.ProcessEnv; outPath: string }): number;\n  now(): number;\n}\n\nexport const realDetachDeps: DetachDeps = {\n  spawnDetached(bin, args, { cwd, env, outPath }) {\n    const fd = openSync(outPath, \"a\");\n    const child = spawn(bin, args, { cwd, env, detached: true, stdio: [\"ignore\", fd, fd] });\n    child.unref();\n    return child.pid ?? 0;\n  },\n  now: Date.now,\n};\n\n/**\n * Hand a run to a detached process and register it. `argv` is the pai\n * command line of the run without --detach; the origin travels in the env so\n * the child reports to the session that started it.\n */\nexport function detachRun(\n  logDir: string,\n  kind: \"plan\" | \"queue\",\n  label: string,\n  bin: string,\n  argv: string[],\n  cwd: string,\n  origin: RunOrigin,\n  deps: DetachDeps = realDetachDeps,\n): RunRecord {\n  mkdirSync(runsDir(logDir), { recursive: true });\n  const stamp = new Date(deps.now()).toISOString().replace(/[-:T]/g, \"\").slice(0, 14);\n  const id = `${kind}-${label.replace(/[^\\w.-]/g, \"_\")}-${stamp}`;\n  const output = join(runsDir(logDir), `${id}.out`);\n  const pid = deps.spawnDetached(bin, argv, { cwd, env: { ...process.env, PAI_RUN_ORIGIN: JSON.stringify(origin), PAI_RUN_ID: id }, outPath: output });\n  const rec: RunRecord = { id, kind, pid, argv: [bin, ...argv], cwd, origin, started: new Date(deps.now()).toISOString(), output };\n  writeFileSync(runRecordPath(logDir, id), JSON.stringify(rec, null, 2) + \"\\n\", \"utf8\");\n  return rec;\n}\n\nexport function listRuns(logDir: string): RunRecord[] {\n  const dir = runsDir(logDir);\n  if (!existsSync(dir)) return [];\n  const out: RunRecord[] = [];\n  for (const f of readdirSync(dir)) {\n    if (!f.endsWith(\".json\")) continue;\n    try {\n      out.push(JSON.parse(readFileSync(join(dir, f), \"utf8\")) as RunRecord);\n    } catch {\n      /* torn record */\n    }\n  }\n  return out;\n}\n\n/** The detached child calls this on a clean end, so the sweep does not report it as dead. */\nexport function markRunDone(logDir: string, id: string, now: () => number = Date.now): void {\n  try {\n    writeFileSync(`${runRecordPath(logDir, id)}.done`, new Date(now()).toISOString(), \"utf8\");\n  } catch {\n    /* the registry is a courtesy; the run's own result stands */\n  }\n}\n\n/**\n * Daemon tick: a registered run whose process is gone without a done marker\n * died silently; tell its session (and PAILot) once.\n */\nexport async function sweepRuns(logDir: string, msg: Messenger, isAlive: (pid: number) => boolean, now: () => number = Date.now): Promise<string[]> {\n  const told: string[] = [];\n  for (const r of listRuns(logDir)) {\n    const marker = `${runRecordPath(logDir, r.id)}.done`;\n    if (existsSync(marker) || isAlive(r.pid)) continue;\n    markRunDone(logDir, r.id, now);\n    const what = `The detached ${r.kind} run ${r.id} stopped without finishing; see ${r.output}.`;\n    await msg.toSession(r.origin, eventLine(r.id, \"run-died\", { output: r.output }, what)).catch(() => false);\n    await msg.toPailot(what).catch(() => false);\n    told.push(r.id);\n  }\n  return told;\n}\n","/**\n * worker-trouble.ts — tell the session that started a worker when PAI's guards\n * hit it. Fed by the supervising `pai worker run` process (the one place each\n * denial is counted once), over the run-events messenger: session only, never\n * PAILot. At most one message per worker per TROUBLE_THROTTLE_MS; the hard\n * stop is always sent. A delivery failure is the messenger's to log.\n */\n\nimport { eventLine, type Messenger, type RunOrigin } from \"./run-events.js\";\n\nexport const TROUBLE_THROTTLE_MS = 5 * 60_000;\nexport const DENIAL_WINDOW_MS = 10 * 60_000;\nexport const DENIAL_THRESHOLD = 3;\nexport const STALL_MS = 10 * 60_000;\n\nconst short = (s: string, n: number): string => s.replace(/\\s+/g, \" \").trim().slice(0, n);\n\nexport class TroubleWatcher {\n  private denials: number[] = [];\n  private lastSent = -Infinity;\n  private lastActivity: number;\n  private stallTold = false;\n  private chain: Promise<unknown> = Promise.resolve();\n\n  constructor(\n    private readonly id: string,\n    private readonly label: string,\n    private readonly msg: Messenger,\n    private readonly origin: RunOrigin,\n    private readonly now: () => number = Date.now,\n  ) {\n    this.lastActivity = now();\n  }\n\n  private send(kind: string, fields: Record<string, string | number>, sentence: string, force = false): void {\n    const t = this.now();\n    if (!force && t - this.lastSent < TROUBLE_THROTTLE_MS) return;\n    this.lastSent = t;\n    const text = eventLine(this.id, kind, fields, sentence);\n    this.chain = this.chain.then(() => this.msg.toSession(this.origin, text).catch(() => false));\n  }\n\n  private get who(): string {\n    return `worker ${this.id}${this.label ? ` (${short(this.label, 40)})` : \"\"}`;\n  }\n\n  /** Any sign of life (a transcript line); resets the stall clock. */\n  activity(): void {\n    this.lastActivity = this.now();\n    this.stallTold = false;\n  }\n\n  /** One guard denial; from the 3rd in the window on, tell the session (throttled). */\n  onDenial(hook: string, reason: string): void {\n    const t = this.now();\n    this.denials = this.denials.filter((d) => t - d < DENIAL_WINDOW_MS);\n    this.denials.push(t);\n    const n = this.denials.length;\n    if (n < DENIAL_THRESHOLD) return;\n    const guard = hook.split(\"/\").pop()?.replace(/\\.(mjs|js|ts)$/, \"\") || \"hook\";\n    this.send(\"guard-denials\", { denied: n, guard }, `${this.who} blocked ${n}x by ${guard} in ${Math.round(DENIAL_WINDOW_MS / 60_000)} min: ${short(reason, 120)}`);\n  }\n\n  /** The loop guard's hard stop; always sent. */\n  onLoopStop(reason: string): void {\n    this.send(\"loop-stopped\", {}, `${this.who} was stopped by the loop guard: ${short(reason, 160)}`, true);\n  }\n\n  /** Timer tick while running: no activity for STALL_MS tells once per quiet spell (throttled). */\n  tick(): void {\n    const quiet = this.now() - this.lastActivity;\n    if (quiet < STALL_MS || this.stallTold) return;\n    this.stallTold = true;\n    this.send(\"stalled\", { quiet_min: Math.round(quiet / 60_000) }, `${this.who} has produced no output for ${Math.round(quiet / 60_000)} min while running.`);\n  }\n\n  async flush(): Promise<void> {\n    await this.chain;\n  }\n}\n","/**\n * usage.ts — exact token tallies per model from stream events / transcripts.\n *\n * `sumUsage` (each message id once, its last usage) serves the transcript\n * side, `pai audit tokens usage`; the worker side, `pai worker usage`, reads\n * a run log through `sumRunUsage`, which prefers the run's `result` event —\n * the harness books the run's authoritative totals there, and local servers\n * that report no per-turn counts still show their tokens (src/router/\n * prompt-tokens.ts makes the router fill what the server never reported).\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { eventsPath } from \"./paths.js\";\nimport { loadStatuses, type WorkerStatus } from \"./status.js\";\nimport { isLocalProvider } from \"./config.js\";\nimport type { UsageBlock } from \"../utils/input-side-tokens.js\";\n\nexport interface CacheCreationSplit {\n  ephemeral_5m_input_tokens?: number;\n  ephemeral_1h_input_tokens?: number;\n}\n\nexport type RichUsage = UsageBlock & { cache_creation?: CacheCreationSplit };\n\nexport interface Tally {\n  input: number;\n  cacheRead: number;\n  cacheWrite5m: number;\n  cacheWrite1h: number;\n  output: number;\n}\n\nexport const emptyTally = (): Tally => ({ input: 0, cacheRead: 0, cacheWrite5m: 0, cacheWrite1h: 0, output: 0 });\n\nexport function addTally(into: Tally, t: Tally): void {\n  into.input += t.input;\n  into.cacheRead += t.cacheRead;\n  into.cacheWrite5m += t.cacheWrite5m;\n  into.cacheWrite1h += t.cacheWrite1h;\n  into.output += t.output;\n}\n\n/** One usage block as a tally; a cache write without a 5m/1h split counts as 5m. */\nexport function tallyOf(u: RichUsage): Tally {\n  const split5 = u.cache_creation?.ephemeral_5m_input_tokens;\n  const split1 = u.cache_creation?.ephemeral_1h_input_tokens;\n  const hasSplit = split5 !== undefined || split1 !== undefined;\n  return {\n    input: u.input_tokens ?? 0,\n    cacheRead: u.cache_read_input_tokens ?? 0,\n    cacheWrite5m: hasSplit ? (split5 ?? 0) : (u.cache_creation_input_tokens ?? 0),\n    cacheWrite1h: hasSplit ? (split1 ?? 0) : 0,\n    output: u.output_tokens ?? 0,\n  };\n}\n\nexport interface SumResult {\n  byModel: Map<string, Tally>;\n  /** total_cost_usd of the last result event, when there was one. */\n  costUsd: number | null;\n}\n\n/** camelCase per-model totals of a result event's modelUsage block as a tally. */\nfunction tallyOfModelUsage(mu: Record<string, unknown>): Tally {\n  const num = (v: unknown): number => (typeof v === \"number\" && Number.isFinite(v) ? v : 0);\n  return {\n    input: num(mu.inputTokens),\n    cacheRead: num(mu.cacheReadInputTokens),\n    cacheWrite5m: num(mu.cacheCreationInputTokens),\n    cacheWrite1h: 0,\n    output: num(mu.outputTokens),\n  };\n}\n\nconst tallyIsZero = (t: Tally): boolean => !t.input && !t.cacheRead && !t.cacheWrite5m && !t.cacheWrite1h && !t.output;\n\n/**\n * Sum usage of a *run* event log (a worker's, as opposed to a transcript):\n * the run's `result` event is authoritative when it carries usage or\n * modelUsage — local servers report per-turn counts as 0, and the harness\n * fills them only into the result event. Without a result event (killed run)\n * the assistant turns are summed like a transcript. `fallbackModel` books\n * result-event usage that names no model on the run's own model.\n */\nexport function sumRunUsage(jsonl: string, fallbackModel?: string): SumResult {\n  const perTurn = sumUsage(jsonl);\n  let result: { model?: string; usage?: RichUsage; modelUsage?: Record<string, Record<string, unknown>> } | undefined;\n  for (const line of jsonl.split(\"\\n\")) {\n    if (!line.includes('\"result\"')) continue;\n    try {\n      const e = JSON.parse(line) as { type?: string; model?: string; usage?: RichUsage; modelUsage?: Record<string, Record<string, unknown>> };\n      if (e.type === \"result\") result = e;\n    } catch {\n      /* torn line */\n    }\n  }\n  if (!result) return perTurn;\n  const byModel = new Map<string, Tally>();\n  const mu = result.modelUsage;\n  if (mu && typeof mu === \"object\" && Object.keys(mu).length) {\n    const named: [string, Tally][] = [];\n    for (const [key, v] of Object.entries(mu)) {\n      if (!v || typeof v !== \"object\") continue;\n      const model = typeof (v as { canonicalModel?: unknown }).canonicalModel === \"string\" ? (v as { canonicalModel: string }).canonicalModel : key;\n      named.push([model, tallyOfModelUsage(v)]);\n    }\n    const whole = result.usage ? tallyOf(result.usage) : undefined;\n    if (named.length === 1 && whole && !tallyIsZero(whole)) {\n      // modelUsage has no 5m/1h split; the result's usage block does, and it is the same run total\n      byModel.set(named[0][0], whole);\n    } else if (named.length > 1 && whole && whole.cacheWrite5m + whole.cacheWrite1h > 0) {\n      // modelUsage has per-model totals but no cache TTL split: apply the run-wide 1h share to each\n      // model, rounding by cumulative position so the per-model sums stay exact\n      const total = whole.cacheWrite5m + whole.cacheWrite1h;\n      let seen = 0;\n      let given1h = 0;\n      for (const [model, t] of named) {\n        const write = t.cacheWrite5m;\n        seen += write;\n        const upTo1h = Math.round((seen * whole.cacheWrite1h) / total);\n        const w1h = Math.min(write, upTo1h - given1h);\n        given1h += w1h;\n        byModel.set(model, { ...t, cacheWrite5m: write - w1h, cacheWrite1h: w1h });\n      }\n    } else {\n      for (const [model, t] of named) byModel.set(model, t);\n    }\n  } else if (result.usage && !tallyIsZero(tallyOf(result.usage))) {\n    const model = result.model ?? fallbackModel ?? (perTurn.byModel.size === 1 ? [...perTurn.byModel.keys()][0] : \"?\");\n    byModel.set(model, tallyOf(result.usage));\n  }\n  return byModel.size ? { byModel, costUsd: perTurn.costUsd } : perTurn;\n}\n\n/** Sum assistant usage of JSONL text: each message id once (its last usage), grouped by model. */\nexport function sumUsage(jsonl: string): SumResult {\n  const byId = new Map<string, { model: string; usage: RichUsage }>();\n  let anon = 0;\n  let costUsd: number | null = null;\n  for (const line of jsonl.split(\"\\n\")) {\n    if (!line.trim()) continue;\n    let e: { type?: string; total_cost_usd?: number; message?: { id?: string; model?: string; usage?: RichUsage } };\n    try {\n      e = JSON.parse(line);\n    } catch {\n      continue;\n    }\n    if (e.type === \"result\" && typeof e.total_cost_usd === \"number\") costUsd = e.total_cost_usd;\n    if (e.type !== \"assistant\" || !e.message?.usage) continue;\n    const m = e.message;\n    byId.set(m.id ?? `anon-${anon++}`, { model: m.model ?? \"?\", usage: m.usage! });\n  }\n  const byModel = new Map<string, Tally>();\n  for (const { model, usage } of byId.values()) {\n    const t = byModel.get(model) ?? emptyTally();\n    addTally(t, tallyOf(usage));\n    byModel.set(model, t);\n  }\n  return { byModel, costUsd };\n}\n\nexport interface UsageRow {\n  provider: string;\n  model: string;\n  local: boolean;\n  workers: number;\n  tally: Tally;\n  /** Summed total_cost_usd; null for local rows. */\n  costUsd: number | null;\n}\n\nexport interface UsageReport {\n  rows: UsageRow[];\n  cloud: UsageRow;\n  local: UsageRow;\n}\n\nconst totalRow = (provider: string, local: boolean): UsageRow => ({\n  provider,\n  model: \"\",\n  local,\n  workers: 0,\n  tally: emptyTally(),\n  costUsd: local ? null : 0,\n});\n\nexport function finishReport(rows: UsageRow[]): UsageReport {\n  const cloud = totalRow(\"TOTAL cloud\", false);\n  const local = totalRow(\"TOTAL local\", true);\n  for (const r of rows) {\n    const t = r.local ? local : cloud;\n    t.workers += r.workers;\n    addTally(t.tally, r.tally);\n    if (!r.local) t.costUsd = (t.costUsd ?? 0) + (r.costUsd ?? 0);\n  }\n  return { rows, cloud, local };\n}\n\nexport interface WorkerSelect {\n  labelPrefix?: string;\n  since?: Date;\n  until?: Date;\n}\n\n/** \"1h\", \"30m\", \"2d\" relative to now, or an ISO timestamp. */\nexport function parseWhen(s: string, now = new Date()): Date {\n  const rel = /^(\\d+)([smhd])$/.exec(s.trim());\n  if (rel) {\n    const mult = { s: 1000, m: 60_000, h: 3_600_000, d: 86_400_000 }[rel[2] as \"s\" | \"m\" | \"h\" | \"d\"];\n    return new Date(now.getTime() - Number(rel[1]) * mult);\n  }\n  const d = new Date(s);\n  if (Number.isNaN(d.getTime())) throw new Error(`cannot read \"${s}\" as a time; use an ISO timestamp or 1h / 30m`);\n  return d;\n}\n\n/** Status `started` is local \"YYYY-MM-DD HH:MM:SS\" (or ISO). */\nfunction startedAt(s: WorkerStatus): Date | null {\n  const d = new Date(s.started.includes(\"T\") ? s.started : s.started.replace(\" \", \"T\"));\n  return Number.isNaN(d.getTime()) ? null : d;\n}\n\nexport function selectWorkers(statuses: WorkerStatus[], sel: WorkerSelect): WorkerStatus[] {\n  return statuses.filter((s) => {\n    if (sel.labelPrefix && !(s.label ?? \"\").startsWith(sel.labelPrefix)) return false;\n    const at = startedAt(s);\n    if (sel.since && (!at || at < sel.since)) return false;\n    if (sel.until && (!at || at > sel.until)) return false;\n    return true;\n  });\n}\n\n/** Tally the selected workers; `baseUrls` maps provider name to its baseUrl (for the local mark). */\nexport function workerUsage(logDir: string, sel: WorkerSelect, baseUrls: Record<string, string>): UsageReport {\n  const groups = new Map<string, UsageRow>();\n  for (const st of selectWorkers(loadStatuses(logDir), sel)) {\n    const path = eventsPath(logDir, st.id);\n    if (!existsSync(path)) continue;\n    const { byModel, costUsd } = sumRunUsage(readFileSync(path, \"utf8\"), st.model);\n    if (byModel.size === 0) continue;\n    const local = isLocalProvider(baseUrls[st.provider] ?? \"\");\n    const models = [...byModel.keys()];\n    // the run's cost is one number; book it on the run's own model, else the last one seen\n    const costModel = models.includes(st.model) ? st.model : models[models.length - 1];\n    for (const [model, tally] of byModel) {\n      const key = `${st.provider}\\u0000${model}`;\n      const row = groups.get(key) ?? { provider: st.provider, model, local, workers: 0, tally: emptyTally(), costUsd: local ? null : 0 };\n      row.workers += 1;\n      addTally(row.tally, tally);\n      if (!local && model === costModel) row.costUsd = (row.costUsd ?? 0) + (costUsd ?? 0);\n      groups.set(key, row);\n    }\n  }\n  return finishReport([...groups.values()].sort((a, b) => a.provider.localeCompare(b.provider) || a.model.localeCompare(b.model)));\n}\n\n// ---------------------------------------------------------------------------\n// Transcript side (tier 0): cost from a price table\n// ---------------------------------------------------------------------------\n\n/** USD per million tokens. Edit here when prices change; cache read 0.1x, write 5m 1.25x, write 1h 2x of input. */\nexport const PRICE_TABLE: Record<\"opus\" | \"sonnet\" | \"haiku\", { input: number; output: number }> = {\n  opus: { input: 5, output: 25 },\n  sonnet: { input: 3, output: 15 },\n  haiku: { input: 1, output: 5 },\n};\nexport const CACHE_READ_X = 0.1;\nexport const CACHE_WRITE_5M_X = 1.25;\nexport const CACHE_WRITE_1H_X = 2;\n\nexport function priceTableText(): string {\n  const lines = Object.entries(PRICE_TABLE).map(([f, p]) => `  ${f.padEnd(7)} input $${p.input}/M, output $${p.output}/M`);\n  return `Prices (USD per million tokens, matched on the model name):\\n${lines.join(\"\\n\")}\\n  cache read ${CACHE_READ_X}x input, cache write 5m ${CACHE_WRITE_5M_X}x, cache write 1h ${CACHE_WRITE_1H_X}x`;\n}\n\n/** Cost of a tally by model family, or null when the model matches no family. */\nexport function priceTally(model: string, t: Tally): number | null {\n  const fam = (Object.keys(PRICE_TABLE) as Array<keyof typeof PRICE_TABLE>).find((f) => model.toLowerCase().includes(f));\n  if (!fam) return null;\n  const p = PRICE_TABLE[fam];\n  const inp = p.input / 1e6;\n  return t.input * inp + t.output * (p.output / 1e6) + t.cacheRead * inp * CACHE_READ_X + t.cacheWrite5m * inp * CACHE_WRITE_5M_X + t.cacheWrite1h * inp * CACHE_WRITE_1H_X;\n}\n\nexport function transcriptUsage(path: string): UsageReport {\n  const { byModel } = sumUsage(readFileSync(path, \"utf8\"));\n  const rows: UsageRow[] = [...byModel.entries()]\n    .sort((a, b) => a[0].localeCompare(b[0]))\n    .map(([model, tally]) => ({ provider: \"transcript\", model, local: false, workers: 0, tally, costUsd: priceTally(model, tally) }));\n  const rep = finishReport(rows);\n  rep.cloud.provider = \"TOTAL\";\n  return rep;\n}\n\n// ---------------------------------------------------------------------------\n// Rendering\n// ---------------------------------------------------------------------------\n\nconst n = (x: number) => x.toLocaleString(\"en-US\");\nconst usd = (x: number | null) => (x === null ? \"—\" : x.toFixed(4));\n\nexport function renderUsage(rep: UsageReport, opts: { workers: boolean }): string {\n  const head = [\"PROVIDER\", \"MODEL\", ...(opts.workers ? [\"WORKERS\"] : []), \"INPUT\", \"CACHE READ\", \"CACHE WRITE 5m\", \"CACHE WRITE 1h\", \"OUTPUT\", \"COST USD\"];\n  const cells = (r: UsageRow) => [\n    r.provider + (r.local && !r.provider.startsWith(\"TOTAL\") ? \" (local)\" : \"\"),\n    r.model,\n    ...(opts.workers ? [String(r.workers)] : []),\n    n(r.tally.input),\n    n(r.tally.cacheRead),\n    n(r.tally.cacheWrite5m),\n    n(r.tally.cacheWrite1h),\n    n(r.tally.output),\n    r.local ? \"—\" : usd(r.costUsd),\n  ];\n  const body = [...rep.rows.map(cells)];\n  const totals = opts.workers ? [cells(rep.cloud), cells(rep.local)] : [cells(rep.cloud)];\n  const all = [head, ...body, ...totals];\n  const w = head.map((_, i) => Math.max(...all.map((r) => r[i].length)));\n  const textCols = 2;\n  const fmt = (r: string[]) => r.map((c, i) => (i < textCols ? c.padEnd(w[i]) : c.padStart(w[i]))).join(\"  \");\n  return [fmt(head), ...body.map(fmt), fmt(w.map((x) => \"-\".repeat(x))), ...totals.map(fmt)].join(\"\\n\");\n}\n\nexport function usageJson(rep: UsageReport): unknown {\n  const row = (r: UsageRow) => ({ provider: r.provider, model: r.model, local: r.local, workers: r.workers, ...r.tally, costUsd: r.costUsd });\n  return { rows: rep.rows.map(row), totalCloud: row(rep.cloud), totalLocal: row(rep.local) };\n}\n","/**\n * run-lock.ts — one plan or queue run at a time. The run writes a lock file\n * with its pid and start time and removes it on exit; a lock whose pid is dead\n * is taken over.\n */\n\nimport { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { pidAlive } from \"./status.js\";\n\nexport interface RunLock {\n  pid: number;\n  startedAt: number;\n}\n\nexport const planLockPath = (planPath: string): string => `${planPath}.lock`;\nexport const queueLockPath = (queueStatePath: string): string => `${queueStatePath}.lock`;\n\nconst hhmm = (ms: number): string => {\n  const d = new Date(ms);\n  return `${String(d.getHours()).padStart(2, \"0\")}:${String(d.getMinutes()).padStart(2, \"0\")}`;\n};\nexport const sinceText = (l: RunLock): string => `since ${hhmm(l.startedAt)} (pid ${l.pid})`;\n\nexport class RunLockedError extends Error {\n  constructor(readonly what: string, readonly lock: RunLock) {\n    super(`a run of ${what} is already in progress since ${hhmm(lock.startedAt)}`);\n  }\n}\n\n/** The lock of a live run, or null (no file, unreadable, or a dead pid). */\nexport function readRunLock(path: string, isAlive: (pid: number) => boolean = (p) => pidAlive(p)): RunLock | null {\n  if (!existsSync(path)) return null;\n  try {\n    const l = JSON.parse(readFileSync(path, \"utf8\")) as RunLock;\n    return Number.isInteger(l.pid) && l.pid > 0 && typeof l.startedAt === \"number\" && isAlive(l.pid) ? l : null;\n  } catch {\n    return null;\n  }\n}\n\nexport interface LockDeps {\n  pid?: number;\n  now?: () => number;\n  isAlive?: (pid: number) => boolean;\n  /** Runs on SIGTERM/SIGINT before the lock is released and the process exits (stop workers, write the run-end). */\n  onSignal?: (sig: NodeJS.Signals) => Promise<void>;\n  /** Exit hook; tests replace process.exit. */\n  exit?: (code: number) => void;\n}\n\n/** Run `fn` holding the lock at `path`; refuses when a live run holds it. `what` names the run in the message. */\nexport async function withRunLock<T>(path: string | undefined, what: string, fn: () => Promise<T>, deps: LockDeps = {}): Promise<T> {\n  if (!path) return fn();\n  const pid = deps.pid ?? process.pid;\n  const held = readRunLock(path, deps.isAlive);\n  if (held && held.pid !== pid) throw new RunLockedError(what, held);\n  mkdirSync(dirname(path), { recursive: true });\n  writeFileSync(path, JSON.stringify({ pid, startedAt: (deps.now ?? Date.now)() } satisfies RunLock), \"utf8\");\n  const release = (): void => {\n    try {\n      const l = JSON.parse(readFileSync(path, \"utf8\")) as RunLock;\n      if (l.pid === pid) unlinkSync(path);\n    } catch {\n      /* already gone */\n    }\n  };\n  let signalled = false;\n  const onSignal = (sig: NodeJS.Signals): void => {\n    if (signalled) return;\n    signalled = true;\n    void (async () => {\n      try {\n        await deps.onSignal?.(sig);\n      } catch {\n        /* the exit must happen anyway */\n      }\n      release();\n      (deps.exit ?? process.exit)(128 + (sig === \"SIGTERM\" ? 15 : 2));\n    })();\n  };\n  process.on(\"SIGTERM\", onSignal);\n  process.on(\"SIGINT\", onSignal);\n  try {\n    return await fn();\n  } finally {\n    process.off(\"SIGTERM\", onSignal);\n    process.off(\"SIGINT\", onSignal);\n    release();\n  }\n}\n","/**\n * plan.ts — the plan file of `pai plan run`: parse, validate, compose specs.\n *\n * A plan is YAML (see docs/plan-runner.md). Pure functions only; reading the\n * file and the spec files is the caller's job except `loadPlan`, which does\n * both and resolves relative paths against the plan's directory.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, isAbsolute, resolve } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\n\nexport interface PlanPart {\n  id: string;\n  unit: string;\n  /** Spec text, preamble(s) already prepended. */\n  spec: string;\n  files: string[];\n  proof?: string;\n  dependsOn: string[];\n  risky: boolean;\n}\n\nexport interface PlanUnit {\n  id: string;\n  unitCheck?: string;\n  parts: PlanPart[];\n}\n\nexport interface Plan {\n  job: string;\n  repo: string;\n  gate: string;\n  provider: string;\n  /** Explicit max_parallel; undefined = the provider's maxConcurrent. */\n  maxParallel?: number;\n  units: PlanUnit[];\n  /** Non-fatal findings of parsePlan, shown by `pai plan validate`. */\n  warnings: string[];\n}\n\n/** JSON-schema-like description of the plan file; `pai plan validate` enforces it. */\nexport const PLAN_SCHEMA = {\n  type: \"object\",\n  required: [\"job\", \"repo\", \"gate\", \"provider\", \"units\"],\n  properties: {\n    job: \"string — job name, the prefix of every worker label\",\n    repo: \"string — path of the git checkout the workers change (relative to the plan file)\",\n    gate: \"string — shell command run on the merged tree; a failure reverts the merge\",\n    provider: \"string — local provider the parts run on (--class implement)\",\n    max_parallel: \"integer >= 1 — parts running at once (default: the provider's maxConcurrent, else 3)\",\n    preamble: \"string — text or file path prepended to every part spec\",\n    units: {\n      type: \"array\",\n      minItems: 1,\n      items: {\n        required: [\"id\", \"parts\"],\n        properties: {\n          id: \"string — unit name\",\n          preamble: \"string — text or file path prepended to this unit's part specs (after the plan preamble)\",\n          unit_check: \"string — command run after the unit's last part merged; failure = needs-decision\",\n          parts: {\n            type: \"array\",\n            minItems: 1,\n            items: {\n              required: [\"id\", \"spec\"],\n              properties: {\n                id: \"string — unique in the whole plan\",\n                spec: \"string — task text, or a path to a file holding it\",\n                files: \"string[] — paths the part touches; parts sharing a file never run together\",\n                proof: \"string — command the worker must run and show passing\",\n                depends_on: \"string[] — part ids (any unit) that must be merged first\",\n                risky: \"boolean — documented intent for review; shown in the schedule\",\n              },\n            },\n          },\n        },\n      },\n    },\n  },\n} as const;\n\nexport class PlanError extends Error {\n  constructor(readonly problems: string[]) {\n    super(problems.join(\"\\n\"));\n  }\n}\n\ntype Obj = Record<string, unknown>;\nconst isObj = (v: unknown): v is Obj => typeof v === \"object\" && v !== null && !Array.isArray(v);\n\n/** `text` as given, or the content of the file it names (single line naming an existing file). */\nfunction textOrFile(value: string, baseDir: string): string {\n  const v = value.trim();\n  if (v && !v.includes(\"\\n\")) {\n    const p = isAbsolute(v) ? v : resolve(baseDir, v);\n    if (existsSync(p)) {\n      try {\n        return readFileSync(p, \"utf8\").trim();\n      } catch {\n        /* a directory or unreadable file: keep the text */\n      }\n    }\n  }\n  return v;\n}\n\n/** A spec value that looks like a path (no spaces, has an extension or slash) but names no file. */\nfunction missingFile(value: string, baseDir: string): boolean {\n  const v = value.trim();\n  if (!v || /\\s/.test(v)) return false;\n  if (!/[\\\\/]|\\.(md|txt|spec)$/.test(v)) return false;\n  return !existsSync(isAbsolute(v) ? v : resolve(baseDir, v));\n}\n\nfunction strList(v: unknown, where: string, problems: string[]): string[] {\n  if (v === undefined || v === null) return [];\n  if (!Array.isArray(v) || v.some((x) => typeof x !== \"string\" || !x)) {\n    problems.push(`${where}: must be a list of non-empty strings`);\n    return [];\n  }\n  return v as string[];\n}\n\n/** Parse and validate plan text. Throws PlanError listing every problem. */\nexport function parsePlan(text: string, baseDir: string): Plan {\n  const problems: string[] = [];\n  let raw: unknown;\n  try {\n    raw = parseYaml(text);\n  } catch (e) {\n    throw new PlanError([`not valid YAML: ${e instanceof Error ? e.message : String(e)}`]);\n  }\n  if (!isObj(raw)) throw new PlanError([\"the plan must be a YAML mapping\"]);\n  const reqStr = (o: Obj, k: string, where: string): string => {\n    const v = o[k];\n    if (typeof v !== \"string\" || !v.trim()) {\n      problems.push(`${where}${k}: required, a non-empty string`);\n      return \"\";\n    }\n    return v.trim();\n  };\n  const job = reqStr(raw, \"job\", \"\");\n  const repo = reqStr(raw, \"repo\", \"\");\n  const gate = reqStr(raw, \"gate\", \"\");\n  const provider = reqStr(raw, \"provider\", \"\");\n  let maxParallel: number | undefined;\n  if (raw.max_parallel !== undefined) {\n    if (typeof raw.max_parallel !== \"number\" || !Number.isInteger(raw.max_parallel) || raw.max_parallel < 1) {\n      problems.push(\"max_parallel: must be an integer >= 1\");\n    } else maxParallel = raw.max_parallel;\n  }\n  const planPre = typeof raw.preamble === \"string\" ? raw.preamble : undefined;\n  if (raw.preamble !== undefined && planPre === undefined) problems.push(\"preamble: must be a string\");\n  if (planPre && missingFile(planPre, baseDir)) problems.push(`preamble: file not found: ${planPre}`);\n\n  const units: PlanUnit[] = [];\n  const seen = new Map<string, string>();\n  if (!Array.isArray(raw.units) || raw.units.length === 0) problems.push(\"units: required, a non-empty list\");\n  else {\n    raw.units.forEach((u, ui) => {\n      const uw = `units[${ui}].`;\n      if (!isObj(u)) return void problems.push(`units[${ui}]: must be a mapping`);\n      const uid = reqStr(u, \"id\", uw);\n      const unitPre = typeof u.preamble === \"string\" ? u.preamble : undefined;\n      if (u.preamble !== undefined && unitPre === undefined) problems.push(`${uw}preamble: must be a string`);\n      if (unitPre && missingFile(unitPre, baseDir)) problems.push(`${uw}preamble: file not found: ${unitPre}`);\n      if (u.unit_check !== undefined && (typeof u.unit_check !== \"string\" || !u.unit_check.trim())) problems.push(`${uw}unit_check: must be a non-empty string`);\n      const parts: PlanPart[] = [];\n      if (!Array.isArray(u.parts) || u.parts.length === 0) problems.push(`${uw}parts: required, a non-empty list`);\n      else {\n        u.parts.forEach((p, pi) => {\n          const pw = `${uw}parts[${pi}].`;\n          if (!isObj(p)) return void problems.push(`${uw}parts[${pi}]: must be a mapping`);\n          const id = reqStr(p, \"id\", pw);\n          const spec = reqStr(p, \"spec\", pw);\n          if (spec && missingFile(spec, baseDir)) problems.push(`${pw}spec: file not found: ${spec}`);\n          if (id) {\n            if (seen.has(id)) problems.push(`${pw}id: duplicate part id \"${id}\" (also in unit ${seen.get(id)})`);\n            else seen.set(id, uid);\n          }\n          if (p.proof !== undefined && typeof p.proof !== \"string\") problems.push(`${pw}proof: must be a string`);\n          if (p.risky !== undefined && typeof p.risky !== \"boolean\") problems.push(`${pw}risky: must be a boolean`);\n          const pieces = [planPre, unitPre, spec].filter((x): x is string => !!x).map((x) => textOrFile(x, baseDir));\n          parts.push({\n            id,\n            unit: uid,\n            spec: pieces.join(\"\\n\\n\"),\n            files: strList(p.files, `${pw}files`, problems),\n            ...(typeof p.proof === \"string\" && p.proof.trim() ? { proof: p.proof.trim() } : {}),\n            dependsOn: strList(p.depends_on, `${pw}depends_on`, problems),\n            risky: p.risky === true,\n          });\n        });\n      }\n      units.push({ id: uid, ...(typeof u.unit_check === \"string\" && u.unit_check.trim() ? { unitCheck: u.unit_check.trim() } : {}), parts });\n    });\n  }\n  const unitIds = units.map((u) => u.id).filter(Boolean);\n  unitIds.forEach((id, i) => {\n    if (unitIds.indexOf(id) !== i) problems.push(`units: duplicate unit id \"${id}\"`);\n  });\n  const all = units.flatMap((u) => u.parts);\n  for (const p of all) {\n    for (const d of p.dependsOn) {\n      if (d === p.id) problems.push(`part ${p.id}: depends on itself`);\n      else if (!seen.has(d)) problems.push(`part ${p.id}: depends_on unknown part \"${d}\"`);\n    }\n  }\n  const cycle = findCycle(all);\n  if (cycle) problems.push(`dependency cycle: ${cycle.join(\" -> \")}`);\n  if (problems.length) throw new PlanError([...new Set(problems)]);\n  const repoAbs = isAbsolute(repo) ? repo : resolve(baseDir, repo);\n  const warnings: string[] = [];\n  for (const p of all) {\n    if (mentionsRepoPath(p.spec, repoAbs)) warnings.push(`part ${p.id}: spec names an absolute path into the repo (${repoAbs}); it is rewritten to a relative path, workers must stay in their worktree`);\n    if (p.files.some((f) => mentionsRepoPath(f, repoAbs))) warnings.push(`part ${p.id}: files lists an absolute path into the repo; use paths relative to the repo`);\n    if (p.proof && mentionsRepoPath(p.proof, repoAbs)) warnings.push(`part ${p.id}: proof names an absolute path into the repo; it is rewritten to a relative path`);\n    p.files = p.files.map((f) => stripRepoPaths(f, repoAbs));\n  }\n  return { job, repo: repoAbs, gate, provider, ...(maxParallel ? { maxParallel } : {}), units, warnings };\n}\n\nfunction findCycle(parts: PlanPart[]): string[] | null {\n  const byId = new Map(parts.map((p) => [p.id, p]));\n  const state = new Map<string, 1 | 2>();\n  const stack: string[] = [];\n  const visit = (id: string): string[] | null => {\n    if (state.get(id) === 2) return null;\n    if (state.get(id) === 1) return [...stack.slice(stack.indexOf(id)), id];\n    state.set(id, 1);\n    stack.push(id);\n    for (const d of byId.get(id)?.dependsOn ?? []) {\n      if (!byId.has(d)) continue;\n      const c = visit(d);\n      if (c) return c;\n    }\n    stack.pop();\n    state.set(id, 2);\n    return null;\n  };\n  for (const p of parts) {\n    const c = visit(p.id);\n    if (c) return c;\n  }\n  return null;\n}\n\n/** Read and validate the plan file at `path`. */\nexport function loadPlan(path: string): Plan {\n  let text: string;\n  try {\n    text = readFileSync(path, \"utf8\");\n  } catch (e) {\n    throw new PlanError([`cannot read ${path}: ${e instanceof Error ? e.message : String(e)}`]);\n  }\n  return parsePlan(text, dirname(resolve(path)));\n}\n\n/** Where the run log of a plan lives. */\nexport const runLogPath = (planPath: string): string => `${planPath}.run.jsonl`;\n\n/** Replace absolute paths into the plan's repo by relative ones. */\nexport function stripRepoPaths(text: string, repo: string): string {\n  const r = repo.replace(/\\/+$/, \"\");\n  if (!r) return text;\n  const esc = r.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n  return text.replace(new RegExp(`${esc}/`, \"g\"), \"\").replace(new RegExp(`${esc}(?![\\\\w.-])`, \"g\"), \".\");\n}\n\n/** Whether `text` names an absolute path inside `repo`. */\nexport function mentionsRepoPath(text: string, repo: string): boolean {\n  const r = repo.replace(/\\/+$/, \"\");\n  return !!r && r !== \"/\" && stripRepoPaths(text, r) !== text;\n}\n\n/** Fixed footer of every composed spec: keeps the worker in its worktree and makes it commit. */\nexport function specFooter(part: PlanPart, job: string): string {\n  return [\n    \"---\",\n    \"Rules for this task:\",\n    \"- Work only with RELATIVE paths inside the current working directory. It is your own git worktree; never use an absolute path to the repository, or you edit the main checkout instead.\",\n    `- Git add the files you changed, then commit on the current branch before you report, with the message \"${job}: ${part.unit} ${part.id}\". An empty commit is not a commit; uncommitted work is lost.`,\n    \"- Report with an R message.\",\n  ].join(\"\\n\");\n}\n\n/** The worker task: the part spec, its file list and proof, the fixed footer, and (on a retry) the failure tail. */\nexport function composeSpec(part: PlanPart, failure: string | undefined, job: string, repo?: string): string {\n  const clean = (t: string) => (repo ? stripRepoPaths(t, repo) : t);\n  const lines = [clean(part.spec)];\n  if (part.files.length) lines.push(\"\", `Files this part touches: ${part.files.map(clean).join(\", \")}`);\n  if (part.proof) lines.push(\"\", `Proof required: run \\`${clean(part.proof)}\\` and show it passing.`);\n  if (failure) lines.push(\"\", \"The previous attempt failed. Its failure output (tail):\", \"```\", failure.trim(), \"```\", \"Fix the cause and try again.\");\n  lines.push(\"\", specFooter(part, job));\n  return lines.join(\"\\n\");\n}\n\n/** Dirty paths (from `git status --porcelain`) that a part of the plan touches. */\nexport function dirtyConflicts(plan: Plan, dirty: string[]): string[] {\n  const files = plan.units.flatMap((u) => u.parts.flatMap((p) => p.files));\n  return dirty.filter((d) => filesOverlap([d], files));\n}\n\n/** Two file lists collide when they share a path or one names a directory containing the other. */\nexport function filesOverlap(a: string[], b: string[]): boolean {\n  const norm = (f: string) => f.replace(/^\\.\\//, \"\").replace(/\\/+$/, \"\");\n  for (const x of a.map(norm))\n    for (const y of b.map(norm)) if (x === y || x.startsWith(y + \"/\") || y.startsWith(x + \"/\")) return true;\n  return false;\n}\n","/**\n * plan-runner.ts — the scheduler behind `pai plan run`. No model involved.\n *\n * Keeps up to N parts running, starts a part once its dependencies are merged\n * and none of its files is in use by a running part, merges each finished part\n * with the plan gate, and walks the failure ladder: one local retry with the\n * failure tail, then needs-decision (or one Sonnet worker with --escalate).\n * Everything that touches workers, git or the clock goes through RunnerDeps.\n */\n\nimport { withRunLock, type LockDeps } from \"./run-lock.js\";\nimport { appendFileSync, existsSync, readFileSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { composeSpec, filesOverlap, type Plan, type PlanPart } from \"./plan.js\";\n\nexport interface WorkerOutcome {\n  id: string;\n  /** Worker ended with a valid report whose result is \"+\". */\n  ok: boolean;\n  /** Failure text (report why, open items, or the run's last output) when !ok. */\n  failure?: string;\n  tokens?: number | null;\n  /** The part must not be retried (e.g. the worker had no worktree); it goes straight to needs-decision. */\n  fatal?: boolean;\n  /** `pai worker run` refused or failed before any worker existed (pane/gate/config): an environment error, never retried. */\n  spawnRefused?: boolean;\n  /** The loop guard stopped the worker: a failed attempt (retry ladder), never a pass. */\n  loopStopped?: boolean;\n  /** The worker's worktree, when it has one. */\n  worktreeDir?: string;\n  /** The worker's final message (its R report). */\n  report?: string;\n}\n\nexport interface StartRequest {\n  part: PlanPart;\n  label: string;\n  spec: string;\n  provider: string;\n  /** \"local\" runs on plan.provider; \"sonnet\" is the escalation. */\n  tier: \"local\" | \"sonnet\";\n  attempt: number;\n  /** Model for a local-tier worker (`pai worker run --model`); the sonnet tier names its own. */\n  model?: string;\n  /** \"front\": the worker goes ahead of the provider's waiting runs (`--now`). */\n  priority?: \"front\";\n}\n\nexport interface MergeOutcome {\n  ok: boolean;\n  commit?: string;\n  /** HEAD before the merge; a merge that leaves HEAD here changed nothing. */\n  before?: string;\n  /** The worker branch carried no commit, so nothing was merged. */\n  noCommit?: boolean;\n  output: string;\n}\n\nexport interface RunnerDeps {\n  startWorker(req: StartRequest): Promise<WorkerOutcome>;\n  merge(workerId: string, gate: string): Promise<MergeOutcome>;\n  unitCheck(cmd: string): Promise<{ ok: boolean; output: string }>;\n  now(): number;\n  /** The provider a plan/queue value names: `local` becomes the running local server, any other name is returned unchanged. */\n  resolveLocal(provider: string): Promise<string>;\n  log(entry: RunLogEntry): void;\n  /** Stop the workers this runner has started (SIGTERM/SIGINT path); resolves once they are told to end. */\n  stopActive?(): Promise<void>;\n}\n\nexport interface RunLogEntry {\n  ts?: string;\n  event: \"run-start\" | \"run-end\" | \"unit-done\" | \"part-start\" | \"part-end\" | \"merge\" | \"escalate\" | \"needs-decision\" | \"unit-check\";\n  part?: string;\n  unit?: string;\n  worker?: string;\n  attempt?: number;\n  tier?: string;\n  ok?: boolean;\n  /** \"no-commit\" when the worker branch held no commit; the merge counts as not done. */\n  status?: string;\n  gate?: string;\n  commit?: string;\n  tokens?: number | null;\n  note?: string;\n}\n\nexport type PartState = \"waiting\" | \"running\" | \"merged\" | \"needs-decision\";\n\nexport interface RunSummary {\n  merged: string[];\n  needsDecision: string[];\n  /** Waiting parts that can never start because a dependency needs a decision. */\n  blocked: string[];\n  unitFailures: string[];\n  /** Parts are waiting, nothing runs and nothing can start: `blockedOn` lists the needs-decision parts and failed units. */\n  stuck: boolean;\n  blockedOn: string[];\n  escalations: number;\n  /** The refusal that stopped scheduling (repeated identically), printed once. */\n  spawnRefusal?: string;\n  /** The run ended on a stop request (marker or signal); `interrupted` lists parts that were in flight. */\n  stopped?: boolean;\n  interrupted?: string[];\n}\n\nexport interface RunOptions {\n  parallel: number;\n  escalate?: boolean;\n  /** Model every local-tier worker of the run gets (default: the provider's). */\n  model?: string;\n  /** \"front\": every worker of the run goes ahead of the provider's waiting runs. */\n  priority?: \"front\";\n  /** Part ids already merged (from the log). */\n  merged?: ReadonlySet<string>;\n  /** Unit ids whose unit_check already passed. */\n  unitsChecked?: ReadonlySet<string>;\n  /** Lock file held for the duration of the run (one run per plan). */\n  lockPath?: string;\n  /** Stop marker (`pai plan stop`): checked before each new part; the run ends \"stopped\" once in-flight parts finish. */\n  stopPath?: string;\n  /** Lock/signal hooks, replaced by tests. */\n  lockDeps?: LockDeps;\n}\n\nexport const planStopPath = (planPath: string): string => `${planPath}.stop`;\n\nexport function requestPlanStop(planPath: string): void {\n  writeFileSync(planStopPath(planPath), new Date().toISOString(), \"utf8\");\n}\n\nconst TAIL_LINES = 40;\nexport const tail = (text: string, n = TAIL_LINES): string => text.trim().split(\"\\n\").slice(-n).join(\"\\n\");\n\n/** Parts startable now: waiting, dependencies merged, no file clash with `busy` or each other, up to `slots`. */\nexport function pickStartable(\n  parts: PlanPart[],\n  state: ReadonlyMap<string, PartState>,\n  busy: PlanPart[],\n  slots: number,\n): PlanPart[] {\n  const picked: PlanPart[] = [];\n  const active = [...busy];\n  for (const p of parts) {\n    if (picked.length >= slots) break;\n    if (state.get(p.id) !== \"waiting\") continue;\n    if (!p.dependsOn.every((d) => state.get(d) === \"merged\")) continue;\n    if (active.some((a) => filesOverlap(a.files, p.files))) continue;\n    picked.push(p);\n    active.push(p);\n  }\n  return picked;\n}\n\nexport function runPlan(plan: Plan, opts: RunOptions, deps: RunnerDeps): Promise<RunSummary> {\n  const running = new Map<string, PlanPart>();\n  let aborted = false;\n  // once a signal arrived the killed workers' failures must not be logged, retried or merged: the parts restart on the next run\n  const guarded: RunnerDeps = {\n    ...deps,\n    log: (e) => {\n      if (!aborted) deps.log(e);\n    },\n    startWorker: (req) => (aborted ? new Promise<WorkerOutcome>(() => undefined) : deps.startWorker(req).then((o) => (aborted ? new Promise<WorkerOutcome>(() => undefined) : o))),\n  };\n  const onSignal = async (): Promise<void> => {\n    aborted = true;\n    const interrupted = [...running.keys()];\n    await deps.stopActive?.();\n    deps.log({ event: \"run-end\", ok: false, status: \"stopped\", note: `interrupted=${interrupted.join(\",\") || \"none\"}` });\n  };\n  return withRunLock(opts.lockPath, `plan ${plan.job}`, () => runPlanLocked(plan, opts, guarded, running), { ...opts.lockDeps, onSignal });\n}\n\nasync function runPlanLocked(plan: Plan, opts: RunOptions, deps: RunnerDeps, active: Map<string, PlanPart>): Promise<RunSummary> {\n  // `provider: local` in a plan means resolveLocalProvider() at run start —\n  // the loopback server that answers, never a provider picked by name.\n  plan = { ...plan, provider: await deps.resolveLocal(plan.provider) };\n  const parts = plan.units.flatMap((u) => u.parts);\n  const state = new Map<string, PartState>(parts.map((p) => [p.id, opts.merged?.has(p.id) ? \"merged\" : \"waiting\"]));\n  const checked = new Set(opts.unitsChecked ?? []);\n  const unitFailures: string[] = [];\n  const failedParts = new Set<string>();\n  let escalations = 0;\n  const refusals = new Map<string, number>();\n  let haltedBy: string | undefined;\n  const running = new Map<string, { part: PlanPart; done: Promise<void> }>();\n  let stopping = false;\n  const stopRequested = (): boolean => !!opts.stopPath && existsSync(opts.stopPath);\n  if (opts.stopPath) {\n    try {\n      unlinkSync(opts.stopPath); // a marker left from before this run is stale\n    } catch {\n      /* none */\n    }\n  }\n  // merges and unit checks touch the checkout: one at a time\n  let lock: Promise<unknown> = Promise.resolve();\n  const exclusive = <T>(fn: () => Promise<T>): Promise<T> => {\n    const r = lock.then(fn, fn);\n    lock = r.catch(() => undefined);\n    return r;\n  };\n\n  const label = (p: PlanPart) => `${plan.job}: ${p.unit} ${p.id}`;\n\n  const checkUnit = async (unitId: string): Promise<void> => {\n    const unit = plan.units.find((u) => u.id === unitId)!;\n    if (checked.has(unitId) || !unit.parts.every((p) => state.get(p.id) === \"merged\")) return;\n    checked.add(unitId);\n    if (!unit.unitCheck) {\n      deps.log({ event: \"unit-done\", unit: unitId });\n      return;\n    }\n    const r = await exclusive(() => deps.unitCheck(unit.unitCheck!));\n    deps.log({ event: \"unit-check\", unit: unitId, ok: r.ok, note: r.ok ? undefined : tail(r.output, 10) });\n    if (r.ok) deps.log({ event: \"unit-done\", unit: unitId });\n    if (!r.ok) {\n      unitFailures.push(unitId);\n      // parts that depend on a unit whose check failed wait for a decision\n      for (const up of unit.parts) failedParts.add(up.id);\n      deps.log({ event: \"needs-decision\", unit: unitId, note: `unit_check failed: ${tail(r.output, 10)}` });\n    }\n  };\n\n  const attemptPart = async (p: PlanPart): Promise<void> => {\n    const ladder: Array<{ tier: \"local\" | \"sonnet\"; provider: string }> = [\n      { tier: \"local\", provider: plan.provider },\n      { tier: \"local\", provider: plan.provider },\n      ...(opts.escalate ? [{ tier: \"sonnet\" as const, provider: \"anthropic\" }] : []),\n    ];\n    let failure: string | undefined;\n    for (let i = 0; i < ladder.length; i++) {\n      const { tier, provider } = ladder[i];\n      if (tier === \"sonnet\") {\n        escalations++;\n        deps.log({ event: \"escalate\", part: p.id, unit: p.unit, attempt: i + 1, tier, note: tail(failure ?? \"\", 10) });\n      }\n      deps.log({ event: \"part-start\", part: p.id, unit: p.unit, attempt: i + 1, tier });\n      const out = await deps.startWorker({ part: p, label: label(p), spec: composeSpec(p, failure, plan.job, plan.repo), provider, tier, attempt: i + 1, ...(tier === \"local\" && opts.model ? { model: opts.model } : {}), ...(opts.priority ? { priority: opts.priority } : {}) });\n      deps.log({ event: \"part-end\", part: p.id, unit: p.unit, worker: out.id, attempt: i + 1, tier, ok: out.ok, ...(out.loopStopped ? { reason: \"loop\" } : {}), tokens: out.tokens ?? null, note: out.ok ? undefined : tail(out.failure ?? \"\", 10) });\n      if (!out.ok && out.spawnRefused) {\n        failure = out.failure || \"worker spawn refused\";\n        const n = (refusals.get(failure) ?? 0) + 1;\n        refusals.set(failure, n);\n        if (n >= 2) haltedBy = failure;\n        break;\n      }\n      if (!out.ok && out.fatal) {\n        failure = out.failure || \"the worker could not be isolated\";\n        break;\n      }\n      if (!out.ok) {\n        failure = out.failure || \"the worker ended without a valid passing report\";\n        continue;\n      }\n      let m = await exclusive(() => deps.merge(out.id, plan.gate));\n      // a \"merge\" that moved nothing is not a merge: the worker never committed\n      if (m.ok && (m.noCommit || !m.commit || m.commit === m.before)) m = { ...m, ok: false, noCommit: true };\n      deps.log({ event: \"merge\", part: p.id, unit: p.unit, worker: out.id, attempt: i + 1, ok: m.ok, ...(m.noCommit ? { status: \"no-commit\" } : {}), gate: plan.gate, ...(m.noCommit ? {} : { commit: m.commit }), note: m.ok ? undefined : tail(m.output, 10) });\n      if (m.ok) {\n        state.set(p.id, \"merged\");\n        await checkUnit(p.unit);\n        return;\n      }\n      failure = m.noCommit\n        ? `no-commit: the worker branch has no commit, nothing was merged. Git add the files you changed, then commit on the current branch (message \"${label(p)}\") and edit files only by relative path inside your worktree.${m.output.trim() ? `\\n${tail(m.output, 10)}` : \"\"}`\n        : `gate failed (${plan.gate}):\\n${tail(m.output)}`;\n    }\n    state.set(p.id, \"needs-decision\");\n    deps.log({ event: \"needs-decision\", part: p.id, unit: p.unit, note: tail(failure ?? \"\", 10) });\n  };\n\n  deps.log({ event: \"run-start\", note: `parallel=${opts.parallel}${opts.escalate ? \" escalate=sonnet\" : \"\"}` });\n  // a resumed run may have units complete but unchecked (killed between merge and check)\n  for (const u of plan.units) await checkUnit(u.id);\n  for (;;) {\n    const busy = [...running.values()].map((r) => r.part);\n    if (!stopping && stopRequested()) stopping = true;\n    for (const p of haltedBy || stopping ? [] : pickStartable(parts.filter((p) => !p.dependsOn.some((d) => failedParts.has(d))), state, busy, opts.parallel - running.size)) {\n      state.set(p.id, \"running\");\n      const done = attemptPart(p).finally(() => {\n        running.delete(p.id);\n        active.delete(p.id);\n      });\n      running.set(p.id, { part: p, done });\n      active.set(p.id, p);\n    }\n    if (running.size === 0) break;\n    await Promise.race([...running.values()].map((r) => r.done));\n  }\n  if (stopping && opts.stopPath) {\n    try {\n      unlinkSync(opts.stopPath);\n    } catch {\n      /* already gone */\n    }\n  }\n  const waiting = parts.filter((p) => state.get(p.id) === \"waiting\").map((p) => p.id);\n  const summary: RunSummary = {\n    merged: parts.filter((p) => state.get(p.id) === \"merged\").map((p) => p.id),\n    needsDecision: parts.filter((p) => state.get(p.id) === \"needs-decision\").map((p) => p.id),\n    blocked: waiting,\n    unitFailures,\n    stuck: !haltedBy && !stopping && waiting.length > 0,\n    blockedOn: [...parts.filter((p) => state.get(p.id) === \"needs-decision\").map((p) => p.id), ...unitFailures.map((u) => `unit ${u}`)],\n    escalations,\n    ...(haltedBy ? { spawnRefusal: haltedBy } : {}),\n    ...(stopping ? { stopped: true } : {}),\n  };\n  if (stopping) {\n    deps.log({ event: \"run-end\", ok: false, status: \"stopped\", note: `stop requested; merged=${summary.merged.length} waiting=${waiting.length}` });\n    return summary;\n  }\n  deps.log({ event: \"run-end\", ok: !summary.needsDecision.length && !waiting.length && !unitFailures.length, ...(summary.stuck ? { status: \"blocked\" } : {}), note: `merged=${summary.merged.length} needs-decision=${summary.needsDecision.length} blocked=${waiting.length}` });\n  return summary;\n}\n\n/** Exit code of `pai plan run`: 0 all merged, 4 stopped by `pai plan stop`, 1 failures with everything else done, 3 blocked (parts left that cannot start). */\nexport function runExitCode(s: RunSummary): number {\n  if (s.stopped) return 4;\n  if (s.stuck) return 3;\n  return s.needsDecision.length || s.blocked.length || s.unitFailures.length ? 1 : 0;\n}\n\nexport function blockedMessage(s: RunSummary, planPath: string): string {\n  return `blocked: ${s.blocked.length} parts wait on needs-decision items: ${s.blockedOn.join(\", \") || \"none\"}; fix and re-run \\`pai plan run ${planPath}\\` (merged parts are skipped)`;\n}\n\n/** The schedule a run would execute, assuming every part succeeds: waves of at most `parallel` parts. */\nexport function dryRunSchedule(plan: Plan, opts: RunOptions): PlanPart[][] {\n  const parts = plan.units.flatMap((u) => u.parts);\n  const state = new Map<string, PartState>(parts.map((p) => [p.id, opts.merged?.has(p.id) ? \"merged\" : \"waiting\"]));\n  const waves: PlanPart[][] = [];\n  for (;;) {\n    const wave = pickStartable(parts, state, [], opts.parallel);\n    if (!wave.length) break;\n    waves.push(wave);\n    for (const p of wave) state.set(p.id, \"merged\");\n  }\n  return waves;\n}\n\nexport function renderSchedule(plan: Plan, opts: RunOptions): string {\n  const waves = dryRunSchedule(plan, opts);\n  const lines = [`job ${plan.job}: ${plan.units.flatMap((u) => u.parts).length} parts, provider ${plan.provider}, ${opts.parallel} at a time, gate: ${plan.gate}`];\n  waves.forEach((w, i) => {\n    lines.push(`step ${i + 1}:`);\n    for (const p of w) lines.push(`  ${p.unit} ${p.id}${p.risky ? \" [risky]\" : \"\"}${p.dependsOn.length ? `  after ${p.dependsOn.join(\", \")}` : \"\"}${p.files.length ? `  files ${p.files.join(\", \")}` : \"\"}`);\n  });\n  const left = plan.units.flatMap((u) => u.parts).filter((p) => !opts.merged?.has(p.id) && !waves.flat().includes(p));\n  if (left.length) lines.push(`never scheduled: ${left.map((p) => p.id).join(\", \")}`);\n  for (const u of plan.units) if (u.unitCheck && !opts.unitsChecked?.has(u.id)) lines.push(`after unit ${u.id}: ${u.unitCheck}`);\n  if (opts.merged?.size) lines.push(`skipped (already merged): ${[...opts.merged].join(\", \")}`);\n  return lines.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// run log\n\nexport function readRunLog(path: string): RunLogEntry[] {\n  if (!existsSync(path)) return [];\n  const out: RunLogEntry[] = [];\n  for (const line of readFileSync(path, \"utf8\").split(\"\\n\")) {\n    if (!line.startsWith(\"{\")) continue;\n    try {\n      out.push(JSON.parse(line) as RunLogEntry);\n    } catch {\n      /* torn line */\n    }\n  }\n  return out;\n}\n\nexport function appendRunLog(path: string, entry: RunLogEntry, now: () => number = Date.now): void {\n  appendFileSync(path, JSON.stringify({ ts: new Date(now()).toISOString(), ...entry }) + \"\\n\", \"utf8\");\n}\n\n/** What a resumed run skips: merged parts and units whose check passed. */\nexport function resumeState(log: RunLogEntry[]): { merged: Set<string>; unitsChecked: Set<string> } {\n  const merged = new Set<string>();\n  const unitsChecked = new Set<string>();\n  for (const e of log) {\n    if (e.event === \"merge\" && e.ok && e.part) merged.add(e.part);\n    if (e.event === \"unit-check\" && e.ok && e.unit) unitsChecked.add(e.unit);\n  }\n  return { merged, unitsChecked };\n}\n\nexport interface PlanStatus {\n  done: string[];\n  running: string[];\n  waiting: string[];\n  needsDecision: string[];\n  tokens: number;\n  wallMs: number;\n}\n\n/** Summarise the log against the plan's parts. `now` closes an unfinished run segment. */\nexport function planStatus(plan: Plan, log: RunLogEntry[], now: number): PlanStatus {\n  const last = new Map<string, RunLogEntry>();\n  let tokens = 0;\n  let wallMs = 0;\n  let segStart: number | null = null;\n  let lastTs = 0;\n  for (const e of log) {\n    const t = e.ts ? Date.parse(e.ts) : 0;\n    lastTs = t || lastTs;\n    if (e.event === \"run-start\") segStart = t;\n    if (e.event === \"run-end\" && segStart !== null) {\n      wallMs += t - segStart;\n      segStart = null;\n    }\n    if (e.part && [\"part-start\", \"part-end\", \"merge\", \"needs-decision\"].includes(e.event)) last.set(e.part, e);\n    if (e.event === \"part-end\" && typeof e.tokens === \"number\") tokens += e.tokens;\n  }\n  // an open segment is a run in progress when the log is fresh, else a run that died: count up to its last entry\n  if (segStart !== null) wallMs += (now - lastTs < 120_000 ? now : lastTs) - segStart;\n  const s: PlanStatus = { done: [], running: [], waiting: [], needsDecision: [], tokens, wallMs };\n  const runActive = segStart !== null && now - lastTs < 120_000;\n  for (const p of plan.units.flatMap((u) => u.parts)) {\n    const e = last.get(p.id);\n    if (e?.event === \"merge\" && e.ok) s.done.push(p.id);\n    else if (e?.event === \"needs-decision\") s.needsDecision.push(p.id);\n    else if (e?.event === \"part-start\" && runActive) s.running.push(p.id);\n    else s.waiting.push(p.id);\n  }\n  return s;\n}\n\nexport function renderStatus(plan: Plan, st: PlanStatus): string {\n  const fmt = (ids: string[]) => (ids.length ? `${ids.length} (${ids.join(\", \")})` : \"0\");\n  const secs = Math.round(st.wallMs / 1000);\n  return [\n    `job ${plan.job}`,\n    `done           ${fmt(st.done)}`,\n    `running        ${fmt(st.running)}`,\n    `waiting        ${fmt(st.waiting)}`,\n    `needs-decision ${fmt(st.needsDecision)}`,\n    `wall so far    ${Math.floor(secs / 60)}m${String(secs % 60).padStart(2, \"0\")}s, tokens ${st.tokens}`,\n  ].join(\"\\n\");\n}\n","/**\n * plan-deps.ts — the real RunnerDeps of `pai plan run`: workers, merges and\n * checks are the existing `pai worker run` / `pai worker merge` verbs, run as\n * child processes of this same binary (PAI_BIN, else `pai`).\n */\n\nimport { spawn } from \"node:child_process\";\nimport { mkdtempSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { parseWorkerReport } from \"./report.js\";\nimport { eventsPath } from \"./paths.js\";\nimport { loadStatuses } from \"./status.js\";\nimport { killTree } from \"./kill-tree.js\";\nimport { sumRunUsage } from \"./usage.js\";\nimport { appendRunLog, tail, type MergeOutcome, type RunnerDeps, type StartRequest, type WorkerOutcome } from \"./plan-runner.js\";\nimport type { Plan } from \"./plan.js\";\nimport { resolveRunnerProvider } from \"./local-provider.js\";\n\nexport interface Captured {\n  code: number | null;\n  out: string;\n  err: string;\n}\n\nexport function capture(cmd: string, args: string[], cwd: string, shell = false): Promise<Captured> {\n  return new Promise((resolve) => {\n    const child = spawn(cmd, args, { cwd, stdio: [\"ignore\", \"pipe\", \"pipe\"], env: process.env, shell });\n    let out = \"\";\n    let err = \"\";\n    child.stdout.on(\"data\", (d) => (out += d));\n    child.stderr.on(\"data\", (d) => (err += d));\n    child.on(\"error\", (e) => resolve({ code: 1, out, err: err + e.message }));\n    child.on(\"close\", (code) => resolve({ code, out, err }));\n  });\n}\n\nexport const pai = (): string => process.env.PAI_BIN || \"pai\";\n\n/** Tokens a finished worker used, from its run log; null when unavailable. */\nfunction workerTokens(logDir: string, id: string): number | null {\n  try {\n    const sum = sumRunUsage(readFileSync(eventsPath(logDir, id), \"utf8\"));\n    let n = 0;\n    for (const t of sum.byModel.values()) n += t.input + t.cacheRead + t.cacheWrite5m + t.cacheWrite1h + t.output;\n    return n || null;\n  } catch {\n    return null;\n  }\n}\n\n/** Paths with uncommitted changes in the plan's repo (`git status --porcelain`). */\nexport async function dirtyPaths(repo: string): Promise<string[]> {\n  const r = await capture(\"git\", [\"status\", \"--porcelain\"], repo);\n  return r.out\n    .split(\"\\n\")\n    .filter(Boolean)\n    .map((l) => l.slice(3).replace(/^.* -> /, \"\").replace(/^\"|\"$/g, \"\"));\n}\n\n/** Args of the part worker: `--worktree` is explicit so the caller's own mode is never inherited. */\nexport function workerArgs(req: Pick<StartRequest, \"label\" | \"provider\" | \"tier\" | \"model\" | \"priority\">, specFile: string, repo: string): string[] {\n  const model = req.tier === \"sonnet\" ? \"sonnet\" : req.model;\n  return [\"worker\", \"run\", \"--provider\", req.provider, \"--class\", \"implement\", ...(model ? [\"--model\", model] : []), ...(req.priority ? [\"--now\"] : []), \"--label\", req.label, \"--spec\", specFile, \"--cwd\", repo, \"--worktree\", \"--output-format\", \"json\"];\n}\n\n/** State of the plan checkout: HEAD and the dirty-path listing. */\nexport interface CheckoutState {\n  head: string;\n  dirty: string;\n}\n\nexport async function checkoutState(repo: string): Promise<CheckoutState> {\n  const head = (await capture(\"git\", [\"rev-parse\", \"HEAD\"], repo)).out.trim();\n  const dirty = (await capture(\"git\", [\"status\", \"--porcelain\"], repo)).out;\n  return { head, dirty };\n}\n\n/** HEADs the runner's own merges produced, per repo: a moved HEAD that is one of them is not a worker edit. */\nconst mergedHeads = new Map<string, Set<string>>();\n\n/** Error text when the plan checkout changed during a part other than by the runner's merges; null when untouched. */\nexport function checkoutProblem(id: string, before: CheckoutState, after: CheckoutState, merged: ReadonlySet<string> = new Set()): string | null {\n  const headMoved = after.head !== before.head && !merged.has(after.head);\n  if (!headMoved && after.dirty === before.dirty) return null;\n  return `worker ${id} changed the plan's checkout (${headMoved ? `HEAD ${before.head.slice(0, 7)} -> ${after.head.slice(0, 7)}` : \"working tree\"})`;\n}\n\n/** Commits on worker/<id> beyond `base` that change something (empty commits do not count). */\nexport async function realCommitsAhead(repo: string, base: string, id: string): Promise<number> {\n  const revs = (await capture(\"git\", [\"rev-list\", \"--no-merges\", `${base}..worker/${id}`], repo)).out.split(\"\\n\").filter(Boolean);\n  let n = 0;\n  for (const sha of revs) if ((await capture(\"git\", [\"diff-tree\", \"--no-commit-id\", \"--name-only\", \"-r\", sha], repo)).out.trim()) n++;\n  return n;\n}\n\n/** Workers this process launched and is waiting on. */\nconst launched = new Set<{ label: string; t0: number }>();\n\n/** Stop every worker this process launched and still waits on, the way `pai worker kill` does (kill-tree). */\nexport async function stopLaunchedWorkers(logDir: string, kill: typeof killTree = killTree): Promise<string[]> {\n  const stopped: string[] = [];\n  for (const l of launched) {\n    for (const s of loadStatuses(logDir)) {\n      if (s.label !== l.label || (s.state !== \"running\" && s.state !== \"queued\") || Date.parse(s.started) < l.t0) continue;\n      try {\n        await kill(logDir, s.id);\n        stopped.push(s.id);\n      } catch {\n        /* already gone */\n      }\n    }\n  }\n  return stopped;\n}\n\n/** Run one worker as `pai worker run` and read its outcome: spawn refusal, plan-checkout and report checks included. */\nexport async function launchWorker(req: Pick<StartRequest, \"label\" | \"provider\" | \"tier\" | \"model\" | \"priority\">, specFile: string, repo: string, logDir: string): Promise<WorkerOutcome> {\n  const t0 = Date.now() - 1000;\n  const before = await checkoutState(repo);\n  const mark = { label: req.label, t0 };\n  launched.add(mark);\n  const r = await capture(pai(), workerArgs(req, specFile, repo), repo).finally(() => launched.delete(mark));\n  const st = loadStatuses(logDir)\n    .filter((s) => s.label === req.label && Date.parse(s.started) >= t0)\n    .sort((a, b) => b.started.localeCompare(a.started))[0];\n  if (!st) return { id: \"\", ok: false, spawnRefused: true, failure: tail(r.err || r.out) || `worker did not start (exit ${r.code})` };\n  const problem = checkoutProblem(st.id, before, await checkoutState(repo), mergedHeads.get(repo));\n  if (problem) return { id: st.id, ok: false, fatal: true, failure: problem };\n  let text = \"\";\n  try {\n    text = (JSON.parse(r.out) as { result?: string }).result ?? \"\";\n  } catch {\n    text = r.out;\n  }\n  const report = parseWorkerReport(text);\n  const passed = !!report && (report.result ? report.result === \"+\" : (report.checks ?? []).every((c) => c.ok !== false));\n  const ok = st.state === \"done\" && (st.rc ?? 0) === 0 && passed;\n  const failure = ok ? undefined : !report ? `worker ended without a valid report (${st.state}): ${tail(text || r.err, 15)}` : [report.why, ...(report.open ?? []), report.notes].filter(Boolean).join(\"\\n\") || `report result ${report.result ?? \"?\"}`;\n  return { id: st.id, ok, failure, ...(st.loopStopped ? { loopStopped: true } : {}), tokens: workerTokens(logDir, st.id), worktreeDir: st.worktreeDir ?? undefined, report: text };\n}\n\n/** Merge worker/<id> into `repo`'s checkout with `pai worker merge` (--verify when a gate is given); an empty branch is refused. */\nexport async function mergeBranch(repo: string, id: string, gate: string): Promise<MergeOutcome> {\n  const rev = async (...a: string[]) => (await capture(\"git\", a, repo)).out.trim();\n  const before = await rev(\"rev-parse\", \"HEAD\");\n  const ahead = await realCommitsAhead(repo, before, id);\n  if (!(ahead > 0)) return { ok: false, noCommit: true, before, output: `branch worker/${id} has no non-empty commit beyond ${before.slice(0, 7)}` };\n  const r = await capture(pai(), [\"worker\", \"merge\", id, ...(gate ? [\"--verify\", gate] : [])], repo);\n  const output = r.out + r.err;\n  if (r.code !== 0) return { ok: false, before, output };\n  const head = await rev(\"rev-parse\", \"HEAD\");\n  if (head) mergedHeads.set(repo, (mergedHeads.get(repo) ?? new Set()).add(head));\n  return { ok: true, commit: head || undefined, before, output };\n}\n\nexport function realRunnerDeps(plan: Plan, logDir: string, logPath: string): RunnerDeps {\n  const dir = mkdtempSync(join(tmpdir(), \"pai-plan-\"));\n  return {\n    now: Date.now,\n    log: (e) => appendRunLog(logPath, e),\n    async startWorker(req: StartRequest): Promise<WorkerOutcome> {\n      const specFile = join(dir, `${req.part.id}-${req.attempt}.txt`);\n      writeFileSync(specFile, req.spec, \"utf8\");\n      return launchWorker(req, specFile, plan.repo, logDir);\n    },\n    merge: (id: string, gate: string) => mergeBranch(plan.repo, id, gate),\n    resolveLocal: resolveRunnerProvider,\n    stopActive: async () => void (await stopLaunchedWorkers(logDir)),\n    async unitCheck(cmd: string) {\n      const r = await capture(cmd, [], plan.repo, true);\n      return { ok: r.code === 0, output: r.out + r.err };\n    },\n  };\n}\n","/**\n * run-report-wiring.ts — the CLI side of run reporting: who reports to whom,\n * and the argv a detached run is restarted with.\n */\n\nimport { aibrokerMessenger, detachRun, markRunDone, originFromEnv, type DetachDeps, type Messenger, type RunOrigin, type RunRecord } from \"./run-events.js\";\nimport { pai } from \"./plan-deps.js\";\n\n/** The origin worth reporting to: none when the caller is a bare shell with no session. */\nexport function reportOrigin(env: NodeJS.ProcessEnv = process.env): RunOrigin | null {\n  const o = originFromEnv(env);\n  return o.claudeSession || o.iterm || o.name ? o : null;\n}\n\nexport function runMessenger(logDir: string): Messenger {\n  return aibrokerMessenger(logDir);\n}\n\n/** A clean end of a detached run, so the daemon sweep does not call it dead. */\nexport function finishDetached(logDir: string, env: NodeJS.ProcessEnv = process.env): void {\n  if (env.PAI_RUN_ID) markRunDone(logDir, env.PAI_RUN_ID);\n}\n\n/** argv (after the binary) that re-runs a plan/queue run in the detached child. */\nexport function detachedArgv(group: \"plan\" | \"queue\", positional: string[], opts: Record<string, unknown>, skip: string[] = [\"detach\", \"dry-run\"]): string[] {\n  const argv: string[] = [group, \"run\", ...positional];\n  for (const [k, v] of Object.entries(opts)) {\n    if (skip.includes(k) || v === undefined || v === false) continue;\n    argv.push(`--${k}`);\n    if (v !== true) argv.push(String(v));\n  }\n  return argv;\n}\n\nexport interface DetachRequest {\n  kind: \"plan\" | \"queue\";\n  label: string;\n  /** Positional args of the `run` command (the plan path for a plan). */\n  positional: string[];\n  opts: Record<string, unknown>;\n  cwd: string;\n  origin: RunOrigin | null;\n}\n\n/** The one place a plan/queue run is handed to a detached process; the CLI --detach and the MCP tools both call it. */\nexport function startDetached(logDir: string, req: DetachRequest, deps?: DetachDeps): RunRecord {\n  return detachRun(logDir, req.kind, req.label, pai(), detachedArgv(req.kind, req.positional, req.opts), req.cwd, req.origin ?? {}, deps);\n}\n","/**\n * slim-profile.ts — what a headless worker loads of the operator's setup.\n *\n * A default `claude -p` run reads the user settings: ~/.claude/CLAUDE.md, the\n * enabled plugins' SessionStart context, every SessionStart/UserPromptSubmit\n * injection (Whispr, caveman, handover...), skills, output style. Measured\n * 2026-10-16 on a \"reply OK\" worker, roughly a third of the first request.\n * A worker needs none of it, only the PreToolUse guards and its contract.\n *\n * The slim profile drops the user setting source (`--setting-sources\n * project,local`) and passes a generated `--settings` file instead: the user's\n * env/permissions plus only the guard hooks. The project CLAUDE.md stays.\n * Opt out with PAI_WORKER_FULL_PROFILE=1 or by passing your own\n * --settings/--setting-sources.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport type { WorkerProvider } from \"./config.js\";\n\n/** Hook commands kept for a worker; everything else is context or bookkeeping. */\nconst GUARD_HOOKS = [\n  \"terminal_guard.py\",\n  \"route-agents-to-worker\",\n  \"block-taskoutput-wait\",\n  \"route-edits-to-worker\",\n  \"security-validator\",\n  \"ztk-auto.sh\",\n  \"caseleaf-warm-builds\",\n  \"block-sleep-poll\",\n  \"worker-guard\",\n  \"worker-path-repair\",\n  \"worker-edit-repair\",\n  \"worker-tool-name-repair\",\n  \"ab-levers\",\n];\n\n/** The text a worker needs in place of the user CLAUDE.md. */\nexport const WORKER_BRIEF = [\n  \"You are a headless worker: do the task in this process, then report.\",\n  \"- Commit or push only if the spec says so; no AI attribution, no --no-verify.\",\n  \"- Keep personal data (names, accounts, home paths) out of code, docs and commits.\",\n  \"- Stay in the working directory; do not touch other checkouts or the user's shell.\",\n  \"- Never sleep-poll: no sleep over 60 s; long jobs run detached and are checked with a bounded wait.\",\n  \"- No screen/osascript automation; no email or messaging.\",\n  \"- Nothing is done without proof: run the tests, show before/after.\",\n  \"- A hook denial is a rule, not a glitch: adjust, do not retry verbatim.\",\n  \"- End with the report format given in the system prompt.\",\n].join(\"\\n\");\n\n/**\n * The built PostToolUse hook that delivers `pai worker goal` notes: next to\n * this CLI's own dist/hooks (so a build under test delivers with its own\n * hook), else the installed one. null when neither exists.\n */\nexport function noteHookPath(from: string = fileURLToPath(import.meta.url), home: string = homedir()): string | null {\n  for (let dir = dirname(from), i = 0; i < 6; i++, dir = dirname(dir)) {\n    const p = join(dir, \"hooks\", \"worker-note.mjs\");\n    if (existsSync(p)) return p;\n  }\n  const installed = join(home, \".claude\", \"Hooks\", \"worker-note.mjs\");\n  return existsSync(installed) ? installed : null;\n}\n\nconst PROVIDER_KEYS = [\"ANTHROPIC_BASE_URL\", \"ANTHROPIC_AUTH_TOKEN\", \"ANTHROPIC_API_KEY\"];\n\ntype HookGroup = { matcher?: string; hooks?: Array<{ type?: string; command?: string }> };\n\n/**\n * Settings env outranks the process env, so the user's global tuning for the\n * first-party API must not shadow a non-anthropic provider: its own output\n * cap wins (none set: the user's is dropped), the first-party-base-url flag\n * goes, and thinking is switched off (no `thinking`, no effort in the request)\n * unless the provider asks for it.\n */\nfunction applyProviderEnv(e: Record<string, unknown>, provider: WorkerProvider): void {\n  const cap = provider.env.CLAUDE_CODE_MAX_OUTPUT_TOKENS;\n  if (cap !== undefined) e.CLAUDE_CODE_MAX_OUTPUT_TOKENS = cap;\n  else delete e.CLAUDE_CODE_MAX_OUTPUT_TOKENS;\n  delete e._CLAUDE_CODE_ASSUME_FIRST_PARTY_BASE_URL;\n  if (!provider.thinking) {\n    e.CLAUDE_CODE_DISABLE_THINKING = \"1\";\n    e.CLAUDE_CODE_EFFORT_LEVEL = \"unset\";\n  }\n}\n\n/** The user settings reduced to env, permissions and the guard hooks. */\nexport function slimSettings(\n  user: Record<string, unknown>,\n  procEnv: NodeJS.ProcessEnv = {},\n  provider?: WorkerProvider,\n  noteHook?: string,\n): Record<string, unknown> {\n  const out: Record<string, unknown> = {};\n  for (const k of [\"env\", \"permissions\", \"model\"]) if (user[k] !== undefined) out[k] = user[k];\n  // Settings env overrides the process env, so a provider's endpoint and token\n  // (set by the spawner) must not be shadowed by the user's own.\n  const nonNative = provider !== undefined && !provider.native;\n  if ((out.env && typeof out.env === \"object\") || nonNative) {\n    const e = { ...((out.env ?? {}) as Record<string, unknown>) };\n    for (const k of PROVIDER_KEYS) if (procEnv[k]) delete e[k];\n    if (provider && nonNative) applyProviderEnv(e, provider);\n    out.env = e;\n  }\n  const hooks: Record<string, HookGroup[]> = {};\n  for (const [event, groups] of Object.entries((user.hooks ?? {}) as Record<string, HookGroup[]>)) {\n    const kept = groups\n      .map((g) => ({ ...g, hooks: (g.hooks ?? []).filter((h) => GUARD_HOOKS.some((n) => h.command?.includes(n))) }))\n      .filter((g) => g.hooks.length > 0);\n    if (kept.length) hooks[event] = kept;\n  }\n  // Not a user hook: the worker's own channel for `pai worker goal` notes, for every provider.\n  if (noteHook) (hooks.PostToolUse ??= []).push({ matcher: \"*\", hooks: [{ type: \"command\", command: noteHook }] });\n  out.hooks = hooks;\n  // Empty strings switch off Claude Code's Co-Authored-By / \"Generated with\" lines.\n  out.attribution = { commit: \"\", pr: \"\" };\n  return out;\n}\n\nfunction noteHookCommand(logDir: string): string | undefined {\n  const hook = noteHookPath();\n  return hook ? `node \"${hook}\" \"${logDir}\"` : undefined;\n}\n\n/**\n * Args for the slim profile, or [] when it does not apply (caller brought\n * their own settings, opted out, or there is no user settings file to slim).\n */\nexport function slimProfileArgs(\n  logDir: string,\n  wid: string,\n  rest: string[],\n  env: NodeJS.ProcessEnv = process.env,\n  userSettingsPath = join(homedir(), \".claude\", \"settings.json\"),\n  provider?: WorkerProvider,\n): string[] {\n  if (env.PAI_WORKER_FULL_PROFILE === \"1\") return [];\n  if (rest.some((a) => a === \"--settings\" || a.startsWith(\"--settings=\") || a.startsWith(\"--setting-sources\"))) return [];\n  if (!existsSync(userSettingsPath)) return [];\n  let user: Record<string, unknown>;\n  try {\n    user = JSON.parse(readFileSync(userSettingsPath, \"utf8\"));\n  } catch {\n    return [];\n  }\n  mkdirSync(logDir, { recursive: true });\n  const path = join(logDir, `${wid}.settings.json`);\n  writeFileSync(path, JSON.stringify(slimSettings(user, env, provider, noteHookCommand(logDir)), null, 2) + \"\\n\", \"utf8\");\n  return [\"--setting-sources\", \"project,local\", \"--settings\", path];\n}\n\n/**\n * Settings-file id of a pool slot. The file is read when the slot's claude\n * starts, so slots of different providers must not share one name: the last\n * writer's provider env (or lack of it) would land in every slot.\n */\nexport function poolSlotSettingsId(providerName: string, model: string): string {\n  return `pool-slot-${providerName}-${model}`.replace(/[^A-Za-z0-9._-]/g, \"_\");\n}\n","/**\n * controls.ts — the clickr argv for handing desktop control to a worker or\n * taking it back, shared by `pai worker controls` and the follow pane's\n * \"your controls\" / \"my controls\" chat action, so both go through clickr the\n * same way.\n *\n * The grant is exclusive to one worker at a time: clickr's MCP server checks\n * PAI_WORKER_ID/pid against the `--agent <id> --pid <pid>` it was handed\n * control for. Crash paths are covered by clickr's own pid check; a clean\n * exit is covered by returnControlsIfHeld below, called from every exit path\n * of run.ts's runWorker.\n */\n\nimport { spawn } from \"node:child_process\";\nimport { loadStatus, saveStatus } from \"./status.js\";\n\n/** clickr argv for `who`: `you` binds the grant to `id` (and its runner pid, when known); `me` has no target. */\nexport function clickrControlsArgv(id: string, who: \"you\" | \"me\", pid?: number): string[] {\n  if (who === \"me\") return [\"controls\", \"me\"];\n  const argv = [\"controls\", \"you\", \"--agent\", id];\n  if (pid !== undefined) argv.push(\"--pid\", String(pid));\n  return argv;\n}\n\n/** clickr argv to hand a worker's grant back on its exit. */\nexport function clickrControlsReturnArgv(id: string): string[] {\n  return [\"controls\", \"return\", \"--agent\", id];\n}\n\n/** Record that `id` was granted clickr desktop controls (`who: \"you\"` succeeded). */\nexport function markControlsHeld(logDir: string, id: string): void {\n  const status = loadStatus(logDir, id);\n  if (!status) return;\n  status.controlsHeld = true;\n  saveStatus(logDir, status);\n}\n\n/**\n * Best-effort hand desktop controls back on a worker's exit, when it ever\n * held them. Never throws and never hangs past clickr's own exit or a 3s\n * cap — a missing clickr binary or a stuck process must not hold up the\n * worker's own exit.\n */\nexport async function returnControlsIfHeld(logDir: string, id: string | undefined): Promise<void> {\n  if (!id) return;\n  const status = loadStatus(logDir, id);\n  if (!status?.controlsHeld) return;\n  await new Promise<void>((resolve) => {\n    let done = false;\n    const finish = () => {\n      if (done) return;\n      done = true;\n      resolve();\n    };\n    try {\n      const proc = spawn(\"clickr\", clickrControlsReturnArgv(id), { stdio: \"ignore\" });\n      proc.on(\"close\", finish);\n      proc.on(\"error\", finish);\n    } catch {\n      finish();\n    }\n    setTimeout(finish, 3000).unref();\n  });\n}\n","/**\n * policy.ts — where workers run: one persistent policy plus per-run hints.\n *\n *   cloud-only   never local (battery, on the road)\n *   local-only   never cloud (conserve tokens); fails when no local server answers\n *   prefer-local local first, falls through to cloud on failure\n *   prefer-cloud cloud first (fast turnaround), local only when cloud is unavailable\n *   auto         prefer-local; cloud-only on battery; prefer-cloud for an --urgent run\n *\n * The policy lives in <logDir>/routing-policy.json (not workers.yaml: a runtime\n * switch with an expiry, not provider configuration). An explicit --provider\n * (or --capability) bypasses it entirely. chooseRoute and fallThroughReason\n * are pure; the I/O (battery, ping, quota) is gathered by routeRun.\n */\n\nimport { execFileSync } from \"node:child_process\";\nimport { existsSync, readFileSync, renameSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n  ANTHROPIC_NATIVE,\n  WorkersConfigError,\n  getProviderOrNative,\n  isLocalProvider,\n  type WorkersConfig,\n} from \"./config.js\";\nimport { cooldownRemaining, quotaExceeded, readRoutingState } from \"./routing.js\";\n\nexport const POLICY_MODES = [\"cloud-only\", \"local-only\", \"prefer-local\", \"prefer-cloud\", \"auto\"] as const;\nexport type PolicyMode = (typeof POLICY_MODES)[number];\n\nexport interface PolicyState {\n  mode: PolicyMode;\n  /** ISO stamp after which the policy no longer applies. */\n  until?: string;\n  set: string;\n}\n\n/** How a run was routed: shown by `pai worker ps`, kept in the worker status. */\nexport interface RouteInfo {\n  policy: PolicyMode;\n  reason: string;\n  local: boolean;\n}\n\nexport function policyPath(logDir: string): string {\n  return join(logDir, \"routing-policy.json\");\n}\n\n/** The active policy, or null when none is set or it has expired. */\nexport function readPolicy(logDir: string, now: Date = new Date()): PolicyState | null {\n  const path = policyPath(logDir);\n  if (!existsSync(path)) return null;\n  try {\n    const p = JSON.parse(readFileSync(path, \"utf8\")) as PolicyState;\n    if (!(POLICY_MODES as readonly string[]).includes(p.mode)) return null;\n    if (p.until && Date.parse(p.until) <= now.getTime()) return null;\n    return p;\n  } catch {\n    return null;\n  }\n}\n\nexport function writePolicy(logDir: string, mode: PolicyMode, forMs?: number, now: Date = new Date()): PolicyState {\n  const state: PolicyState = {\n    mode,\n    ...(forMs ? { until: new Date(now.getTime() + forMs).toISOString() } : {}),\n    set: now.toISOString(),\n  };\n  const tmp = `${policyPath(logDir)}.tmp`;\n  writeFileSync(tmp, JSON.stringify(state, null, 2) + \"\\n\", \"utf8\");\n  renameSync(tmp, policyPath(logDir));\n  return state;\n}\n\nexport function clearPolicy(logDir: string): void {\n  if (existsSync(policyPath(logDir))) unlinkSync(policyPath(logDir));\n}\n\n/** \"30m\", \"2h\", \"1d\" → milliseconds. */\nexport function parseDuration(s: string): number {\n  const m = /^(\\d+)([mhd])$/.exec(s.trim());\n  if (!m) throw new WorkersConfigError(`--for: expected a duration like 30m, 2h or 1d, got \"${s}\"`);\n  return Number(m[1]) * { m: 60_000, h: 3_600_000, d: 86_400_000 }[m[2] as \"m\" | \"h\" | \"d\"];\n}\n\nexport function onBattery(): boolean {\n  try {\n    return /Battery Power/.test(execFileSync(\"pmset\", [\"-g\", \"batt\"], { encoding: \"utf8\", timeout: 3000 }));\n  } catch {\n    return false;\n  }\n}\n\n// ---------------------------------------------------------------------------\n// route selection\n// ---------------------------------------------------------------------------\n\nexport interface RouteInputs {\n  mode: PolicyMode;\n  urgent: boolean;\n  localOk: boolean;\n  cloud: boolean;\n  battery: boolean;\n  /** Name of an enabled local provider that answered, or null. */\n  local: string | null;\n  /** Why `local` is null: \"no local provider\" (none enabled) or \"local down\". */\n  localWhy: string;\n  /** The cloud provider is in cooldown or over its quota. */\n  cloudUnavailable: boolean;\n}\n\nexport type RouteChoice = { local: string; reason: string } | { local: null; reason: string };\n\nexport function chooseRoute(i: RouteInputs): RouteChoice {\n  const cloud = (reason: string): RouteChoice => ({ local: null, reason });\n  const useLocal = (reason: string): RouteChoice => ({ local: i.local!, reason });\n  if (i.mode === \"cloud-only\") return cloud(\"policy cloud-only\");\n  if (i.mode === \"local-only\") {\n    if (!i.local) {\n      throw new WorkersConfigError(`policy local-only: ${i.localWhy} — start a local server or change the policy (pai worker policy)`);\n    }\n    return useLocal(\"policy local-only\");\n  }\n  if (i.mode === \"prefer-cloud\") {\n    if (i.localOk && i.local && !i.cloud) return useLocal(\"--local-ok\");\n    if (i.cloudUnavailable && i.local) return useLocal(\"cloud unavailable\");\n    return cloud(\"policy prefer-cloud\");\n  }\n  // prefer-local and auto\n  if (i.mode === \"auto\" && i.battery) return cloud(\"battery\");\n  if (i.urgent) return cloud(\"urgent\");\n  if (i.cloud) return cloud(\"--cloud\");\n  if (!i.local) return cloud(i.localWhy);\n  return useLocal(`policy ${i.mode}`);\n}\n\n/** One cheap models request; any answer below 500 (a 401 included) means the server is up. */\nexport async function pingLocal(baseUrl: string, timeoutMs = 4000): Promise<boolean> {\n  try {\n    const r = await fetch(`${baseUrl.replace(/\\/+$/, \"\")}/v1/models`, { signal: AbortSignal.timeout(timeoutMs) });\n    return r.status < 500;\n  } catch {\n    return false;\n  }\n}\n\n/** First enabled, loopback, answering provider in config order. */\nexport async function findLocal(\n  config: WorkersConfig,\n  logDir: string,\n  ping: (url: string) => Promise<boolean> = pingLocal\n): Promise<{ name: string | null; why: string }> {\n  const state = readRoutingState(logDir);\n  const candidates = Object.entries(config.providers).filter(\n    ([name, p]) => p.enabled && p.engine !== \"image\" && isLocalProvider(p.baseUrl) && cooldownRemaining(state, name) === 0\n  );\n  if (!candidates.length) return { name: null, why: \"no local provider\" };\n  for (const [name, p] of candidates) if (await ping(p.baseUrl)) return { name, why: \"\" };\n  return { name: null, why: \"local down\" };\n}\n\nexport interface RouteFlags {\n  urgent?: boolean;\n  localOk?: boolean;\n  cloud?: boolean;\n}\n\n/**\n * The policy decision for one run: null when no policy is set (class/active\n * routing stands), else the provider to pin (null = cloud, normal routing)\n * and the RouteInfo to record.\n */\nexport async function routeRun(\n  config: WorkersConfig,\n  logDir: string,\n  flags: RouteFlags\n): Promise<{ providerFlag: string | null; route: RouteInfo } | null> {\n  const policy = readPolicy(logDir);\n  if (!policy) return null;\n  const mode = policy.mode;\n  const needLocal = mode !== \"cloud-only\";\n  const found = needLocal ? await findLocal(config, logDir) : { name: null, why: \"\" };\n  const native = getProviderOrNative(config, ANTHROPIC_NATIVE);\n  const cloudUnavailable =\n    mode === \"prefer-cloud\" &&\n    (cooldownRemaining(readRoutingState(logDir), ANTHROPIC_NATIVE) > 0 || (native ? quotaExceeded(native) : false));\n  const choice = chooseRoute({\n    mode,\n    urgent: flags.urgent ?? false,\n    localOk: flags.localOk ?? false,\n    cloud: flags.cloud ?? false,\n    battery: mode === \"auto\" ? onBattery() : false,\n    local: found.name,\n    localWhy: found.why,\n    cloudUnavailable,\n  });\n  return { providerFlag: choice.local, route: { policy: mode, reason: choice.reason, local: choice.local !== null } };\n}\n\n// ---------------------------------------------------------------------------\n// fall-through\n// ---------------------------------------------------------------------------\n\nexport interface EndedRun {\n  reportValid?: boolean;\n  timedOut?: boolean;\n  rc?: number | null;\n  state?: string;\n}\n\n/**\n * Why a finished local run should be repeated once on the cloud, or null.\n * Reads the stored result: an invalid report (reportValid false covers a\n * failed AG2 check and the proof-check downgrade), r=- or r=!, a timeout, a\n * crash with no report. A killed run (rc 143) is the operator's call, not a\n * model failure.\n */\nexport function fallThroughReason(\n  route: RouteInfo | undefined,\n  status: EndedRun,\n  report: { result?: string } | null\n): string | null {\n  if (!route?.local || route.policy === \"local-only\") return null;\n  if (status.timedOut) return \"max-minutes\";\n  if (status.rc === 143) return null;\n  if (status.reportValid === false) return \"invalid report\";\n  if (report?.result === \"-\" || report?.result === \"!\") return `r=${report.result}`;\n  if (!report && status.state === \"failed\") return \"no report\";\n  return null;\n}\n","/**\n * session-name.ts — the one place that decides which session profile applies:\n * the name `pai` exported at launch, else the persistent name the picker shows\n * (AIBroker registry by iTerm pane, bridged to the claude session id; then the\n * transcript's customTitle), else the project name of the cwd.\n */\n\nimport { currentSessionName } from \"./session-profile-store.js\";\nimport { AIBROKER_REGISTRY, resolveSession } from \"./scope.js\";\n\nexport interface SessionNameDeps {\n  registryPath?: string;\n  mapPath?: string;\n  projectsDir?: string;\n  /** Project name for a directory (default: the registry `pai project list` reads). */\n  projectName?: (cwd: string) => Promise<string | undefined>;\n  cwd?: string;\n}\n\nasync function registryProjectName(cwd: string): Promise<string | undefined> {\n  try {\n    const { detectProject } = await import(\"../cli/impl/detect.js\");\n    return (await detectProject(cwd))?.display_name || undefined;\n  } catch {\n    return undefined;\n  }\n}\n\nlet cached: { key: string; name: string | undefined } | null = null;\n\n/** Env name, else AIBroker/transcript persistent name, else the cwd's project name. Cached per process (per env identity). */\nexport async function detectSessionName(env: NodeJS.ProcessEnv = process.env, deps: SessionNameDeps = {}): Promise<string | undefined> {\n  const fromEnv = currentSessionName(env);\n  if (fromEnv) return fromEnv;\n  const cwd = deps.cwd ?? process.cwd();\n  const key = [env.ITERM_SESSION_ID, env.CLAUDE_CODE_SESSION_ID, cwd, deps.registryPath, deps.mapPath, deps.projectsDir].join(\"|\");\n  if (cached?.key === key) return cached.name;\n\n  let name: string | undefined;\n  const registry = deps.registryPath ?? AIBROKER_REGISTRY;\n  const claudeId = env.CLAUDE_CODE_SESSION_ID?.trim();\n  const { loadBrokerNames, transcriptCustomTitle } = await import(\"../cli/lib/session-scan.js\");\n  name =\n    resolveSession(env.ITERM_SESSION_ID ?? \"\", registry)?.name ??\n    (claudeId ? loadBrokerNames(registry, deps.mapPath).get(claudeId) ?? transcriptCustomTitle(claudeId, deps.projectsDir) : undefined) ??\n    (await (deps.projectName ?? registryProjectName)(cwd));\n  cached = { key, name };\n  return name;\n}\n\n/** Test hook: forget the per-process cache. */\nexport function resetDetectedSessionName(): void {\n  cached = null;\n}\n","/**\n * session-profile.ts — one store, one resolver for \"which models does this\n * session use\". A profile is kept per NAMED session (the persistent name:\n * AIBroker name / custom title) in session-profiles.yaml under the PAI home:\n *\n *   job-search:\n *     chat:     { provider: anthropic, model: opus }\n *     workers:  { provider: kimi, model: fast }\n *     fallback: [ { provider: glm, model: fast }, { provider: local } ]\n *     parallel_min: 2\n *\n * resolveWorkers is the single function every worker spawn path asks (pai\n * worker run, MCP handoff/queue/plan tools). Precedence:\n *\n *   explicit target > session profile workers > env from a setup launch > global routing\n *\n * When the chosen provider is exhausted (a fresh budget reading at or above\n * its wall, default 95% of any window, or a recorded quota/429 cooldown) the\n * profile's fallback list is walked in order, else the global auto order.\n * In a batch (queue run, plan run with parallel > 1, explicit flag) fallback\n * targets whose concurrency cap is below parallel_min are skipped: a cap-1\n * server must not serialise a fan-out. Nothing left reads as `none`, with the\n * reasons, rather than a silent slow path.\n */\n\nimport { resolveCap } from \"./capacity.js\";\nimport type { BudgetMap } from \"./budget.js\";\nimport { budgetFull } from \"./budget.js\";\nimport { getProviderOrNative, type WorkersConfig } from \"./config.js\";\nimport { isLoopbackProvider } from \"./run-env.js\";\nimport { cooldownRemaining, autoOrder, type RoutingState } from \"./routing.js\";\nimport { SESSION_WORKER_PROVIDER_ENV } from \"./session-provider.js\";\nimport { detectSessionName } from \"./session-name.js\";\nimport { BATCH_ENV, currentSessionName, getProfile, type ProfileTarget, type SessionProfile } from \"./session-profile-store.js\";\n\nexport * from \"./session-profile-store.js\";\n\n// ---------------------------------------------------------------------------\n// Resolution\n// ---------------------------------------------------------------------------\n\nexport interface ResolveArgs {\n  /** Explicit target: wins over everything, never falls back. */\n  explicit?: { provider?: string; model?: string };\n  /** This spawn is part of a fan-out. */\n  batch?: boolean;\n  /** Parallelism of the fan-out (plan parallel); informational. */\n  parallel?: number;\n}\n\nexport interface ResolveCtx {\n  cfg: Pick<WorkersConfig, \"providers\" | \"routing\" | \"active\" | \"nativeModels\">;\n  profile: SessionProfile | null;\n  env: NodeJS.ProcessEnv;\n  budgets: BudgetMap;\n  routing: RoutingState;\n  now?: Date;\n}\n\nexport type WorkersSource = \"explicit\" | \"profile\" | \"env\" | \"fallback\" | \"global\" | \"none\";\n\nexport interface WorkersResolution {\n  source: WorkersSource;\n  provider?: string;\n  /** Alias default|fast or a model id; undefined = the provider's own choice. */\n  model?: string;\n  /** One line, with the reason: \"glm fast (fallback: kimi 5h at 100%)\". */\n  description: string;\n}\n\nconst label = (provider: string, model?: string): string => `${provider}${model && model !== \"default\" ? ` ${model}` : \"\"}`;\n\n/** Why a provider cannot take work right now; null when it can. */\nexport function exhaustion(ctx: ResolveCtx, name: string): string | null {\n  const p = getProviderOrNative(ctx.cfg, name);\n  if (!p) return `${name} not configured`;\n  if (!p.enabled) return `${name} disabled`;\n  const left = cooldownRemaining(ctx.routing, name, ctx.now);\n  if (left > 0) return `${name} out of quota, ${Math.ceil(left / 60_000)}m cooldown`;\n  const hit = budgetFull(ctx.cfg.routing, name, ctx.budgets[name]);\n  if (hit) return `${name} ${hit.window ? `${hit.window} ` : \"\"}at ${hit.percent}%`;\n  return null;\n}\n\n/** Concurrency cap of a provider; Infinity when uncapped. */\nexport function capOf(cfg: ResolveCtx[\"cfg\"], name: string): number {\n  const p = getProviderOrNative(cfg, name);\n  if (!p) return Infinity;\n  return resolveCap(p.maxConcurrent, isLoopbackProvider(p)) ?? Infinity;\n}\n\nexport function resolveWorkers(args: ResolveArgs, ctx: ResolveCtx): WorkersResolution {\n  const ex = args.explicit;\n  if (ex?.provider) return { source: \"explicit\", provider: ex.provider, model: ex.model, description: `${label(ex.provider, ex.model)} (explicit)` };\n\n  const profile = ctx.profile;\n  const envProvider = ctx.env[SESSION_WORKER_PROVIDER_ENV]?.trim();\n  let chosen: ProfileTarget | undefined = profile?.workers;\n  let source: WorkersSource = \"profile\";\n  if (!chosen && envProvider) {\n    chosen = { provider: envProvider };\n    source = \"env\";\n  }\n  // an explicit model alone (no provider) still applies to the chosen provider\n  if (chosen && ex?.model) chosen = { ...chosen, model: ex.model };\n  if (!chosen) return { source: \"global\", model: ex?.model, description: \"global routing\" };\n\n  const why = exhaustion(ctx, chosen.provider);\n  if (!why) return { source, provider: chosen.provider, model: chosen.model, description: `${label(chosen.provider, chosen.model)} (${source === \"env\" ? \"setup launch\" : \"session profile\"})` };\n\n  const model = chosen.model;\n  const skipped: string[] = [];\n  const min = args.batch ? profile?.parallel_min : undefined;\n  const list: ProfileTarget[] = profile?.fallback?.length\n    ? profile.fallback\n    : autoOrder(ctx.cfg as WorkersConfig).map((provider) => ({ provider }));\n  for (const t of list) {\n    if (t.provider === chosen.provider) continue;\n    const why2 = exhaustion(ctx, t.provider);\n    if (why2) {\n      skipped.push(why2);\n      continue;\n    }\n    const cap = capOf(ctx.cfg, t.provider);\n    if (min !== undefined && cap < min) {\n      skipped.push(`${t.provider} cap ${cap} < parallel_min ${min}`);\n      continue;\n    }\n    const m = t.model ?? model;\n    return { source: \"fallback\", provider: t.provider, model: m, description: `${label(t.provider, m)} (fallback: ${why})` };\n  }\n  return {\n    source: \"none\",\n    description: `no worker target available: ${why}${skipped.length ? `; skipped ${skipped.join(\", \")}` : \"\"}`,\n  };\n}\n\n/** The live context: config, this session's profile, fresh budget readings (warmed best effort) and recorded cooldowns. */\nexport async function liveResolveCtx(env: NodeJS.ProcessEnv = process.env): Promise<ResolveCtx> {\n  const [{ readWorkersSection }, { budgetCache }, { readRoutingState }, { workersLogDir }] = await Promise.all([\n    import(\"./config.js\"),\n    import(\"./budget.js\"),\n    import(\"./routing.js\"),\n    import(\"./paths.js\"),\n  ]);\n  const { workers } = readWorkersSection();\n  const profile = getProfile(await detectSessionName(env));\n  if (profile && workers.routing.policy !== \"order\") {\n    try {\n      await budgetCache.warm(workers);\n    } catch {\n      // unknown readings never read as full\n    }\n  }\n  return { cfg: workers, profile, env, budgets: budgetCache.snapshot(), routing: readRoutingState(workersLogDir(workers)) };\n}\n\nexport const isBatchEnv = (env: NodeJS.ProcessEnv = process.env): boolean => env[BATCH_ENV] === \"1\";\n","/**\n * engines/image.ts — the `engine: image` worker.\n *\n * No claude-code process, no worktree, no MCP: `pai worker run --capability\n * image` POSTs one OpenAI-compatible images-generations request straight to\n * the provider's `url` and writes the PNG it gets back. One request, no\n * retries beyond the fetch's own timeout — a caller that wants another try\n * just runs again.\n */\n\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { resolveProviderKey, WorkersConfigError, type WorkerProvider } from \"../config.js\";\n\nexport interface ImageRunOptions {\n  providerName: string;\n  provider: WorkerProvider;\n  model: string;\n  prompt: string;\n  /** Where the PNG is written; caller resolves the default path. */\n  outPath: string;\n  /** \"WIDTHxHEIGHT\", default 1024x1024. */\n  size?: string;\n  /** Default 120000 (2 minutes). */\n  timeoutMs?: number;\n}\n\nexport interface ImageRunResult {\n  ok: true;\n  path: string;\n  model: string;\n  provider: string;\n  durationMs: number;\n  bytes: number;\n}\n\nconst DEFAULT_SIZE = \"1024x1024\";\nexport const DEFAULT_IMAGE_TIMEOUT_MS = 120_000;\n\ninterface ImagesGenerationsResponse {\n  data?: { b64_json?: string }[];\n}\n\n/**\n * `POST {url}/images/generations` with `{model, prompt, size, n: 1,\n * response_format: \"b64_json\"}` and the provider's bearer token, decode the\n * base64 PNG it returns, and write it to `outPath`.\n */\nexport async function runImageCapability(opts: ImageRunOptions): Promise<ImageRunResult> {\n  if (!opts.provider.baseUrl) {\n    throw new WorkersConfigError(\n      `provider \"${opts.providerName}\" (engine image) has no \"url\" configured — set one with: ` +\n        `pai worker providers update ${opts.providerName} --base-url <url>`\n    );\n  }\n  const token = resolveProviderKey(opts.provider);\n  const url = `${opts.provider.baseUrl.replace(/\\/+$/, \"\")}/images/generations`;\n  const timeoutMs = opts.timeoutMs ?? DEFAULT_IMAGE_TIMEOUT_MS;\n  const controller = new AbortController();\n  const timer = setTimeout(() => controller.abort(), timeoutMs);\n  const t0 = Date.now();\n  let res: Response;\n  try {\n    res = await fetch(url, {\n      method: \"POST\",\n      headers: {\n        \"content-type\": \"application/json\",\n        ...(token ? { authorization: `Bearer ${token}` } : {}),\n      },\n      body: JSON.stringify({\n        model: opts.model,\n        prompt: opts.prompt,\n        size: opts.size ?? DEFAULT_SIZE,\n        n: 1,\n        response_format: \"b64_json\",\n      }),\n      signal: controller.signal,\n    });\n  } catch (e) {\n    if (e instanceof Error && e.name === \"AbortError\") {\n      throw new WorkersConfigError(\n        `provider \"${opts.providerName}\": image request timed out after ${timeoutMs}ms`\n      );\n    }\n    throw new WorkersConfigError(\n      `provider \"${opts.providerName}\": image request failed: ${e instanceof Error ? e.message : String(e)}`\n    );\n  } finally {\n    clearTimeout(timer);\n  }\n  const durationMs = Date.now() - t0;\n  const text = await res.text();\n  if (!res.ok) {\n    throw new WorkersConfigError(\n      `provider \"${opts.providerName}\": image request failed (${res.status}): ${text.slice(0, 500)}`\n    );\n  }\n  let parsed: ImagesGenerationsResponse;\n  try {\n    parsed = JSON.parse(text) as ImagesGenerationsResponse;\n  } catch {\n    throw new WorkersConfigError(`provider \"${opts.providerName}\": image response was not JSON`);\n  }\n  const b64 = parsed.data?.[0]?.b64_json;\n  if (!b64) {\n    throw new WorkersConfigError(`provider \"${opts.providerName}\": image response had no data[0].b64_json`);\n  }\n  const bytes = Buffer.from(b64, \"base64\");\n  mkdirSync(dirname(opts.outPath), { recursive: true });\n  writeFileSync(opts.outPath, bytes);\n  return {\n    ok: true,\n    path: opts.outPath,\n    model: opts.model,\n    provider: opts.providerName,\n    durationMs,\n    bytes: bytes.length,\n  };\n}\n","/**\n * pane.ts — the per-worker follow pane in iTerm2.\n *\n * One small-font pane per worker, stacked in a right-hand column: the first\n * worker of a scope splits the launching session vertically, every further\n * one splits the lowest live worker pane horizontally, so panes stack top to\n * bottom. The split never sizes the new session — that would grow the whole\n * window; instead the window's bounds are read before the split and restored\n * right after, so the panes share the space the window already had. The follow\n * command is part of the split itself — iTerm creates the new session already\n * running it — so no text is ever typed into any session afterwards; a separate\n * typing step raced the operator's keystrokes (focus briefly sits on the new\n * pane after a split, and in one observed failure the command landed in the\n * operator's own shell). A split still makes the new session the tab's active\n * one — the scripts re-select the launching session right after, so a pane\n * opening never steals the keystrokes the operator is typing. Each\n * pane runs `pai worker follow <id> --auto-exit <n>` under the `pai-worker`\n * dynamic profile (Close Sessions On End), so panes disappear by themselves.\n *\n * Panes are tracked per scope (AIBroker session id, else tab key) in\n * <logDir>/panes/<key>/<worker id>.json (one file per worker), iTerm session unique id, newest first —\n * the split lands below the lowest live worker pane.\n *\n * The dynamic profile's font is the family of iTerm's DEFAULT profile (the\n * `Default Bookmark Guid` entry in New Bookmarks) at workers.pane.fontSize —\n * never the launching session's profile, which the Python version did and\n * which produced iTerm's \"unknown parent name\" dialog whenever the two\n * differed. `Dynamic Profile Parent Name` is only written when that name\n * actually exists in New Bookmarks; when iTerm's preferences cannot be read\n * the profile is still written, with font Menlo-Regular and no parent.\n */\n\nimport { spawn } from \"node:child_process\";\nimport { execFileSync } from \"node:child_process\";\nimport {\n  existsSync,\n  mkdirSync,\n  readdirSync,\n  mkdtempSync,\n  readFileSync,\n  renameSync,\n  rmSync,\n  writeFileSync,\n} from \"node:fs\";\nimport { homedir, tmpdir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport type { WorkersConfig } from \"./config.js\";\nimport { panesDir, statusPath } from \"./paths.js\";\nimport { itermUuid, scopeKey } from \"./scope.js\";\n\nexport const PROFILE_NAME = \"pai-worker\";\n\n/** Where the dynamic profile lives (env override keeps tests off the real one). */\nexport function dynamicProfilePath(): string {\n  return process.env.PAI_WORKER_PROFILE ?? join(\n    homedir(),\n    \"Library\",\n    \"Application Support\",\n    \"iTerm2\",\n    \"DynamicProfiles\",\n    \"pai-worker.json\"\n  );\n}\n\n// ---------------------------------------------------------------------------\n// JXA scripts (arguments are passed as argv items, never interpolated).\n// JXA, not AppleScript: iTerm's AppleScript window collection can get stuck\n// failing every enumeration (\"every window doesn't understand the count\n// message\", -1708) while the JXA object model keeps answering.\n// ---------------------------------------------------------------------------\n\n// Shared prelude: locate the window/tab/session with a given unique id.\nconst FIND_SESSION = `function findSession(app, id) {\n    function arr(f) { try { return f() || []; } catch (e) { return []; } }\n    var ws = arr(function () { return app.windows(); });\n    for (var i = 0; i < ws.length; i++) {\n        if (!ws[i]) continue;\n        var ts = arr(function () { return ws[i].tabs(); });\n        for (var j = 0; j < ts.length; j++) {\n            if (!ts[j]) continue;\n            var ss = arr(function () { return ts[j].sessions(); });\n            for (var k = 0; k < ss.length; k++) {\n                try { if (ss[k] && ss[k].id() === id) return { w: ws[i], t: ts[j], s: ss[k], all: ss }; } catch (e) {}\n            }\n        }\n    }\n    return null;\n}`;\n\n// A split or new tab makes the new session the active one. Capture what was\n// active before and put it back afterwards, so typing focus stays with the\n// operator's session. Only restores a selection inside the app's own window:\n// never activates iTerm, raises a window or touches the frontmost app.\nconst CAPTURE_ACTIVE = `var prevTab = null, prevSess = null;\n    try { prevTab = f.w.currentTab(); prevSess = prevTab.currentSession(); } catch (e) {}`;\nconst RESTORE_ACTIVE = `try {\n        if (prevTab && f.w.currentTab().id() !== prevTab.id()) prevTab.select();\n        if (prevSess && prevTab.currentSession().id() !== prevSess.id()) prevSess.select();\n    } catch (e) {}`;\n\n// Smallest height a follow pane may be split down to (the visible-pane gate\n// refuses anything under 8 rows).\nconst MIN_ROWS = 8;\n\n// Equalise the follow panes' heights. iTerm exposes no pane position, so panes\n// are grouped by column count: panes stacked in one column share it, and a\n// group of equal width splits its summed rows evenly. ponytail: two columns of\n// equal width but unequal stack height are balanced as one group; upgrade to\n// real geometry if iTerm ever exposes it. Expects the `live` session list.\nconst REBALANCE = `var groups = {};\n    live.forEach(function (o) { var c = o.columns(); (groups[c] = groups[c] || []).push([o, o.rows()]); });\n    Object.keys(groups).forEach(function (c) {\n        var g = groups[c];\n        var want = Math.floor(g.reduce(function (a, e) { return a + e[1]; }, 0) / g.length);\n        g.forEach(function (e) { try { e[0].rows = want; } catch (x) {} });\n    });`;\n\n// One pane per worker: split the launching session vertically, or the lowest\n// live candidate horizontally. Returns \"<live ids>,|<new session id>\".\n// Exported for the script-content tests (window size, argv-only arguments).\nexport const WORKER_SPLIT_SCRIPT = `${FIND_SESSION}\nvar MIN_ROWS = ${MIN_ROWS};\nfunction run(argv) {\n    var targetID = argv[0], candList = argv[1], followCmd = argv[2], profileName = argv[3];\n    var app = Application(\"iTerm2\");\n    if (!app.running()) return \"notrunning\";\n    var f = findSession(app, targetID);\n    if (!f) return \"notfound\";\n    ${CAPTURE_ACTIVE}\n    // sizing the new session would grow the whole window: pin the window's\n    // bounds now and restore them after the split, so the panes share the\n    // existing space\n    var winBounds = f.w.bounds();\n    var sessIDs = f.all.map(function (o) { return o.id(); });\n    var lived = [];\n    var live = [];\n    (candList === \"\" ? [] : candList.split(\",\")).forEach(function (cid) {\n        var at = sessIDs.indexOf(cid);\n        if (at < 0) return;\n        lived.push(cid);\n        live.push(f.all[at]);\n    });\n    // split the LARGEST worker pane (by area), never the newest: halving the\n    // newest pane caps a tab at ~4 workers. Stack (horizontal split) while\n    // both halves keep >= MIN_ROWS rows, else add a column (vertical split).\n    var splitS = null;\n    live.forEach(function (o) { if (!splitS || o.columns() * o.rows() > splitS.columns() * splitS.rows()) splitS = o; });\n    var stack = splitS && Math.floor(splitS.rows() / 2) >= MIN_ROWS + 1;\n    // the follow command is part of the split itself: the pane is born already\n    // running it, so no text is ever typed into any session — a typing step\n    // raced the operator's keystrokes and could even land in the operator's\n    // own session\n    var newS;\n    if (!splitS || !stack) {\n        var base = splitS || f.s;\n        newS = profileName === \"\"\n            ? base.splitVerticallyWithDefaultProfile({ command: followCmd })\n            : base.splitVertically({ withProfile: profileName, command: followCmd });\n    } else {\n        newS = profileName === \"\"\n            ? splitS.splitHorizontallyWithDefaultProfile({ command: followCmd })\n            : splitS.splitHorizontally({ withProfile: profileName, command: followCmd });\n    }\n    live.push(newS);\n    ${REBALANCE}\n    ${RESTORE_ACTIVE}\n    try { f.w.bounds = winBounds; } catch (e) {}\n    return lived.map(function (l) { return l + \",\"; }).join(\"\") + \"|\" + newS.id();\n}`;\n\n// TTys of every session in the launching session's tab (no-worker pane variant),\n// comma-joined.\nconst TAB_TTYS_SCRIPT = `${FIND_SESSION}\nfunction run(argv) {\n    var app = Application(\"iTerm2\");\n    if (!app.running()) return \"notrunning\";\n    var f = findSession(app, argv[0]);\n    if (!f) return \"notfound\";\n    return f.all.map(function (o) { return o.tty(); }).join(\",\");\n}`;\n\n// Bounds (x1, y1, x2, y2, comma-joined) of the window hosting one iTerm\n// session — read-only, for `pai worker pane <id> --check`. Exported for the\n// script-content tests (reads bounds, never sets them).\nexport const WINDOW_BOUNDS_SCRIPT = `${FIND_SESSION}\nfunction run(argv) {\n    var app = Application(\"iTerm2\");\n    if (!app.running()) return \"notrunning\";\n    var f = findSession(app, argv[0]);\n    if (!f) return \"notfound\";\n    var b = f.w.bounds();\n    return [b.x, b.y, b.x + b.width, b.y + b.height].join(\", \");\n}`;\n\n// Split the launching session vertically and run followCmd in the new pane.\n// Exported for the script-content tests (focus stays on the launching session).\nexport const SPLIT_SCRIPT = `${FIND_SESSION}\nfunction run(argv) {\n    var followCmd = argv[1];\n    var app = Application(\"iTerm2\");\n    if (!app.running()) return \"notrunning\";\n    var f = findSession(app, argv[0]);\n    if (!f) return \"notfound\";\n    ${CAPTURE_ACTIVE}\n    // the follow command is part of the split itself (see WORKER_SPLIT_SCRIPT):\n    // nothing is ever typed into a session afterwards\n    f.s.splitVerticallyWithDefaultProfile({ command: followCmd });\n    ${RESTORE_ACTIVE}\n    return \"opened\";\n}`;\n\n// Fallback placements when a split would be too small: the follow command in a\n// new tab of the host's window, or in a new window. argv: host session id,\n// follow command, profile name (\"\" = default). Return the new session id.\nexport const NEW_PLACE_SCRIPT = `${FIND_SESSION}\nfunction run(argv) {\n    var kind = argv[0], followCmd = argv[2], profileName = argv[3];\n    var app = Application(\"iTerm2\");\n    if (!app.running()) return \"notrunning\";\n    var f = findSession(app, argv[1]);\n    if (!f) return \"notfound\";\n    ${CAPTURE_ACTIVE}\n    var opts = { command: followCmd };\n    var w = f.w;\n    if (kind === \"tab\") {\n        if (profileName === \"\") w.createTabWithDefaultProfile(opts);\n        else w.createTabWithProfile(profileName, opts);\n    } else {\n        w = profileName === \"\" ? app.createWindowWithDefaultProfile(opts) : app.createWindowWithProfile(profileName, opts);\n    }\n    var id = w.currentTab().currentSession().id();\n    if (kind === \"tab\") { ${RESTORE_ACTIVE} }\n    return id;\n}`;\n\n// ---------------------------------------------------------------------------\n// osascript / ps / defaults helpers\n// ---------------------------------------------------------------------------\n\n/** Run a JXA script with argv. Rejects when osascript itself cannot run. */\nfunction osascript(script: string, args: string[]): Promise<{ stdout: string; stderr: string }> {\n  return new Promise((resolve, reject) => {\n    const proc = spawn(\"osascript\", [\"-l\", \"JavaScript\", \"-\", ...args], { stdio: [\"pipe\", \"pipe\", \"pipe\"] });\n    let out = \"\";\n    let err = \"\";\n    proc.stdout.on(\"data\", (c: Buffer) => (out += c.toString(\"utf8\")));\n    proc.stderr.on(\"data\", (c: Buffer) => (err += c.toString(\"utf8\")));\n    proc.on(\"error\", reject);\n    proc.on(\"close\", () => resolve({ stdout: out, stderr: err }));\n    proc.stdin.write(script);\n    proc.stdin.end();\n  });\n}\n\nfunction psOutput(format: string): string {\n  try {\n    return execFileSync(\"ps\", [\"-axo\", format], { encoding: \"utf8\" });\n  } catch {\n    return \"\";\n  }\n}\n\n/** TTys of running `worker follow` processes, normalised to /dev/ttysNNN. */\nfunction followTtys(): Set<string> {\n  const ttys = new Set<string>();\n  for (const line of psOutput(\"tty=,command=\").split(\"\\n\")) {\n    const parts = line.trim().split(/\\s+/, 2);\n    if (parts.length < 2 || parts[0] === \"ps\") continue;\n    if (!/(^|\\/)(worker-follow|pai worker follow|glm-ps follow)\\b/.test(parts[1])) continue;\n    if (parts[0].startsWith(\"ttys\")) ttys.add(`/dev/${parts[0]}`);\n  }\n  return ttys;\n}\n\n/** True while a `follow <wid>` process runs (its pane shows that worker). */\nexport function workerPaneOpen(wid: string): boolean {\n  const pat = new RegExp(`(?:worker follow|worker-follow|glm-ps follow) ${wid.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")}\\\\b`);\n  return psOutput(\"command=\").split(\"\\n\").some((ln) => pat.test(ln));\n}\n\n/** One entry of iTerm's New Bookmarks (the fields the pane cares about). */\nexport interface Bookmark {\n  Name?: string;\n  Guid?: string;\n  \"Normal Font\"?: string;\n}\n\n/** What reading iTerm's preferences yielded — `error` carries the reason. */\nexport interface PrefsRead {\n  bookmarks: Bookmark[];\n  defaultGuid: string | null;\n  error: string | null;\n}\n\n/** plutil's message for an ExecFileSync failure, else the exception text. */\nfunction toolErr(e: unknown): string {\n  const err = e as { stderr?: string | Buffer; message?: string };\n  const stderr = typeof err.stderr === \"string\" ? err.stderr : err.stderr?.toString(\"utf8\");\n  return (stderr || err.message || String(e)).trim();\n}\n\n/**\n * Read New Bookmarks and Default Bookmark Guid from an iTerm preferences\n * plist. Key-scoped `plutil -extract`, never a whole-file JSON conversion:\n * real iTerm preferences carry `<date>` objects (SULastCheckTime & friends)\n * which `plutil -convert json` rejects outright — \"Invalid object in plist\n * for JSON format\" — so the whole-file read always failed and the dynamic\n * profile was never written.\n */\nexport function readItermPlist(plistPath: string): PrefsRead {\n  let bookmarks: Bookmark[] = [];\n  try {\n    const out = execFileSync(\n      \"plutil\",\n      [\"-extract\", \"New Bookmarks\", \"json\", \"-o\", \"-\", plistPath],\n      { encoding: \"utf8\", timeout: 10_000 }\n    );\n    const parsed = JSON.parse(out) as unknown;\n    if (Array.isArray(parsed)) bookmarks = parsed as Bookmark[];\n  } catch (e) {\n    return { bookmarks: [], defaultGuid: null, error: `extracting New Bookmarks: ${toolErr(e)}` };\n  }\n  let defaultGuid: string | null = null;\n  try {\n    const out = execFileSync(\n      \"plutil\",\n      [\"-extract\", \"Default Bookmark Guid\", \"raw\", \"-o\", \"-\", plistPath],\n      { encoding: \"utf8\", timeout: 10_000 }\n    );\n    defaultGuid = out.trim() || null;\n  } catch {\n    // no default guid set — defaultBookmarkFrom() yields null, fine\n  }\n  return { bookmarks, defaultGuid, error: null };\n}\n\n/** iTerm's exported preferences, via a temp plist (no shell pipe involved). */\nexport function itermPrefs(): PrefsRead {\n  let dir: string | null = null;\n  try {\n    dir = mkdtempSync(join(tmpdir(), \"pai-iterm-\"));\n    const plist = join(dir, \"iterm2.plist\");\n    execFileSync(\"defaults\", [\"export\", \"com.googlecode.iterm2\", plist], {\n      encoding: \"utf8\",\n      timeout: 10_000,\n    });\n    return readItermPlist(plist);\n  } catch (e) {\n    return { bookmarks: [], defaultGuid: null, error: `defaults export: ${toolErr(e)}` };\n  } finally {\n    if (dir) {\n      try {\n        rmSync(dir, { recursive: true, force: true });\n      } catch {\n        // best effort cleanup of a temp dir\n      }\n    }\n  }\n}\n\n/** The New Bookmarks entry of that profile name, null if absent. */\nfunction bookmarkFrom(read: PrefsRead, named: string): Bookmark | null {\n  return read.bookmarks.find((b) => b.Name === named) ?? null;\n}\n\n/** The bookmark iTerm marks default, null when it is missing or unreadable. */\nfunction defaultBookmarkFrom(read: PrefsRead): Bookmark | null {\n  return read.defaultGuid\n    ? read.bookmarks.find((b) => b.Guid === read.defaultGuid) ?? null\n    : null;\n}\n\n/** The default profile, read fresh from iTerm's preferences. */\nexport function defaultBookmark(): Bookmark | null {\n  return defaultBookmarkFrom(itermPrefs());\n}\n\n/**\n * The pane profile's font: the family of iTerm's default profile at\n * `fontSize` points (\"MesloLGLNFM-Regular 18\" + 13 → \"MesloLGLNFM-Regular 13\"),\n * or \"Menlo-Regular <fontSize>\" when the default font cannot be read.\n */\nexport function paneFont(font: string | undefined, fontSize: number): string {\n  const idx = (font ?? \"\").lastIndexOf(\" \");\n  if (idx > 0) {\n    const family = font!.slice(0, idx);\n    if (!Number.isNaN(parseFloat(font!.slice(idx + 1)))) return `${family} ${fontSize}`;\n  }\n  return `Menlo-Regular ${fontSize}`;\n}\n\n/** Write the pai-worker dynamic profile; iTerm2 loads that directory itself. */\nexport function writeDynamicProfile(\n  parent: Bookmark | null,\n  fontSize: number,\n  read: () => PrefsRead = itermPrefs\n): void {\n  const profile: Record<string, unknown> = {\n    Name: PROFILE_NAME,\n    Guid: \"pai-worker-dynamic-profile\",\n    \"Normal Font\": paneFont(parent?.[\"Normal Font\"], fontSize),\n    \"Close Sessions On End\": true,\n  };\n  // Parent name only when iTerm actually has that profile loaded — a name it\n  // does not know makes every split open an error dialog instead of a pane.\n  if (parent?.Name && bookmarkFrom(read(), parent.Name)) {\n    profile[\"Dynamic Profile Parent Name\"] = parent.Name;\n  }\n  const path = dynamicProfilePath();\n  const dir = dirname(path);\n  if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n  const tmp = `${path}.tmp`;\n  writeFileSync(tmp, JSON.stringify({ Profiles: [profile] }, null, 2) + \"\\n\", \"utf8\");\n  renameSync(tmp, path);\n}\n\nlet warnedPrefs = false;\n\n/**\n * Profile for new worker panes, creating the small-font one on demand.\n * \"\" means \"split with the default profile\" (also the fallback when the\n * dynamic profile does not show up in time).\n *\n * The profile file is written whenever it is missing — even when iTerm's\n * preferences cannot be read; then it gets font \"Menlo-Regular <fontSize>\"\n * and no parent, and the reason is logged to stderr once.\n */\nexport async function followProfile(\n  fontSize: number,\n  read: () => PrefsRead = itermPrefs\n): Promise<string> {\n  const first = read();\n  const parent = defaultBookmarkFrom(first);\n  const path = dynamicProfilePath();\n  const existed = existsSync(path);\n  if (!existed) writeDynamicProfile(parent, fontSize, () => first);\n  if (!parent) {\n    if (!warnedPrefs) {\n      warnedPrefs = true;\n      const reason = first.error ?? \"no profile is marked default\";\n      const what = existed\n        ? `keeping ${path} as-is`\n        : `wrote ${path} with Menlo-Regular ${fontSize} and no parent`;\n      process.stderr.write(\n        `pai worker pane: cannot read iTerm's default profile (${reason}) — ${what}\\n`\n      );\n    }\n    if (first.error) return \"\"; // polling cannot succeed against unreadable prefs\n  }\n  for (let i = 0; i < 10; i++) {\n    // iTerm2 picks DynamicProfiles up quickly; allow it 2 s\n    if (bookmarkFrom(read(), PROFILE_NAME)) return PROFILE_NAME;\n    await new Promise((r) => setTimeout(r, 200));\n  }\n  process.stderr.write(`pai worker pane: profile ${PROFILE_NAME} not visible, splitting with default\\n`);\n  return \"\";\n}\n\n// ---------------------------------------------------------------------------\n// Pane registry\n// ---------------------------------------------------------------------------\n\nexport interface PaneEntry {\n  session: string;\n  worker: string;\n  opened: string;\n  /** the scope (registry key) the entry was opened under */\n  scope?: string;\n}\n\n/**\n * One file per worker, `<panes>/<scope>/<worker id>.json`: concurrent opens\n * for the same scope write different files, so none can be lost (the former\n * shared `<scope>.json` list was a read-modify-write that dropped entries when\n * workers started a second apart). Legacy `<scope>.json` lists are still read.\n */\nfunction readEntry(path: string, scope: string): PaneEntry[] {\n  try {\n    const v = JSON.parse(readFileSync(path, \"utf8\")) as unknown;\n    return (Array.isArray(v) ? v : [v])\n      .filter((e): e is PaneEntry => !!e && typeof (e as PaneEntry).session === \"string\" && typeof (e as PaneEntry).worker === \"string\")\n      .map((e) => ({ ...e, scope }));\n  } catch {\n    return [];\n  }\n}\n\n/** Registry entries of one scope (`scope` set) or of all scopes, oldest first. */\nexport function loadRegistry(logDir: string, scope?: string): PaneEntry[] {\n  const root = panesDir(logDir);\n  const out: PaneEntry[] = [];\n  let names: string[] = [];\n  try {\n    names = readdirSync(root);\n  } catch {\n    return out;\n  }\n  for (const name of names.sort()) {\n    const full = join(root, name);\n    if (name.endsWith(\".json\")) {\n      const sc = name.slice(0, -5);\n      if (!scope || sc === scope) out.push(...readEntry(full, sc));\n    } else if (!scope || name === scope) {\n      try {\n        for (const f of readdirSync(full)) if (f.endsWith(\".json\")) out.push(...readEntry(join(full, f), name));\n      } catch {\n        /* not a directory */\n      }\n    }\n  }\n  return out.sort((x, y) => x.opened.localeCompare(y.opened));\n}\n\nfunction entryPath(logDir: string, e: PaneEntry): string {\n  return join(panesDir(logDir), e.scope ?? \"\", `${e.worker}.json`);\n}\n\nfunction saveEntry(logDir: string, e: PaneEntry): void {\n  const path = entryPath(logDir, e);\n  mkdirSync(dirname(path), { recursive: true });\n  const tmp = `${path}.${process.pid}.tmp`;\n  writeFileSync(tmp, JSON.stringify({ session: e.session, worker: e.worker, opened: e.opened }, null, 1), \"utf8\");\n  renameSync(tmp, path);\n}\n\n/** Forget an entry (its per-worker file; a legacy list is rewritten without it). */\nfunction dropEntry(logDir: string, e: PaneEntry): void {\n  const legacy = join(panesDir(logDir), `${e.scope}.json`);\n  rmSync(entryPath(logDir, e), { force: true });\n  if (existsSync(legacy)) {\n    const rest = readEntry(legacy, e.scope ?? \"\").filter((x) => x.session !== e.session);\n    writeFileSync(legacy, JSON.stringify(rest.map(({ scope: _s, ...x }) => x), null, 1), \"utf8\");\n  }\n}\n\n// ---------------------------------------------------------------------------\n// Ending panes of finished workers\n// ---------------------------------------------------------------------------\n\n// One listing for every caller. Each property is read on its own: iTerm 3.7 can\n// throw on name() for a session, which must not drop the others.\nconst LIST_SESSIONS_SCRIPT = `function run(argv) {\n    var app = Application(\"iTerm2\");\n    if (!app.running()) return \"\";\n    function get(s, k) { try { return String(s[k]()); } catch (e) { return \"\"; } }\n    function arr(f) { try { return f() || []; } catch (e) { return []; } }\n    var out = \"\";\n    arr(function () { return app.windows(); }).forEach(function (w) {\n        if (!w) return;\n        arr(function () { return w.tabs(); }).forEach(function (t) {\n            if (!t) return;\n            arr(function () { return t.sessions(); }).forEach(function (s) {\n                if (!s) return;\n                var id = get(s, \"id\");\n                function v(n) { try { return String(s.variable({ named: n })); } catch (e) { return \"\"; } }\n                if (id) out += id + \"\\\\t\" + get(s, \"tty\") + \"\\\\t\" + v(\"jobPid\") + \"\\\\t\" + v(\"pid\") + \"\\\\t\" + get(s, \"name\") + \"\\\\n\";\n            });\n        });\n    });\n    return out;\n}`;\n\nexport interface ItermSession {\n  id: string;\n  tty: string;\n  /** Pid of the session's foreground job (variable \"jobPid\"), undefined when iTerm gave none. */\n  jobPid?: number;\n  /** Pid of the session's root process (variable \"pid\"). */\n  pid?: number;\n  /** Undefined when iTerm would not give the session's name. */\n  name?: string;\n}\n\n/** Every open iTerm session. [] when iTerm is not running; rejects when the script fails twice. */\nexport async function listItermSessions(\n  run: (script: string, args: string[]) => Promise<{ stdout: string }> = osascript\n): Promise<ItermSession[]> {\n  let p: { stdout: string };\n  try {\n    p = await run(LIST_SESSIONS_SCRIPT, []);\n  } catch {\n    await new Promise((r) => setTimeout(r, 300)); // a window may be mid-close; one retry\n    p = await run(LIST_SESSIONS_SCRIPT, []);\n  }\n  return p.stdout\n    .split(\"\\n\")\n    .filter(Boolean)\n    .map((l) => {\n      const [id, tty, jobPid, pid, ...name] = l.split(\"\\t\");\n      return { id, tty, jobPid: Number(jobPid) || undefined, pid: Number(pid) || undefined, name: name.join(\"\\t\") || undefined };\n    });\n}\n\n// Ends one session by its unique id, never a window or the app.\nconst END_SESSION_SCRIPT = `${FIND_SESSION}\nfunction run(argv) {\n    var app = Application(\"iTerm2\");\n    if (!app.running()) return \"notrunning\";\n    var f = findSession(app, argv[0]);\n    if (!f) return \"notfound\";\n    f.s.close();\n    return \"closed\";\n}`;\n\n// Re-balance the follow panes (argv[0]: comma-joined session ids) after a close.\nexport const REBALANCE_SCRIPT = `${FIND_SESSION}\nfunction run(argv) {\n    var ids = argv[0].split(\",\");\n    var app = Application(\"iTerm2\");\n    if (!app.running()) return \"notrunning\";\n    var f = null;\n    for (var i = 0; i < ids.length && !f; i++) f = findSession(app, ids[i]);\n    if (!f) return \"notfound\";\n    var winBounds = f.w.bounds();\n    var live = f.all.filter(function (o) { return ids.indexOf(o.id()) >= 0; });\n    ${REBALANCE}\n    try { f.w.bounds = winBounds; } catch (e) {}\n    return \"balanced\";\n}`;\n\n/** The real iTerm / tmux calls, swappable so tests never touch either. */\nexport interface PaneOps {\n  listIterm(): Promise<Array<{ id: string; name: string }>>;\n  closeIterm(id: string): Promise<boolean>;\n  listTmux(): Array<{ id: string; command: string }>;\n  closeTmux(id: string): boolean;\n  /** Equalise the heights of the given follow panes (optional: tests omit it). */\n  rebalanceIterm?(ids: string[]): Promise<void>;\n}\n\nexport const realPaneOps: PaneOps = {\n  async listIterm() {\n    if (process.platform !== \"darwin\") return [];\n    const sessions = await listItermSessions();\n    // iTerm renames a pane after its running command (\"node\"), so the follow\n    // command is looked up by the session's tty instead\n    const cmdByTty = new Map<string, string>();\n    for (const line of psOutput(\"tty=,command=\").split(\"\\n\")) {\n      const [tty, ...rest] = line.trim().split(/\\s+/);\n      if (tty && tty !== \"??\") cmdByTty.set(`/dev/${tty}`, rest.join(\" \"));\n    }\n    return sessions.map((x) => ({ id: x.id, name: `${x.name ?? \"\"} ${cmdByTty.get(x.tty) ?? \"\"}`.trim() }));\n  },\n  async closeIterm(id) {\n    const p = await osascript(END_SESSION_SCRIPT, [id]);\n    return p.stdout.trim() === \"closed\";\n  },\n  async rebalanceIterm(ids) {\n    if (ids.length) await osascript(REBALANCE_SCRIPT, [ids.join(\",\")]);\n  },\n  listTmux() {\n    try {\n      const out = execFileSync(\"tmux\", [\"list-panes\", \"-a\", \"-F\", \"#{pane_id}\\t#{pane_start_command}\"], {\n        encoding: \"utf8\",\n        stdio: [\"ignore\", \"pipe\", \"ignore\"],\n      });\n      return out.split(\"\\n\").filter(Boolean).map((l) => ({ id: l.split(\"\\t\")[0], command: l.split(\"\\t\").slice(1).join(\" \") }));\n    } catch {\n      return [];\n    }\n  },\n  closeTmux(id) {\n    try {\n      execFileSync(\"tmux\", [\"kill-pane\", \"-t\", id], { stdio: \"ignore\" });\n      return true;\n    } catch {\n      return false;\n    }\n  },\n};\n\nconst FOLLOW_ID = /worker[- ]follow (\\d{8}-\\d{6}-\\d+)/;\n\n/** End one worker's registered iTerm pane, found by worker id. True if a pane was closed. */\nexport async function closePaneForWorker(logDir: string, wid: string, ops: PaneOps = realPaneOps): Promise<boolean> {\n  let closed = false;\n  for (const e of loadRegistry(logDir).filter((x) => x.worker === wid)) {\n    try {\n      if (await ops.closeIterm(e.session)) closed = true;\n    } catch {\n      /* iTerm gone: the entry is stale either way */\n    }\n    dropEntry(logDir, e);\n  }\n  return closed;\n}\n\n/**\n * The follow pane closing its own iTerm session on exit, so a pane closes even\n * when the runner died and even under a profile without Close Sessions On End.\n * No-op outside iTerm.\n */\nexport async function closeOwnPane(env: NodeJS.ProcessEnv = process.env, ops: PaneOps = realPaneOps): Promise<boolean> {\n  const uid = itermUuid(env.ITERM_SESSION_ID ?? \"\");\n  if (!uid) return false;\n  return ops.closeIterm(uid).catch(() => false);\n}\n\nexport interface CloseEndedResult {\n  closed: string[];\n  kept: string[];\n}\n\n/**\n * Close every open follow pane whose worker has ended: registry entries first\n * (by worker id), then any iTerm session named after / tmux pane started with a\n * `worker follow <id>` command of an ended worker. `ended(id)` says whether\n * that worker is over; unknown ids are never closed. `dryRun` only reports.\n */\nexport async function closeEndedPanes(\n  logDir: string,\n  ended: (wid: string) => boolean,\n  dryRun: boolean,\n  ops: PaneOps = realPaneOps\n): Promise<CloseEndedResult> {\n  const res: CloseEndedResult = { closed: [], kept: [] };\n  const seen = new Set<string>();\n  const handle = async (backend: \"iterm\" | \"tmux\", id: string, worker: string, entry?: PaneEntry): Promise<void> => {\n    const key = `${backend}:${id}`;\n    if (seen.has(key)) return;\n    seen.add(key);\n    if (!ended(worker)) {\n      res.kept.push(`${worker} ${key} (running)`);\n      return;\n    }\n    if (!dryRun) {\n      const ok = backend === \"tmux\" ? ops.closeTmux(id) : await ops.closeIterm(id).catch(() => false);\n      if (entry) dropEntry(logDir, entry); // stale whether or not the pane still existed\n      if (!ok && !entry) return;\n    }\n    res.closed.push(`${worker} ${key}${dryRun ? \" (dry run)\" : \"\"}`);\n  };\n  // iTerm unreachable: no live-session view, registry entries are still handled\n  const sessions = await ops.listIterm().catch(() => []);\n  const open = new Set(sessions.map((s) => s.id));\n  for (const e of loadRegistry(logDir)) {\n    // iTerm answered and the session is gone: a stale entry, forgotten without a close\n    if (sessions.length && !open.has(e.session)) {\n      if (!dryRun) dropEntry(logDir, e);\n      continue;\n    }\n    await handle(\"iterm\", e.session, e.worker, e);\n  }\n  for (const s of sessions) {\n    const m = FOLLOW_ID.exec(s.name);\n    if (m) await handle(\"iterm\", s.id, m[1]);\n  }\n  for (const t of ops.listTmux()) {\n    const m = FOLLOW_ID.exec(t.command);\n    if (m) await handle(\"tmux\", t.id, m[1]);\n  }\n  // closed panes leave uneven neighbours: re-balance what is left\n  if (!dryRun && res.closed.length) {\n    await ops.rebalanceIterm?.(loadRegistry(logDir).map((e) => e.session)).catch(() => undefined);\n  }\n  return res;\n}\n\n// ---------------------------------------------------------------------------\n// Public entry points\n// ---------------------------------------------------------------------------\n\n/**\n * The command a worker pane runs: one exec-able line with no shell syntax —\n * iTerm's split command parameter execs without a shell (proven live: panes\n * survive `sleep 30` and a single-quoted `/bin/sh -c`, die instantly on\n * `export …; …` or a redirect), so the command must be one exec-able line.\n * No --auto-exit: a finished worker's pane stays until the operator closes it\n * (exit the follow) or the next pane opened in the same scope replaces it.\n * Absolute node on the CLI entry file also sidesteps the panes' bare launchd\n * PATH (no pai, no node) and the `#!/usr/bin/env node` shebang.\n */\nexport function followCommand(wid: string): string {\n  return `${process.execPath} ${absoluteCliPath()} worker follow ${wid}`;\n}\n\n/** Absolute path of the running pai CLI; falls back to PATH lookup at spawn. */\nfunction absoluteCliPath(): string {\n  const argv1 = process.argv[1] ?? \"\";\n  if (argv1.endsWith(\"pai\")) return argv1;\n  return \"pai\";\n}\n\n// ---------------------------------------------------------------------------\n// Host session — which iTerm session launched this process\n// ---------------------------------------------------------------------------\n\n/** Lookups behind resolveHostSession, swappable so tests never touch ps or iTerm. */\nexport interface HostDeps {\n  /** [ppid, tty] of a pid, null when ps cannot say. tty is as ps prints it (\"ttys004\", \"??\"). */\n  psOf(pid: number): [number, string] | null;\n  /** Command line per pid, one batched ps call; pids ps does not know are absent. */\n  commandsOf(pids: number[]): Map<number, string>;\n  /** Every open iTerm session. Empty when iTerm is not running; rejects when the listing fails. */\n  listSessions(): Promise<ItermSession[]>;\n}\n\nexport const realHostDeps: HostDeps = {\n  psOf(pid) {\n    try {\n      const out = execFileSync(\"ps\", [\"-o\", \"ppid=,tty=\", \"-p\", String(pid)], {\n        encoding: \"utf8\",\n        env: { ...process.env, LC_ALL: \"C\" },\n      }).trim();\n      const [ppid, tty] = out.split(/\\s+/);\n      return ppid && tty ? [Number(ppid), tty] : null;\n    } catch {\n      return null;\n    }\n  },\n  commandsOf(pids) {\n    const m = new Map<number, string>();\n    if (!pids.length) return m;\n    let out = \"\";\n    try {\n      out = execFileSync(\"ps\", [\"-o\", \"pid=,command=\", \"-p\", pids.join(\",\")], {\n        encoding: \"utf8\",\n        env: { ...process.env, LC_ALL: \"C\" },\n      });\n    } catch (e) {\n      out = (e as { stdout?: string }).stdout ?? \"\"; // ps exits 1 when some pid is gone\n    }\n    for (const l of out.split(\"\\n\")) {\n      const r = /^\\s*(\\d+)\\s+(.*)$/.exec(l);\n      if (r) m.set(Number(r[1]), r[2]);\n    }\n    return m;\n  },\n  async listSessions() {\n    if (process.platform !== \"darwin\") return [];\n    return listItermSessions(); // rejects on failure: resolveHostSession reports why\n  },\n};\n\n/** Pids from `start` up through its parents (self included), stopping at init or an unknown pid. */\nfunction ancestorPids(deps: HostDeps, start: number): number[] {\n  const pids: number[] = [];\n  for (let pid = start; pids.length < 64 && pid > 1; ) {\n    pids.push(pid);\n    const row = deps.psOf(pid);\n    if (!row) break;\n    pid = row[0];\n  }\n  return pids;\n}\n\n/** /dev/ttysNNN of the nearest ancestor (self included) that has a real tty, null when none. */\nexport function ancestorTty(deps: HostDeps = realHostDeps, start: number = process.pid): string | null {\n  let pid = start;\n  for (let i = 0; i < 64 && pid > 1; i++) {\n    const row = deps.psOf(pid);\n    if (!row) return null;\n    const [ppid, tty] = row;\n    if (tty && tty !== \"??\" && tty !== \"?\") return tty.startsWith(\"/dev/\") ? tty : `/dev/${tty}`;\n    pid = ppid;\n  }\n  return null;\n}\n\nexport interface HostSession {\n  /** iTerm unique id of the host session, \"\" when none was found. */\n  uid: string;\n  /** ITERM_SESSION_ID-shaped value for status/scope: the env value when it names the host, else the bare uid. \"\" when none. */\n  term: string;\n  /** Which step resolved it: \"foreground jobPid\", \"attach <short>\", \"tty\", \"env\", or \"none\". */\n  via: string;\n  reason?: string;\n}\n\nconst UUID_RE = \"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\";\n\n/** Claude session id from a Claude process command line: `--session-id <uuid>` or `--bg-pty-host …/pty/<short>.sock`. */\nfunction claudeIdOf(cmd: string): string | undefined {\n  return new RegExp(`--session-id[ =](${UUID_RE})`, \"i\").exec(cmd)?.[1] ?? /--bg-pty-host\\s+\\S*\\/pty\\/([0-9a-f]{8})\\.sock/i.exec(cmd)?.[1];\n}\n\n/**\n * The one place that decides which iTerm session hosts this process; first hit\n * wins:\n *  1. foreground: a session whose jobPid is CLAUDE_PID or an ancestor pid\n *  2. background (`claude attach <short>`): the Claude session id from env or an\n *     ancestor's command line, matched against each session's jobPid command;\n *     several matches are ambiguous and fail loudly\n *  3. the tty of the nearest ancestor that has one\n *  4. ITERM_SESSION_ID, only when it names a live session — a reattached session\n *     keeps its old id in the process env for good\n */\nexport async function resolveHostSession(\n  env: NodeJS.ProcessEnv = process.env,\n  deps: HostDeps = realHostDeps,\n  start: number = process.pid\n): Promise<HostSession> {\n  let sessions: ItermSession[] = [];\n  let listFail = \"\";\n  try {\n    sessions = await deps.listSessions();\n  } catch (e) {\n    listFail = `session listing failed: ${(e as Error).message?.trim().split(\"\\n\")[0] ?? e}`;\n  }\n  const envTerm = env.ITERM_SESSION_ID ?? \"\";\n  const envUid = itermUuid(envTerm);\n  const found = (s: { id: string }, via: string): HostSession => ({ uid: s.id, term: s.id === envUid ? envTerm : s.id, via });\n  const notes: string[] = listFail ? [listFail] : [];\n\n  const ancestors = ancestorPids(deps, start);\n  const jobPids = sessions.flatMap((s) => (s.jobPid ? [s.jobPid] : []));\n  const cmds = deps.commandsOf([...new Set([...ancestors, ...jobPids])]);\n\n  const fg = new Set(ancestors);\n  if (Number(env.CLAUDE_PID)) fg.add(Number(env.CLAUDE_PID));\n  const byJob = sessions.find((s) => s.jobPid && fg.has(s.jobPid));\n  if (byJob) return found(byJob, \"foreground jobPid\");\n  notes.push(`foreground: no session jobPid is CLAUDE_PID ${env.CLAUDE_PID || \"(unset)\"} or an ancestor`);\n\n  const cid = env.CLAUDE_CODE_SESSION_ID || ancestors.map((p) => claudeIdOf(cmds.get(p) ?? \"\")).find(Boolean);\n  if (cid) {\n    const short = cid.slice(0, 8);\n    const attach = new RegExp(`\\\\battach\\\\s+(${short}|${cid})\\\\b`, \"i\");\n    const hits = sessions.filter((s) => s.jobPid && attach.test(cmds.get(s.jobPid) ?? \"\"));\n    if (hits.length === 1) return found(hits[0], `attach ${short}`);\n    const why = hits.length ? `ambiguous, ${hits.length} sessions run attach ${short}: ${hits.map((s) => s.id).join(\", \")}` : `no session runs attach ${short}`;\n    if (hits.length) return { uid: \"\", term: \"\", via: \"none\", reason: [...notes, `attach: ${why}`].join(\"; \") };\n    notes.push(`attach: ${why}`);\n  } else {\n    notes.push(\"attach: no Claude session id in env or ancestors\");\n  }\n\n  const tty = ancestorTty(deps, start);\n  const byTty = tty ? sessions.find((s) => s.tty === tty) : undefined;\n  if (byTty) return found(byTty, \"tty\");\n  notes.push(tty ? `tty: ancestor tty ${tty} matched no session` : \"tty: no tty ancestor\");\n\n  if (envUid && sessions.some((s) => s.id === envUid)) return { uid: envUid, term: envTerm, via: \"env\" };\n  notes.push(`env: ITERM_SESSION_ID ${envTerm ? `${envTerm} is not live` : \"is unset\"}`);\n\n  const why = sessions.length === 0 ? \"iTerm2 not running or unreachable\" : \"no live iTerm2 session matched\";\n  return { uid: \"\", term: \"\", via: \"none\", reason: `${why}; ${notes.join(\"; \")}` };\n}\n\nexport type PaneBackend = \"tmux\" | \"iterm\" | \"none\";\n\n/** The one place that decides where a follow pane opens: tmux (any OS) > iTerm2 (macOS) > nowhere. */\nexport function paneBackend(\n  env: NodeJS.ProcessEnv = process.env,\n  platform: string = process.platform,\n  hostTerm: string = \"\"\n): PaneBackend {\n  if (env.TMUX) return \"tmux\";\n  if (platform === \"darwin\" && (env.ITERM_SESSION_ID || hostTerm)) return \"iterm\";\n  return \"none\";\n}\n\nconst NO_HOST = \"pai worker pane: no live iTerm2 host session (foreground, attach, tty lookups found none, ITERM_SESSION_ID not live)\";\n\nexport function noPaneMessage(wid?: string): string {\n  return `no pane support here, use: pai worker follow${wid ? ` ${wid}` : \"\"}`;\n}\n\n/** Split the current tmux window horizontally (right-hand column) and run cmd in it, focus stays put. */\nfunction tmuxSplit(cmd: string): void {\n  const target = process.env.TMUX_PANE ? [\"-t\", process.env.TMUX_PANE] : [];\n  try {\n    execFileSync(\"tmux\", [\"split-window\", \"-h\", \"-d\", \"-l\", \"40%\", ...target, cmd], { stdio: \"pipe\" });\n  } catch (e) {\n    const err = e as { stderr?: Buffer; message?: string };\n    throw new Error(`pai worker pane: tmux split-window failed: ${(err.stderr?.toString() || err.message || \"\").trim().slice(0, 200)}`);\n  }\n}\n\n/**\n * Worker state straight from its status file (pane.ts cannot import status.ts: it imports us).\n * Ended = any state but \"running\"/\"queued\", or a live state whose runner pid is gone (a ghost\n * that died before it could write its end state). A missing/unreadable file or a status without\n * a pid is never ended.\n */\nexport function workerEnded(logDir: string, wid: string): boolean {\n  try {\n    const st = JSON.parse(readFileSync(statusPath(logDir, wid), \"utf8\")) as { state?: string; pid?: number };\n    if (!st.state) return false;\n    if (st.state !== \"running\" && st.state !== \"queued\") return true;\n    if (typeof st.pid !== \"number\" || st.pid <= 0) return false;\n    try {\n      process.kill(st.pid, 0);\n      return false;\n    } catch (e) {\n      return (e as NodeJS.ErrnoException).code !== \"EPERM\";\n    }\n  } catch {\n    return false;\n  }\n}\n\n/** The replacement rule: a new pane in a scope closes that scope's panes of ended workers. */\nexport async function closeEndedInScope(logDir: string, scope: string, ops: PaneOps = realPaneOps): Promise<void> {\n  for (const e of loadRegistry(logDir, scope)) {\n    if (!workerEnded(logDir, e.worker)) continue;\n    await ops.closeIterm(e.session).catch(() => false);\n    dropEntry(logDir, e);\n  }\n}\n\n/** Outcome of opening a worker's follow pane: the report line plus, on a fresh open, the new iTerm session id. */\nexport interface PaneOpenResult {\n  message: string;\n  session: string | null;\n}\n\n/** Open (or only report on) the stacked follow pane of one worker. */\nexport async function openPaneForWorker(\n  logDir: string,\n  config: WorkersConfig,\n  wid: string,\n  term: string\n): Promise<PaneOpenResult> {\n  if (workerPaneOpen(wid)) return { message: `pane for ${wid} already open`, session: null };\n  const backend = paneBackend(process.env, process.platform, term);\n  if (backend === \"none\") return { message: noPaneMessage(wid), session: null };\n  if (backend === \"tmux\") {\n    tmuxSplit(followCommand(wid));\n    return { message: `pane opened for ${wid}`, session: null };\n  }\n  const uid = itermUuid(term);\n  if (!uid) throw new Error(NO_HOST);\n  const scope = scopeKey(term);\n  await closeEndedInScope(logDir, scope);\n  const reg = loadRegistry(logDir, scope);\n  const profile = await followProfile(config.pane.fontSize);\n  const cmd = followCommand(wid);\n  // registry newest first: the split lands below the lowest live worker pane\n  const cands = [...reg].reverse().map((e) => e.session).join(\",\");\n  const p = await osascript(WORKER_SPLIT_SCRIPT, [uid, cands, cmd, profile]);\n  const out = p.stdout.trim();\n  if (out === \"notfound\" || out === \"notrunning\") {\n    throw new Error(\n      out === \"notfound\"\n        ? \"pai worker pane: resolved iTerm2 session vanished\"\n        : \"pai worker pane: iTerm2 is not running\"\n    );\n  }\n  const bar = out.indexOf(\"|\");\n  if (bar < 0) {\n    throw new Error(\n      `pai worker pane: osascript failed: ${(p.stderr || out).slice(0, 200)}`\n    );\n  }\n  const live = new Set(out.slice(0, bar).split(\",\").filter(Boolean));\n  for (const e of reg) if (!live.has(e.session)) dropEntry(logDir, e);\n  saveEntry(logDir, {\n    session: out.slice(bar + 1),\n    worker: wid,\n    opened: new Date().toISOString().replace(\"T\", \" \").slice(0, 19),\n    scope,\n  });\n  return { message: `pane opened for ${wid}`, session: out.slice(bar + 1) };\n}\n\n/**\n * One `--check` line with the bounds of the window hosting `term`'s iTerm\n * session — the before/after pair that shows whether a split moved it.\n * Read-only; never touches the window.\n */\nasync function windowBoundsLine(term: string): Promise<string> {\n  const uid = itermUuid(term);\n  if (!uid) return \"window bounds: (not in iTerm2)\";\n  try {\n    const p = await osascript(WINDOW_BOUNDS_SCRIPT, [uid]);\n    const out = p.stdout.trim();\n    if (out && out !== \"notfound\" && out !== \"notrunning\") return `window bounds: ${out}`;\n    const why =\n      out === \"notfound\" ? \"iTerm2 session not found\"\n      : out === \"notrunning\" ? \"iTerm2 not running\"\n      : (p.stderr.trim() || \"no output\").slice(0, 120);\n    return `window bounds: (${why})`;\n  } catch (e) {\n    return `window bounds: (osascript: ${String((e as Error).message ?? e).slice(0, 120)})`;\n  }\n}\n\n/**\n * Report-only variant used by `pai worker pane <id> --check`: whether a pane\n * runs for the worker, the bounds of the window hosting the asking session,\n * plus the dynamic profile's path, its existence, and the font it contains\n * (or, when missing, would write).\n */\nexport async function checkPaneForWorker(wid: string, fontSize: number, term: string): Promise<string> {\n  const lines = [workerPaneOpen(wid) ? `pane for ${wid} open` : `no pane for ${wid}`];\n  if (paneBackend(process.env, process.platform, term) !== \"iterm\") return lines.join(\"\\n\");\n  lines.push(await windowBoundsLine(term));\n  const path = dynamicProfilePath();\n  if (existsSync(path)) {\n    let font = \"(unreadable)\";\n    try {\n      const parsed = JSON.parse(readFileSync(path, \"utf8\")) as {\n        Profiles?: Array<{ \"Normal Font\"?: string }>;\n      };\n      font = parsed.Profiles?.[0]?.[\"Normal Font\"] ?? \"(none)\";\n    } catch {\n      // font stays \"(unreadable)\"\n    }\n    lines.push(`profile file: ${path} (exists)`);\n    lines.push(`profile font: ${font}`);\n  } else {\n    const parent = defaultBookmark();\n    lines.push(`profile file: ${path} (missing)`);\n    lines.push(`profile font (would write): ${paneFont(parent?.[\"Normal Font\"], fontSize)}`);\n  }\n  return lines.join(\"\\n\");\n}\n\n/**\n * Split this iTerm tab and run `pai worker follow` in the new pane, unless\n * one already runs here (detected by TTY — iTerm overwrites session names\n * with the running command, so names cannot serve as idempotence).\n */\nexport async function openFollowPane(\n  logDir: string,\n  _config: WorkersConfig,\n  term: string,\n  checkOnly: boolean\n): Promise<string> {\n  void logDir;\n  const backend = paneBackend(process.env, process.platform, term);\n  if (backend === \"none\") return noPaneMessage();\n  if (backend === \"tmux\") {\n    if (checkOnly) return \"no follow pane\";\n    tmuxSplit(`${process.execPath} ${absoluteCliPath()} worker follow`);\n    return \"follow pane opened\";\n  }\n  const uid = itermUuid(term);\n  if (!uid) throw new Error(NO_HOST);\n  const p = await osascript(TAB_TTYS_SCRIPT, [uid]);\n  const out = p.stdout.trim();\n  if (out === \"notfound\") throw new Error(\"pai worker pane: resolved iTerm2 session vanished\");\n  if (out === \"notrunning\") throw new Error(\"pai worker pane: iTerm2 is not running\");\n  const tabTtys = new Set(out.split(\",\").map((t) => t.trim()).filter(Boolean));\n  const overlap = [...tabTtys].filter((t) => followTtys().has(t));\n  if (overlap.length > 0) return \"follow pane already open\";\n  if (checkOnly) return \"no follow pane\";\n  // one exec-able line, no shell syntax — see followCommand()\n  const cmd = `${process.execPath} ${absoluteCliPath()} worker follow`;\n  const s = await osascript(SPLIT_SCRIPT, [uid, cmd]);\n  const sout = s.stdout.trim();\n  if (sout === \"opened\") return \"follow pane opened\";\n  if (sout === \"notfound\") throw new Error(\"pai worker pane: resolved iTerm2 session vanished\");\n  throw new Error(`pai worker pane: osascript failed: ${(s.stderr || sout).slice(0, 200)}`);\n}\n\n// ---------------------------------------------------------------------------\n// Fail-closed visibility: a headless worker runs only behind a verified pane\n// ---------------------------------------------------------------------------\n\n/**\n * The operator-only switch that lets a run go headless: this file's existence.\n * The PreToolUse Bash hook denies any command naming it, so a Claude session\n * cannot create it through Bash; only the operator's own shell can.\n */\nexport function headlessOverridePath(): string {\n  return process.env.PAI_HEADLESS_OK_FILE ?? join(homedir(), \".claude\", \"pai\", \"headless-ok\");\n}\n\n/**\n * Why this process may run a worker without a verified pane, null when it may\n * not. Three reasons only: it is itself a worker (PAI_WORKER=1: a child\n * spawned inside its parent's pane may stay headless), the operator set\n * PAI_WORKER_ALLOW_HIDDEN=1 in their own shell (buildRunEnv strips it from\n * every spawned worker, so the consent ends at the process it was set for),\n * or the operator created the override file.\n */\nexport const ALLOW_HIDDEN_ENV = \"PAI_WORKER_ALLOW_HIDDEN\";\n\nexport function headlessAllowed(env: NodeJS.ProcessEnv = process.env, file: string = headlessOverridePath()): string | null {\n  if (env.PAI_WORKER === \"1\") return \"PAI_WORKER=1 (child of a worker, runs inside its parent's pane)\";\n  if (env[ALLOW_HIDDEN_ENV] === \"1\") return `${ALLOW_HIDDEN_ENV}=1 (operator override)`;\n  if (existsSync(file)) return `operator override file ${file}`;\n  return null;\n}\n\n// Reports where the pane sits, without raising or focusing anything: a window\n// need not be frontmost, only visible (several sessions live in several windows). JSON on stdout; `fail` set when the pane is not a visible, usable\n// neighbour of the host session.\nexport const VERIFY_PANE_SCRIPT = `${FIND_SESSION}\nfunction run(argv) {\n    var app = Application(\"iTerm2\");\n    if (!app.running()) return JSON.stringify({ fail: \"iTerm2 is not running\" });\n    var h = findSession(app, argv[0]);\n    if (!h) return JSON.stringify({ fail: \"host session \" + argv[0] + \" is gone\" });\n    var p = findSession(app, argv[1]);\n    if (!p) return JSON.stringify({ fail: \"pane session \" + argv[1] + \" is gone (closed right after opening)\" });\n    function ids(ss) { return ss.map(function (o) { return o.id(); }); }\n    var where = argv[2] || \"split\";\n    if (where !== \"window\" && h.w.id() !== p.w.id()) return JSON.stringify({ fail: \"pane is in window \" + p.w.id() + \", host in window \" + h.w.id() });\n    if (where === \"split\" && ids(h.all).indexOf(argv[1]) < 0) return JSON.stringify({ fail: \"pane is not in the host's tab\" });\n    var tabs = p.w.tabs();\n    var tabIdx = 0;\n    for (var i = 0; i < tabs.length; i++) if (ids(tabs[i].sessions()).indexOf(argv[1]) >= 0) tabIdx = i + 1;\n    var selected = ids(p.w.currentTab().sessions()).indexOf(argv[1]) >= 0;\n    var b = p.w.bounds();\n    // On screen: the frame intersects a display (NSScreen is bottom-left origin, iTerm top-left).\n    ObjC.import(\"AppKit\");\n    var scr = $.NSScreen.screens, top = scr.objectAtIndex(0).frame.size.height, onScreen = false;\n    for (var k = 0; k < scr.count; k++) {\n        var f = scr.objectAtIndex(k).frame, fy = top - f.origin.y - f.size.height;\n        if (b.x < f.origin.x + f.size.width && b.x + b.width > f.origin.x && b.y < fy + f.size.height && b.y + b.height > fy) onScreen = true;\n    }\n    var hidden = false;\n    try { hidden = Application(\"System Events\").processes.byName(\"iTerm2\").visible() === false; } catch (e) {}\n    return JSON.stringify({\n        window: p.w.id(), bounds: [b.x, b.y, b.width, b.height], tab: tabIdx + \"/\" + tabs.length,\n        selectedTab: selected, onScreen: onScreen, hidden: hidden, miniaturized: p.w.miniaturized(),\n        rows: p.s.rows(), cols: p.s.columns(), tty: p.s.tty(), hostRows: h.s.rows(), hostCols: h.s.columns()\n    });\n}`;\n\n// Host session's tab selection and size, read before anything is opened.\n// JSON on stdout.\nconst HOST_TAB_SCRIPT = `${FIND_SESSION}\nfunction run(argv) {\n    var app = Application(\"iTerm2\");\n    if (!app.running()) return JSON.stringify({ fail: \"iTerm2 is not running\" });\n    var h = findSession(app, argv[0]);\n    if (!h) return JSON.stringify({ fail: \"host session \" + argv[0] + \" is gone\" });\n    var selected = h.w.currentTab().sessions().map(function (o) { return o.id(); }).indexOf(argv[0]) >= 0;\n    return JSON.stringify({ selectedTab: selected, rows: h.s.rows(), cols: h.s.columns() });\n}`;\n\n/** True unless the host session's tab is known not to be its window's selected tab. */\nasync function hostTabSelected(hostUid: string): Promise<boolean> {\n  try {\n    const p = await osascript(HOST_TAB_SCRIPT, [hostUid]);\n    return (JSON.parse(p.stdout.trim()) as { selectedTab?: boolean }).selectedTab !== false;\n  } catch {\n    return true; // unreadable: split, and let verifyPane judge the result\n  }\n}\n\n/** Where a follow pane sits: split of the host's tab, a new tab of its window, or a new window. */\nexport type PanePlacement = \"split\" | \"tab\" | \"window\";\n\nconst placements = new Map<string, PanePlacement>();\n\n/** The placement openVerifiedPane used for a worker in this process, for the status record. */\nexport function panePlacement(wid: string): PanePlacement | undefined {\n  return placements.get(wid);\n}\n\nconst MIN_PANE_ROWS = 8;\nconst MIN_PANE_COLS = 40;\n\n/** True while a `worker follow <wid>` process runs on that tty. */\nfunction followRunsOn(tty: string, wid: string): boolean {\n  const short = tty.replace(/^\\/dev\\//, \"\");\n  return psOutput(\"tty=,command=\")\n    .split(\"\\n\")\n    .some((ln) => ln.trim().startsWith(`${short} `) && new RegExp(`worker follow ${wid}\\\\b`).test(ln));\n}\n\n/**\n * Check, and bring forward, the iTerm pane of a worker. Resolves with a line\n * naming window, tab and size; rejects with the reason when the pane is not\n * something the operator can see: gone, other window or tab, tab not selected,\n * window off screen, hidden or minimised, too small, or its follow command not running\n * (polled for up to ~7 s while the new session starts it).\n */\nexport async function verifyPane(\n  hostUid: string,\n  paneUid: string,\n  wid: string,\n  run: (script: string, args: string[]) => Promise<{ stdout: string; stderr: string }> = osascript,\n  running: (tty: string, wid: string) => boolean = followRunsOn,\n  tries = 25,\n  pollMs = 300,\n  placement: PanePlacement = \"split\"\n): Promise<string> {\n  let last = \"\";\n  for (let i = 0; i < tries; i++) {\n    const p = await run(VERIFY_PANE_SCRIPT, [hostUid, paneUid, placement]);\n    let r: Record<string, unknown>;\n    try {\n      r = JSON.parse(p.stdout.trim()) as Record<string, unknown>;\n    } catch {\n      throw new Error(`pane verification failed: osascript said ${(p.stderr || p.stdout || \"nothing\").trim().slice(0, 200)}`);\n    }\n    if (typeof r.fail === \"string\") throw new Error(`pane verification failed: ${r.fail}`);\n    const rows = Number(r.rows);\n    const cols = Number(r.cols);\n    const where = `window ${r.window} [${(r.bounds as number[]).join(\",\")}] tab ${r.tab}, pane ${cols}x${rows}, ${r.tty}`;\n    if (r.miniaturized === true) throw new Error(`pane verification failed: window is minimised (${where})`);\n    if (r.selectedTab !== true) throw new Error(`pane verification failed: its tab is not the selected one (${where})`);\n    if (r.hidden === true) throw new Error(`pane verification failed: iTerm2 is hidden (${where})`);\n    if (r.onScreen !== true) throw new Error(`pane verification failed: its window is off screen (${where})`);\n    if (rows < MIN_PANE_ROWS || cols < MIN_PANE_COLS) {\n      throw new Error(`pane verification failed: pane too small, ${cols}x${rows} < ${MIN_PANE_COLS}x${MIN_PANE_ROWS} (${where})`);\n    }\n    if (running(String(r.tty), wid)) return where;\n    last = where;\n    await new Promise((res) => setTimeout(res, pollMs));\n  }\n  throw new Error(`pane verification failed: \\`worker follow ${wid}\\` is not running in the pane (${last})`);\n}\n\n/** Test seams of openVerifiedPane: the real iTerm-touching steps. */\nexport interface PaneSeam {\n  split?: typeof openPaneForWorker;\n  verify?: typeof verifyPane;\n  place?: typeof openPlaced;\n  hostSelected?: (hostUid: string) => Promise<boolean>;\n}\n\n/**\n * Open the worker's pane and prove the operator can see it, or throw the\n * reason (the pane just opened is closed again). Needs a live iTerm2 host\n * session that ITERM_SESSION_ID itself names, or tmux; a stale or invented\n * id is refused, whatever the process-tree lookup would find.\n */\nexport async function openVerifiedPane(\n  logDir: string,\n  config: WorkersConfig,\n  wid: string,\n  term: string,\n  env: NodeJS.ProcessEnv = process.env,\n  ops: PaneOps = realPaneOps,\n  seam: PaneSeam = {}\n): Promise<string> {\n  const split = seam.split ?? openPaneForWorker;\n  const verify = seam.verify ?? verifyPane;\n  const place = seam.place ?? openPlaced;\n  if (env.TMUX) {\n    const r = await openPaneForWorker(logDir, config, wid, term);\n    if (!r.message.startsWith(\"pane opened\")) throw new Error(`pane verification failed: ${r.message}`);\n    return \"tmux pane\";\n  }\n  const envUid = itermUuid(env.ITERM_SESSION_ID ?? \"\");\n  const hostUid = itermUuid(term);\n  if (!envUid) throw new Error(\"neither TMUX nor ITERM_SESSION_ID is set: this process does not run in a terminal pane the operator sees\");\n  if (envUid !== hostUid) {\n    throw new Error(`ITERM_SESSION_ID names ${envUid}, which is not a live iTerm2 session${hostUid ? ` (host found: ${hostUid})` : \"\"}`);\n  }\n  // a split in a background tab is invisible: use a new window instead\n  if (!(await (seam.hostSelected ?? hostTabSelected)(hostUid))) {\n    const where = await place(logDir, config, wid, term, hostUid, \"window\");\n    process.stderr.write(\"[pai worker] pane: new window (host tab not selected)\\n\");\n    placements.set(wid, \"window\");\n    return where;\n  }\n  const r = await split(logDir, config, wid, term);\n  if (!r.session) throw new Error(`pane verification failed: ${r.message}`);\n  try {\n    const where = await verify(hostUid, r.session, wid);\n    placements.set(wid, \"split\");\n    return `${where} (iTerm session ${r.session})`;\n  } catch (e) {\n    await closePaneForWorker(logDir, wid, ops).catch(() => false);\n    if (!/pane too small/.test((e as Error).message)) throw e;\n    // no room in this window is not \"no visible pane possible\": try a new tab, then a new window\n    await ops.rebalanceIterm?.(loadRegistry(logDir).map((x) => x.session)).catch(() => undefined);\n    for (const kind of [\"tab\", \"window\"] as const) {\n      try {\n        const where = await place(logDir, config, wid, term, hostUid, kind);\n        process.stderr.write(`[pai worker] pane: opened in a new ${kind} (${kind === \"tab\" ? \"window too crowded\" : \"no room for a tab\"})\\n`);\n        placements.set(wid, kind);\n        return where;\n      } catch {\n        // next placement; the original too-small error is what the gate reports\n      }\n    }\n    throw e;\n  }\n}\n\n/** Open the follow pane in a new tab / window, register it and verify it, closing it again on failure. */\nexport async function openPlaced(\n  logDir: string,\n  config: WorkersConfig,\n  wid: string,\n  term: string,\n  hostUid: string,\n  kind: \"tab\" | \"window\"\n): Promise<string> {\n  // a tab/window pane replaces the scope's ended panes exactly like a split does\n  await closeEndedInScope(logDir, scopeKey(term));\n  const profile = await followProfile(config.pane.fontSize);\n  const p = await osascript(NEW_PLACE_SCRIPT, [kind, hostUid, followCommand(wid), profile]);\n  const id = p.stdout.trim();\n  if (!id || id === \"notfound\" || id === \"notrunning\") {\n    throw new Error(`pane verification failed: new ${kind}: ${(p.stderr || id || \"no output\").slice(0, 200)}`);\n  }\n  saveEntry(logDir, {\n    session: id,\n    worker: wid,\n    opened: new Date().toISOString().replace(\"T\", \" \").slice(0, 19),\n    scope: scopeKey(term),\n  });\n  try {\n    return `${await verifyPane(hostUid, id, wid, osascript, followRunsOn, 25, 300, kind)} (iTerm session ${id}, new ${kind})`;\n  } catch (e) {\n    await closePaneForWorker(logDir, wid).catch(() => false);\n    throw e;\n  }\n}\n\n/** CLI entry check: --no-pane and PAI_WORKER_AUTOPANE=0 are refused unless headlessAllowed(). */\nexport function assertPaneNotDisabled(noPaneFlag: boolean, env: NodeJS.ProcessEnv = process.env): void {\n  const what = noPaneFlag ? \"--no-pane\" : env.PAI_WORKER_AUTOPANE === \"0\" ? \"PAI_WORKER_AUTOPANE=0\" : \"\";\n  if (what && !headlessAllowed(env)) {\n    throw new Error(\n      `${what} refused: every worker runs behind a visible pane ` +\n        `(only a worker's own children, the operator's ${ALLOW_HIDDEN_ENV}=1, ` +\n        `or the operator's ${headlessOverridePath()} may skip it)`\n    );\n  }\n}\n","/**\n * tree.ts — sub-workers: parent detection and the tree caps.\n *\n * A worker launched by another worker (the runner exports PAI_WORKER_ID in\n * every worker's environment) carries `parent` in its status, so the worker\n * forest is visible in `ps`, the status line and the ledger. Two caps keep\n * the tree from growing without bound, both under `workers.tree`:\n *\n *   - maxDepth (default 2): how deep sub-workers may nest. A top-level worker\n *     sits at depth 0; its children at 1; grandchildren at 2 — one level past\n *     the cap refuses with a clear message.\n *   - maxChildren (default 4): how many children of one parent may run at the\n *     same time. Finished children do not count; a planner works through its\n *     sub-tasks in waves of this size.\n *\n * Chain stages also carry `parent` (the chain id), but chains are not workers\n * and never get a status file — a parent without a status is not capped.\n */\n\nimport type { WorkersTreeConfig } from \"./config.js\";\nimport { currentWorkerId } from \"./worker-id.js\";\nimport { isLive, loadStatus, loadStatuses, saveStatus, type WorkerStatus } from \"./status.js\";\n\n/** The env var the runner sets in every worker's environment. */\nexport const WORKER_ID_ENV = \"PAI_WORKER_ID\";\n\n/** The worker this process runs inside, when it runs inside one. */\nexport function parentFromEnv(env: NodeJS.ProcessEnv = process.env): string | null {\n  const id = currentWorkerId(env);\n  return typeof id === \"string\" && id.trim() ? id.trim() : null;\n}\n\n/**\n * Depth of `id` in the worker forest: 0 for a top-level worker, 1 + the\n * parent's depth for a sub-worker. Parents without a status file (chain ids,\n * unknown ids) count as roots; a cycle reads as its own depth and is cut off\n * after the statuses it walked. `chatIsRoot` stops one level short of the\n * chat-pane tracker (origin \"chat\"): the status line treats the pane as the\n * bar itself, so the workers it spawned are its top level.\n */\nexport function workerDepth(\n  statuses: WorkerStatus[],\n  id: string,\n  opts?: { chatIsRoot?: boolean }\n): number {\n  const byId = new Map(statuses.map((s) => [s.id, s]));\n  let depth = 0;\n  let cur = byId.get(id);\n  const seen = new Set<string>([id]);\n  while (cur?.parent && !seen.has(cur.parent)) {\n    seen.add(cur.parent);\n    const next = byId.get(cur.parent);\n    if (!next) break; // chain id or stale parent: a root, not a level\n    if (!(opts?.chatIsRoot && next.origin === \"chat\")) depth += 1;\n    cur = next;\n  }\n  return depth;\n}\n\n/** Children of `parent` that are still running, oldest first. */\nexport function runningChildren(statuses: WorkerStatus[], parent: string): WorkerStatus[] {\n  return statuses.filter((s) => s.parent === parent && isLive(s));\n}\n\n/**\n * Would starting a child of `parent` stay within the caps? Throws with a\n * clear message when it would not; returns silently when `parent` has no\n * status file (a chain id or an unknown id — not a worker, not capped).\n */\nexport function assertChildAllowed(\n  logDir: string,\n  parent: string,\n  caps: WorkersTreeConfig,\n  statuses: WorkerStatus[] = loadStatuses(logDir)\n): void {\n  if (!statuses.some((s) => s.id === parent)) return;\n  const depth = workerDepth(statuses, parent);\n  if (depth + 1 > caps.maxDepth) {\n    throw new Error(\n      `worker tree: ${parent} sits at depth ${depth} and ` +\n        `workers.tree.maxDepth is ${caps.maxDepth} — it cannot start another level of sub-workers. ` +\n        `Hand the task up instead: pai worker handoff '{\"kind\":\"proposal\",\"text\":\"…\"}'`\n    );\n  }\n  const kids = runningChildren(statuses, parent);\n  if (kids.length >= caps.maxChildren) {\n    throw new Error(\n      `worker tree: ${parent} already has ${kids.length} running sub-workers ` +\n        `(${kids.map((k) => k.id).join(\", \")}) and workers.tree.maxChildren is ${caps.maxChildren} — ` +\n        `wait for one to finish, or raise the cap in the workers config`\n    );\n  }\n}\n\n/**\n * The parent a launch should record: an explicit one (chain stage) wins, else\n * the worker this process runs inside. Returns null for top-level runs.\n */\nexport function launchParent(explicit: string | undefined, env: NodeJS.ProcessEnv = process.env): string | null {\n  return explicit ?? parentFromEnv(env);\n}\n\n/** Does a status file exist for `id` (i.e. is it a worker rather than a chain)? */\nexport function isWorkerId(logDir: string, id: string): boolean {\n  return loadStatus(logDir, id) !== null;\n}\n\n/**\n * A worker owns its children's results (the worker contract says so): if\n * `parent` exits leaving sub-workers unaccounted for, its own run must not\n * report success. Two shapes count, both read off `runningChildren` and the\n * raw statuses, never a second live-child lookup:\n *\n *   - still live: left running untouched (killing another process's work\n *     here would be its own bug) but named in the reason.\n *   - marked \"running\" with a dead pid (the child never got to write its own\n *     terminal state before its parent vanished from under it): finalised\n *     here as failed, so `ps` stops showing a corpse as live.\n *\n * Returns the reason string for the parent's own report, or null when every\n * child it started is accounted for.\n */\nexport function checkOrphanedChildren(logDir: string, parent: string): string | null {\n  const statuses = loadStatuses(logDir);\n  const live = runningChildren(statuses, parent);\n  const abandoned = statuses.filter(\n    (s) => s.parent === parent && (s.state === \"running\" || s.state === \"queued\") && !isLive(s)\n  );\n  for (const child of abandoned) {\n    saveStatus(logDir, { ...child, state: \"failed\", last: `parent ${parent} exited` });\n  }\n  const ids = [...live, ...abandoned].map((s) => s.id);\n  if (!ids.length) return null;\n  return (\n    `exited with ${ids.length} sub-worker${ids.length === 1 ? \"\" : \"s\"} still running ` +\n    `(${ids.join(\", \")}); they were not waited for — run children in the foreground or wait for them before finishing`\n  );\n}\n","/**\n * handoff.ts — upward messages between workers.\n *\n * Coordination in the worker tree is upward only: a child appends a handoff\n * to `<logDir>/<parent>.inbox.jsonl` and (when the parent is a running\n * worker) the same text is said to it, so it lands in the parent's\n * conversation as `[handoff from <child>] …`. The parent's pane renders the\n * inbox as `◆` lines, `ps`/`worker_status` show an inbox count, and a child\n * that finishes delivers its structured report automatically as a\n * `kind: \"result\"` handoff. There is no downward or sideways path — telling\n * a worker something is the operator's job (`pai worker say`).\n */\n\nimport { currentWorkerId } from \"./worker-id.js\";\nimport { appendFileSync, existsSync, mkdirSync, readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { isLive, loadStatus } from \"./status.js\";\nimport { sayToWorker } from \"./operator.js\";\n\nexport const HANDOFF_KINDS = [\"proposal\", \"result\", \"question\", \"blocker\"] as const;\n\nexport type HandoffKind = (typeof HANDOFF_KINDS)[number];\n\nexport interface Handoff {\n  /** Sending worker id. */\n  from: string;\n  /** Receiving worker id (the parent). */\n  to: string;\n  kind: HandoffKind;\n  text: string;\n  /** Structured payload (a report, a proposal's fields, …). */\n  data?: Record<string, unknown>;\n  /** ISO stamp, attached on append. */\n  _ts?: string;\n}\n\n/** Where a worker's handoffs land: <logDir>/<id>.inbox.jsonl. */\nexport function inboxPath(logDir: string, id: string): string {\n  return join(logDir, `${id}.inbox.jsonl`);\n}\n\nexport function isHandoffKind(v: unknown): v is HandoffKind {\n  return typeof v === \"string\" && (HANDOFF_KINDS as readonly string[]).includes(v);\n}\n\n/**\n * Normalize a raw parsed value into a Handoff, or explain what is missing.\n * `from`/`to` may be preset by the caller (the CLI fills them from the\n * environment); everything else must be present and well-formed.\n */\nexport function parseHandoff(\n  v: unknown,\n  preset: Partial<Pick<Handoff, \"from\" | \"to\">> = {}\n): Handoff {\n  if (typeof v !== \"object\" || v === null || Array.isArray(v)) {\n    throw new Error(\"handoff payload must be a JSON object\");\n  }\n  const o = v as Record<string, unknown>;\n  const from = typeof o.from === \"string\" && o.from ? o.from : preset.from;\n  const to = typeof o.to === \"string\" && o.to ? o.to : preset.to;\n  if (!from) throw new Error(`handoff needs \"from\" (the sending worker id)`);\n  if (!to) throw new Error(`handoff needs \"to\" (the parent worker id)`);\n  if (!isHandoffKind(o.kind)) {\n    throw new Error(`handoff \"kind\" must be one of: ${HANDOFF_KINDS.join(\", \")}`);\n  }\n  const text = typeof o.text === \"string\" ? o.text : \"\";\n  if (!text.trim()) throw new Error(`handoff needs a non-empty \"text\"`);\n  const data =\n    typeof o.data === \"object\" && o.data !== null && !Array.isArray(o.data)\n      ? (o.data as Record<string, unknown>)\n      : undefined;\n  return { from, to, kind: o.kind, text, ...(data ? { data } : {}) };\n}\n\n/** Append one handoff to its recipient's inbox, stamped now. */\nexport function appendHandoff(logDir: string, h: Handoff, now: Date = new Date()): void {\n  const path = inboxPath(logDir, h.to);\n  const dir = dirname(path);\n  if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n  appendFileSync(path, JSON.stringify({ ...h, _ts: now.toISOString() }) + \"\\n\", \"utf8\");\n}\n\n/** Every handoff in a worker's inbox, oldest first; damaged lines skip. */\nexport function readInbox(logDir: string, id: string): Handoff[] {\n  const path = inboxPath(logDir, id);\n  if (!existsSync(path)) return [];\n  const out: Handoff[] = [];\n  for (const line of readFileSync(path, \"utf8\").split(\"\\n\")) {\n    if (!line.trim()) continue;\n    try {\n      out.push(JSON.parse(line) as Handoff);\n    } catch {\n      // a half-written line is not worth a crash; the rest still reads\n    }\n  }\n  return out;\n}\n\n/** How the say path prefixes a handoff so the parent model knows its source. */\nexport function handoffMessage(h: Pick<Handoff, \"from\" | \"kind\" | \"text\">): string {\n  return `[handoff from ${h.from}] (${h.kind}) ${h.text.replace(/\\s+/g, \" \").trim()}`;\n}\n\n/** True for the exact shape of handoffMessage() — the runner marks the mirror. */\nexport function isHandoffMessage(text: string): boolean {\n  return new RegExp(`^\\\\[handoff from \\\\S+\\\\] \\\\((${HANDOFF_KINDS.join(\"|\")})\\\\) `).test(text);\n}\n\n/** Test seam for deliverHandoff: the say path, overridable with a mock. */\nexport interface HandoffDeps {\n  say?: (id: string, text: string) => Promise<string>;\n}\n\n/**\n * Deliver one handoff: append it to the parent's inbox, then — when the\n * parent is a running worker with a live operator socket — say it so it\n * enters the parent's conversation. The say is best effort: a parent that is\n * busy, finished or gone still has the inbox line, and nothing here may make\n * a finishing child's exit path fail.\n */\nexport async function deliverHandoff(\n  logDir: string,\n  h: Handoff,\n  deps: HandoffDeps = {},\n  now: Date = new Date()\n): Promise<Handoff> {\n  appendHandoff(logDir, h, now);\n  const say = deps.say ?? ((id: string, text: string) => sayToWorker(logDir, id, text));\n  const parent = loadStatus(logDir, h.to);\n  if (parent && isLive(parent)) {\n    try {\n      await say(h.to, handoffMessage(h));\n    } catch {\n      // the inbox line is the durable record; a failed say is not an error\n    }\n  }\n  return h;\n}\n\n/**\n * Send a handoff from inside a worker (the `pai worker handoff` CLI and the\n * MCP tool both land here): the sender comes from PAI_WORKER_ID, the\n * recipient from its status file's `parent`. Rejects with a clear message\n * outside a worker or under a parentless worker.\n */\nexport async function handoffFromInside(\n  logDir: string,\n  env: NodeJS.ProcessEnv,\n  payload: unknown,\n  deps: HandoffDeps = {}\n): Promise<Handoff> {\n  const mine = currentWorkerId(env, logDir);\n  if (!mine) {\n    throw new Error(\n      \"not inside a worker — handoffs are sent by workers (PAI_WORKER_ID unset). \" +\n        \"Talk to a running worker with: pai worker say <id> \\\"<text>\\\"\"\n    );\n  }\n  const st = loadStatus(logDir, mine);\n  if (!st) throw new Error(`no status for this worker (${mine}) — cannot find its parent`);\n  if (!st.parent || !loadStatus(logDir, st.parent)) {\n    throw new Error(\n      `worker ${mine} has no worker parent to hand off to ` +\n        `(parent: ${st.parent ?? \"(none)\"}) — handoffs go up the worker tree only`\n    );\n  }\n  const h = parseHandoff(payload, { from: mine, to: st.parent });\n  return deliverHandoff(logDir, h, deps);\n}\n","/**\n * denials.ts — hook/permission denials a worker ran into, recorded by the\n * runner so orchestrators can fix specs that contradict the worker contract\n * and turn recurring ones into deterministic rules.\n *\n * Detection happens on the stream-json tool_result (see run.ts); this file is\n * pure: text → denial, denial list → specConflict flags.\n */\n\nexport interface Denial {\n  at: string;\n  tool: string;\n  hook: string;\n  /** First ~120 chars of the denied input (command, file_path, …). */\n  input: string;\n  /** First ~200 chars of the denial reason. */\n  reason: string;\n  specConflict: boolean;\n}\n\n/** Entries kept per run; `denialCount` on the status keeps the true total. */\nexport const MAX_DENIALS = 50;\nconst MIN_SPEC_OVERLAP = 20;\n\n/**\n * Claude Code's denial texts: `PreToolUse:<Tool> hook error: [<hook>]: <reason>`\n * (also \"hook blocking error from command\"), the `<prog>: command denied by\n * permission rules` shape, and the plain permission-denied sentences.\n */\nexport function parseDenialText(\n  text: string,\n  fallbackTool = \"?\"\n): { tool: string; hook: string; reason: string } | null {\n  const pre = text.match(/^PreToolUse:(\\S+) hook (?:blocking )?error(?: from command)?:\\s*(?:\\[([^\\]]*)\\]:?\\s*)?([\\s\\S]*)/);\n  if (pre) return { tool: pre[1], hook: pre[2] ?? \"hook\", reason: pre[3].trim() };\n  const rules = text.match(/(?:^|\\n)(\\S+): command denied by permission rules/);\n  if (rules) return { tool: fallbackTool, hook: rules[1], reason: text.trim() };\n  if (/Permission to use \\S+ has been denied|requested permissions to use \\S+, but you haven't granted/.test(text)) {\n    return { tool: fallbackTool, hook: \"permission\", reason: text.trim() };\n  }\n  return null;\n}\n\n/** The denied input as one short line: command / file_path / path / pattern / url, else JSON. */\nexport function denialInput(input: unknown): string {\n  if (typeof input !== \"object\" || input === null) return \"\";\n  const o = input as Record<string, unknown>;\n  const key = [\"command\", \"file_path\", \"path\", \"pattern\", \"url\"].find((k) => typeof o[k] === \"string\");\n  return (key ? String(o[key]) : JSON.stringify(o)).replace(/\\s+/g, \" \").slice(0, 120);\n}\n\nconst normalizeReason = (r: string): string => r.toLowerCase().replace(/\\d+/g, \"#\").replace(/\\s+/g, \" \").trim();\n\n/**\n * specConflict: the denial is likely the orchestrator's spec contradicting the\n * worker contract, not a worker mistake. True when\n *  (a) the same (hook, tool, normalized reason) was denied 2+ times in the run, or\n *  (b) the denied input shares a >= 20 char verbatim substring with the spec/prompt.\n * Sets the flag on every entry it matches, so the first occurrence of a\n * repeated denial is flagged too. Cheap enough: O(input × spec) on ≤120 chars.\n */\nexport function markSpecConflicts(denials: Denial[], spec: string | null): void {\n  const key = (d: Denial): string => `${d.hook}\\0${d.tool}\\0${normalizeReason(d.reason)}`;\n  const seen = new Map<string, number>();\n  for (const d of denials) seen.set(key(d), (seen.get(key(d)) ?? 0) + 1);\n  for (const d of denials) {\n    d.specConflict = (seen.get(key(d)) ?? 0) >= 2 || sharesSubstring(d.input, spec ?? \"\");\n  }\n}\n\nfunction sharesSubstring(input: string, spec: string): boolean {\n  for (let i = 0; i + MIN_SPEC_OVERLAP <= input.length; i++) {\n    if (spec.includes(input.slice(i, i + MIN_SPEC_OVERLAP))) return true;\n  }\n  return false;\n}\n\n/** Status fields the recorder owns. */\nexport interface DenialStatus {\n  denials?: Denial[];\n  denialCount?: number;\n}\n\n/**\n * Record one tool_result block when it is a denial. `uses` maps tool_use ids to\n * the tool name and input. Returns whether the status changed.\n */\nexport function recordDenial(\n  status: DenialStatus,\n  block: { tool_use_id?: string; is_error?: boolean; content?: unknown },\n  text: string,\n  uses: Map<string, { name: string; input: unknown }>,\n  spec: string | null,\n  at: string\n): boolean {\n  if (block.is_error !== true) return false;\n  const use = block.tool_use_id ? uses.get(block.tool_use_id) : undefined;\n  const p = parseDenialText(text, use?.name ?? \"?\");\n  if (!p) return false;\n  const list = (status.denials ??= []);\n  status.denialCount = (status.denialCount ?? 0) + 1;\n  if (list.length < MAX_DENIALS) {\n    list.push({\n      at,\n      tool: use?.name ?? p.tool,\n      hook: p.hook,\n      input: denialInput(use?.input),\n      reason: p.reason.slice(0, 200),\n      specConflict: false,\n    });\n  }\n  markSpecConflicts(list, spec);\n  return true;\n}\n\n/** `denied N` plus `spec?` when any entry looks like a spec conflict; \"\" when none. */\nexport function denialMark(s: DenialStatus): string {\n  const n = s.denialCount ?? s.denials?.length ?? 0;\n  if (n <= 0) return \"\";\n  return `denied ${n}${s.denials?.some((d) => d.specConflict) ? \" spec?\" : \"\"}`;\n}\n\n/** Replay lines: one per recorded denial, `!` marking a likely spec conflict. */\nexport function denialLines(s: DenialStatus): string[] {\n  const list = s.denials ?? [];\n  if (!list.length) return [];\n  const more = (s.denialCount ?? list.length) - list.length;\n  return [\n    `  ${denialMark(s)}:`,\n    ...list.map((d) => `  ${d.specConflict ? \"!\" : \" \"} ${d.at.slice(11, 19)} ${d.tool} [${d.hook}] ${d.input} — ${d.reason}`),\n    ...(more > 0 ? [`    … ${more} more`] : []),\n  ];\n}\n","/**\n * Per-provider worker-contract addendum: lessons learned for a model class,\n * appended to the system prompt right after the generic contract. File is\n * `providers.<name>.contract` from the config, else `<PAI_HOME>/contracts/<name>.md`.\n * Missing or empty: no addendum, behaviour unchanged.\n */\nimport { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { paiHomePath } from \"../config/pai-home.js\";\n\nexport interface ContractAddendum {\n  path: string;\n  text: string;\n  sha: string;\n}\n\nexport function loadContractAddendum(provider: string, override?: string): ContractAddendum | null {\n  const path = override ?? paiHomePath(\"contracts\", `${provider}.md`);\n  if (!existsSync(path)) return null;\n  const text = readFileSync(path, \"utf8\").trim();\n  if (!text) return null;\n  return { path, text, sha: createHash(\"sha256\").update(text).digest(\"hex\").slice(0, 8) };\n}\n","/**\n * result-grace.ts — end a headless claude that outlives its final result.\n *\n * Headless Claude Code waits for background Bash tasks before it exits, so a\n * leftover `sleep`/scan can keep the run \"running\" long after the result event.\n * After the result the process gets a short grace to exit by itself; if it has\n * not, everything below it and then claude itself is terminated.\n */\n\nimport { processTree, killProcessTree } from \"./wait-on.js\";\n\nexport const RESULT_GRACE_MS = 20_000;\n\nexport interface ResultGraceDeps {\n  /** Pids below `pid` (not `pid` itself). */\n  descendants: (pid: number) => number[];\n  /** End `pid` and its whole tree. */\n  terminate: (pid: number) => Promise<void>;\n}\n\nconst defaultDeps: ResultGraceDeps = {\n  descendants: (pid) => processTree(pid).slice(1),\n  terminate: (pid) => killProcessTree(pid),\n};\n\nexport interface ResultGrace {\n  /** The final result event arrived: (re)start the grace clock. */\n  onResult(): void;\n  /** More work is coming (operator input) or the process exited: stop the clock. */\n  cancel(): void;\n  /** Resolves once a fired grace has finished terminating; the leftover count. */\n  readonly leftover: number;\n  readonly fired: boolean;\n  settled(): Promise<void>;\n}\n\nexport function armResultGrace(\n  pid: number | undefined,\n  graceMs = RESULT_GRACE_MS,\n  deps: ResultGraceDeps = defaultDeps\n): ResultGrace {\n  let timer: NodeJS.Timeout | null = null;\n  let done: Promise<void> = Promise.resolve();\n  const g = {\n    leftover: 0,\n    fired: false,\n    onResult() {\n      if (!pid || g.fired) return;\n      if (timer) clearTimeout(timer);\n      timer = setTimeout(() => {\n        timer = null;\n        g.fired = true;\n        g.leftover = deps.descendants(pid).length;\n        done = deps.terminate(pid).catch(() => undefined);\n      }, graceMs);\n      timer.unref?.();\n    },\n    cancel() {\n      if (timer) clearTimeout(timer);\n      timer = null;\n    },\n    settled: () => done,\n  };\n  return g;\n}\n\nexport function leftoverNote(n: number): string {\n  return `finished; ended ${n} leftover background process(es)`;\n}\n","/**\n * deadline.ts — the time gate of a worker run: resolving --max-minutes /\n * --deadline / workers.defaultMaxMinutes into one absolute deadline, the\n * prompt line that tells the worker, the ps label, and the timer that stops\n * the child (SIGTERM, then SIGKILL after a grace period).\n */\n\nimport type { WorkerStatus } from \"./status.js\";\n\nexport interface RunLimit {\n  /** Epoch ms the run is stopped at. */\n  deadlineAt: number;\n  /** Minutes from launch to the deadline. */\n  minutes: number;\n}\n\n/** Local HH:MM → epoch ms: today, or tomorrow when already past. */\nexport function parseDeadline(hhmm: string, now: Date = new Date()): number {\n  const m = /^(\\d{1,2}):(\\d{2})$/.exec(hhmm.trim());\n  if (!m || Number(m[1]) > 23 || Number(m[2]) > 59) {\n    throw new Error(`--deadline: expected HH:MM (local time, 00:00-23:59), got \"${hhmm}\"`);\n  }\n  const at = new Date(now);\n  at.setHours(Number(m[1]), Number(m[2]), 0, 0);\n  if (at.getTime() <= now.getTime()) at.setDate(at.getDate() + 1);\n  return at.getTime();\n}\n\n/** The run's limit, or null when disabled (--max-minutes 0 / default 0). */\nexport function resolveLimit(\n  flags: { maxMinutes?: number; deadline?: string },\n  defaultMinutes: number,\n  now: Date = new Date()\n): RunLimit | null {\n  if (flags.maxMinutes !== undefined && flags.deadline !== undefined) {\n    throw new Error(\"--max-minutes and --deadline are mutually exclusive\");\n  }\n  if (flags.deadline !== undefined) {\n    const deadlineAt = parseDeadline(flags.deadline, now);\n    return { deadlineAt, minutes: Math.max(1, Math.round((deadlineAt - now.getTime()) / 60_000)) };\n  }\n  const minutes = flags.maxMinutes ?? defaultMinutes;\n  if (!Number.isFinite(minutes) || minutes < 0) throw new Error(`--max-minutes: expected a non-negative number, got ${minutes}`);\n  return minutes === 0 ? null : { deadlineAt: now.getTime() + minutes * 60_000, minutes };\n}\n\nconst pad = (n: number): string => String(n).padStart(2, \"0\");\n\n/** The one line injected into the worker's system prompt. */\nexport function deadlinePromptLine(limit: RunLimit): string {\n  const d = new Date(limit.deadlineAt);\n  return (\n    `Hard deadline ${pad(d.getHours())}:${pad(d.getMinutes())} (${limit.minutes} min). ` +\n    \"Finish and report before it; at the deadline the run is stopped and whatever you have is salvaged.\"\n  );\n}\n\n/** ps column: \"36s left\", \"12m left\", \"1h05m left\" for running; \"OVERDUE ...\" for overdue; \"timed out\" for stopped; null otherwise. */\nexport function deadlineLabel(\n  s: Pick<WorkerStatus, \"state\" | \"deadlineAt\" | \"timedOut\">,\n  now: number = Date.now()\n): string | null {\n  if (s.timedOut) return \"timed out\";\n  if (s.state !== \"running\" || !s.deadlineAt) return null;\n  const secs = Math.abs(s.deadlineAt - now) / 1_000;\n  let label: string;\n  if (secs < 60) {\n    label = `${Math.floor(secs)}s`;\n  } else if (secs < 3600) {\n    label = `${Math.floor(secs / 60)}m`;\n  } else {\n    const hours = Math.floor(secs / 3600);\n    const mins = Math.floor((secs % 3600) / 60);\n    label = `${hours}h${String(mins).padStart(2, \"0\")}m`;\n  }\n  return s.deadlineAt >= now ? `${label} left` : `OVERDUE ${label}`;\n}\n\n/** Grace between SIGTERM and SIGKILL. */\nexport const DEADLINE_GRACE_MS = 10_000;\n\n/**\n * Stop `proc` at the deadline: `onFire`, SIGTERM, SIGKILL after `graceMs`\n * when it is still alive. Returns the disarm function.\n */\nexport function armDeadline(\n  proc: { kill(sig?: NodeJS.Signals): boolean; exitCode: number | null; signalCode: NodeJS.Signals | null },\n  limit: RunLimit,\n  onFire: () => void,\n  graceMs: number = DEADLINE_GRACE_MS\n): () => void {\n  let kill: NodeJS.Timeout | null = null;\n  const t = setTimeout(() => {\n    onFire();\n    try {\n      proc.kill(\"SIGTERM\");\n    } catch {\n      /* already gone */\n    }\n    kill = setTimeout(() => {\n      if (proc.exitCode === null && proc.signalCode === null) {\n        try {\n          proc.kill(\"SIGKILL\");\n        } catch {\n          /* already gone */\n        }\n      }\n    }, graceMs);\n    kill.unref();\n  }, Math.max(0, limit.deadlineAt - Date.now()));\n  return () => {\n    clearTimeout(t);\n    if (kill) clearTimeout(kill);\n  };\n}\n","/**\n * browser-tools.ts — what `--no-browser` strips: --chrome, every browser MCP\n * tool grant (mcp__claude-in-chrome__*, browsr, playwright, …) and browser\n * server names, from the caller's claude args. The PreToolUse worker guard\n * denies the same tools (hooks/ts/lib/worker-guard.ts) when\n * PAI_WORKER_NO_BROWSER=1.\n */\n\nconst BROWSER_SERVER = /chrome|browsr|browser|playwright|puppeteer/i;\n\n/** A browser MCP server name (bare, e.g. \"browsr\") or tool name (mcp__browsr__open). */\nexport function isBrowserTool(name: string): boolean {\n  const server = /^mcp__(.+?)(__|$)/.exec(name)?.[1] ?? name;\n  return BROWSER_SERVER.test(server) && (name.startsWith(\"mcp__\") || !name.includes(\"__\"));\n}\n\nconst keepNonBrowser = (list: string): string[] =>\n  list.split(\",\").map((s) => s.trim()).filter((s) => s && !isBrowserTool(s));\n\n/** claude args without --chrome and browser tool grants (an emptied --allowedTools goes too). */\nexport function stripBrowserArgs(rest: string[]): string[] {\n  const out: string[] = [];\n  for (let i = 0; i < rest.length; i++) {\n    const a = rest[i];\n    if (a === \"--chrome\") continue;\n    if (a === \"--allowedTools\" && i + 1 < rest.length && !rest[i + 1].startsWith(\"-\")) {\n      const kept = keepNonBrowser(rest[++i]);\n      if (kept.length) out.push(a, kept.join(\",\"));\n    } else if (a.startsWith(\"--allowedTools=\")) {\n      const kept = keepNonBrowser(a.slice(\"--allowedTools=\".length));\n      if (kept.length) out.push(`--allowedTools=${kept.join(\",\")}`);\n    } else out.push(a);\n  }\n  return out;\n}\n\n/** Comma-list entries (--mcp values, class MCP) without browser servers. */\nexport function stripBrowserNames(names: string[]): string[] {\n  return names.map((n) => keepNonBrowser(n).join(\",\")).filter(Boolean);\n}\n","/**\n * project-config.ts — the project registry's optional launch pin, read for\n * the interactive branch of run.ts only: which MCP servers and built-in\n * tools a project's supervisor session (`pai worker run`, no -p) loads. Set\n * with `pai project mcp` / `pai project tools` (src/cli/commands/project/\n * session-config.ts), stored in the same `projects.session_config` JSON\n * column as the rest of a project's launch config. Unset = today's\n * behavior: every server, every tool.\n *\n * A standalone SQL lookup rather than importing the CLI's detectProject:\n * workers/ is a dependency of cli/, not the other way around.\n */\n\nimport { resolve } from \"node:path\";\nimport { getRegistryBackend } from \"../storage/factory.js\";\nimport type { RegistryBackend } from \"../storage/registry-interface.js\";\nimport { readMcpServers } from \"./mcp.js\";\n\nexport interface ProjectLaunchConfig {\n  slug: string;\n  mcp?: string[];\n  tools?: string[];\n}\n\nfunction asStringArray(v: unknown): string[] | undefined {\n  if (!Array.isArray(v)) return undefined;\n  const out = v.filter((x): x is string => typeof x === \"string\");\n  return out.length ? out : undefined;\n}\n\n/**\n * The launch config of the project whose root_path is `cwd` or an ancestor\n * of it (longest match wins) — null when no registered project covers it,\n * or when the matching project has no mcp/tools pin set. `registry` is\n * injectable for tests; production callers take the process-wide backend.\n */\nexport async function projectLaunchConfig(\n  cwd: string,\n  registry?: RegistryBackend\n): Promise<ProjectLaunchConfig | null> {\n  const target = resolve(cwd);\n  const backend = registry ?? (await getRegistryBackend());\n  const rows = await backend.listProjectsByPathLengthDesc({ excludeArchived: true });\n  for (const row of rows) {\n    const root = resolve(row.root_path);\n    if (target !== root && !target.startsWith(root + \"/\")) continue;\n    if (!row.session_config) return null;\n    let parsed: { mcp?: unknown; tools?: unknown };\n    try {\n      parsed = JSON.parse(row.session_config);\n    } catch {\n      return null;\n    }\n    const mcp = asStringArray(parsed.mcp);\n    const tools = asStringArray(parsed.tools);\n    return mcp || tools ? { slug: row.slug, mcp, tools } : null;\n  }\n  return null;\n}\n\n/**\n * One line per active pin, so a pin never silently removes a server or tool:\n * shown by the SessionStart hook and by `pai worker run`'s interactive launch.\n * `claudeJson` is injectable for tests; read-only.\n */\nexport function pinNotices(launch: ProjectLaunchConfig | null, claudeJson?: string): string[] {\n  if (!launch) return [];\n  const lines: string[] = [];\n  if (launch.mcp) {\n    const all = Object.keys(readMcpServers(claudeJson));\n    const loaded = all.filter((n) => launch.mcp!.includes(n));\n    const missing = all.filter((n) => !launch.mcp!.includes(n));\n    lines.push(\n      `MCP pinned for ${launch.slug}: loading ${loaded.length} of ${all.length} servers; ` +\n        `not loaded: ${missing.join(\", \") || \"(none)\"} — \\`pai project mcp --clear\\` to load all`\n    );\n  }\n  if (launch.tools) {\n    lines.push(`Tools pinned for ${launch.slug}: ${launch.tools.join(\",\")} — \\`pai project tools --clear\\``);\n  }\n  return lines;\n}\n","/**\n * codex.ts — the \"codex\" runner engine.\n *\n * A ChatGPT plan gives no API key, only Codex CLI access, so a provider may\n * set `engine: \"codex\"`: `run` then shells out to `codex exec --json <prompt>`\n * (non-interactive) instead of Claude Code. The JSONL event stream is parsed\n * into the same status-file fields (turns, tools, last) and ledger lines as a\n * Claude run, and is normalised into claude-code-shaped events in the\n * worker's .jsonl so follow/replay/the pane render it unchanged.\n *\n * Implemented against the documented `codex exec --json` interface\n * (thread.started / item.completed / turn.completed / turn.failed lines);\n * verify against the installed CLI when one is present.\n * `--allowedTools` has no Codex equivalent and is dropped (ledgered).\n */\n\nimport { execFileSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { providerKeyPath, resolveProviderKey, type WorkerProvider } from \"./config.js\";\n\n/** Build the codex exec argument vector (without the binary itself). */\nexport function buildCodexArgs(prompt: string, model: string | undefined): string[] {\n  return [\n    \"exec\",\n    \"--json\",\n    \"--skip-git-repo-check\",\n    ...(model ? [\"-m\", model] : []),\n    \"--\",\n    prompt,\n  ];\n}\n\n/** Env for a codex run: caller's env, Anthropic vars stripped, key applied. */\nexport function buildCodexEnv(provider: WorkerProvider): NodeJS.ProcessEnv {\n  const env: NodeJS.ProcessEnv = { ...process.env };\n  delete env.ANTHROPIC_API_KEY;\n  delete env.ANTHROPIC_BASE_URL;\n  delete env.ANTHROPIC_AUTH_TOKEN;\n  delete env.ANTHROPIC_DEFAULT_HAIKU_MODEL;\n  delete env.ANTHROPIC_DEFAULT_SONNET_MODEL;\n  delete env.ANTHROPIC_DEFAULT_OPUS_MODEL;\n  // API-key providers: OpenAI env from key/keyFile/baseUrl; ChatGPT-login\n  // codex (neither set) keeps its own auth from ~/.codex. A key_file that\n  // does not exist is tolerated here (unlike resolveProviderKey's other\n  // callers) — that is the ChatGPT-login shape, not a broken config.\n  const keyPath = providerKeyPath(provider);\n  if (provider.key || (keyPath && existsSync(keyPath))) {\n    env.OPENAI_API_KEY = resolveProviderKey(provider) ?? \"\";\n  }\n  if (provider.upstreamUrl) env.OPENAI_BASE_URL = provider.upstreamUrl;\n  for (const [k, v] of Object.entries(provider.env)) env[k] = v;\n  env.PAI_WORKER = \"1\";\n  return env;\n}\n\n/** Codex \"not applicable\" flags the runner drops with a ledger note. */\nexport function codexDroppedFlags(argv: string[]): string[] {\n  const dropped: string[] = [];\n  for (let i = 0; i < argv.length; i++) {\n    const a = argv[i];\n    if (a === \"--allowedTools\" || a === \"--disallowedTools\" || a === \"--mcp-config\" || a === \"--mcp\") {\n      dropped.push(a);\n      if (i + 1 < argv.length && !argv[i + 1].startsWith(\"-\")) i++; // and its value\n    } else if (a.startsWith(\"--allowedTools=\") || a.startsWith(\"--mcp-config=\")) {\n      dropped.push(a.split(\"=\")[0]);\n    }\n  }\n  return dropped;\n}\n\n// ---------------------------------------------------------------------------\n// Event stream parsing (pure — tested with recorded JSONL lines)\n// ---------------------------------------------------------------------------\n\n/** One normalised claude-code-shaped event + its effect on the status. */\nexport interface CodexEventResult {\n  events: Array<Record<string, unknown>>;\n  turns: number;\n  tools: number;\n  last: string | null;\n  isError: boolean;\n  contextTokens: number | null;\n  finalText: string | null;\n  threadId: string | null;\n}\n\nexport const emptyCodexResult = (): CodexEventResult => ({\n  events: [],\n  turns: 0,\n  tools: 0,\n  last: null,\n  isError: false,\n  contextTokens: null,\n  finalText: null,\n  threadId: null,\n});\n\n/**\n * Fold one parsed `codex exec --json` line into the running result: appends\n * normalised transcript events and updates the counters in place.\n */\nexport function foldCodexLine(line: unknown, r: CodexEventResult): void {\n  if (typeof line !== \"object\" || line === null) return;\n  const e = line as Record<string, unknown>;\n  const type = typeof e.type === \"string\" ? e.type : \"\";\n\n  if (type === \"thread.started\" && typeof e.thread_id === \"string\") {\n    r.threadId = e.thread_id;\n    return;\n  }\n  if (type === \"item.completed\" && typeof e.item === \"object\" && e.item !== null) {\n    const item = e.item as Record<string, unknown>;\n    const kind = typeof item.type === \"string\" ? item.type : \"\";\n    if (kind === \"agent_message\" && typeof item.text === \"string\") {\n      r.turns += 1;\n      r.last = `says: ${item.text.slice(0, 70)}`;\n      r.finalText = item.text;\n      r.events.push({\n        type: \"assistant\",\n        message: { content: [{ type: \"text\", text: item.text }] },\n      });\n    } else if (kind === \"command_execution\") {\n      r.tools += 1;\n      const cmd = typeof item.command === \"string\" ? item.command : \"?\";\n      const rc = typeof item.exit_code === \"number\" ? item.exit_code : 0;\n      r.last = `Bash: ${cmd.slice(0, 70)}`;\n      r.events.push({\n        type: \"assistant\",\n        message: { content: [{ type: \"tool_use\", name: \"Bash\", input: { command: cmd } }] },\n      });\n      r.events.push({\n        type: \"user\",\n        message: {\n          content: [\n            {\n              type: \"tool_result\",\n              tool_use_id: \"\",\n              is_error: rc !== 0,\n              content: item.aggregated_output ?? \"\",\n            },\n          ],\n        },\n      });\n    } else if (kind === \"file_change\") {\n      r.tools += 1;\n      const changes = Array.isArray(item.changes) ? item.changes : [];\n      const files = changes\n        .map((c) => (typeof c === \"object\" && c !== null && typeof (c as { path?: unknown }).path === \"string\" ? (c as { path: string }).path : \"?\"))\n        .join(\", \");\n      r.last = `files: ${files.slice(0, 70)}`;\n      r.events.push({\n        type: \"assistant\",\n        message: { content: [{ type: \"tool_use\", name: \"Write\", input: { file_path: files } }] },\n      });\n    } else if (kind === \"mcp_tool_call\") {\n      r.tools += 1;\n      r.last = `mcp: ${String(item.tool ?? \"?\")}`;\n    }\n    return;\n  }\n  if (type === \"turn.completed\") {\n    const usage = (typeof e.usage === \"object\" && e.usage !== null ? e.usage : {}) as {\n      input_tokens?: number;\n      output_tokens?: number;\n      cached_input_tokens?: number;\n    };\n    const tokens =\n      (usage.input_tokens ?? 0) + (usage.cached_input_tokens ?? 0) + (usage.output_tokens ?? 0);\n    if (tokens > 0) r.contextTokens = tokens;\n    return;\n  }\n  if (type === \"turn.failed\" || type === \"error\") {\n    r.isError = true;\n    const err = typeof e.error === \"object\" && e.error !== null ? e.error : {};\n    r.last = String((err as { message?: unknown }).message ?? e.message ?? \"codex turn failed\");\n  }\n}\n\n/** Parse one JSONL line; null for blanks and non-JSON noise. */\nexport function parseCodexLine(line: string): unknown | null {\n  const t = line.trim();\n  if (!t.startsWith(\"{\")) return null;\n  try {\n    return JSON.parse(t) as unknown;\n  } catch {\n    return null;\n  }\n}\n\n// ---------------------------------------------------------------------------\n// The engine probe used by `providers test`\n// ---------------------------------------------------------------------------\n\n/** True when the Codex CLI is on PATH (test reports \"not installed\" else). */\nexport function codexInstalled(): boolean {\n  try {\n    execFileSync(\"codex\", [\"--version\"], { timeout: 5000, stdio: \"ignore\" });\n    return true;\n  } catch {\n    return false;\n  }\n}\n","/**\n * run.ts — the worker runner (port of the glm / glm-run pair, provider-neutral).\n *\n * One claude-code process per call, pointed at the chosen provider:\n *\n *   - env: ANTHROPIC_BASE_URL/AUTH_TOKEN from the provider (token from its\n *     key file, never from the environment), the three DEFAULT_*_MODEL vars,\n *     the provider's extra env, nonessential traffic off, and ANTHROPIC_API_KEY\n *     stripped so nothing can fall back to Anthropic billing. Headless runs\n *     also drop the spawner's session identity (messaging socket, session id,\n *     nesting markers) — inherited, a worktree child starts tool-blind.\n *     OpenAI-protocol providers point at the PAI proxy instead (started on\n *     demand, the provider name in the URL path); codex-engine providers run\n *     the Codex CLI.\n *   - headless (-p): strict empty MCP config unless the caller brings one or\n *     names servers via --mcp / a role (then a filtered <id>.mcp.json), the\n *     core tool grants the caller did not bring (a headless run cannot\n *     approve a permission-gated tool mid-flight — with no grant at all,\n *     claude drops the file/shell tools entirely and the worker is\n *     tool-blind), PAI_WORKER=1 so PAI's per-session hooks leave it alone,\n *     the worker\n *     contract appended to the system prompt, `--input-format stream-json`\n *     with the prompt as the first stdin user message (the operator socket\n *     can add more mid-run), stream-json mirroring (every line stamped `_ts`)\n *     into <logDir>/<id>.jsonl, a live <id>.status for ps/follow/status line\n *     (context meter included), ledger lines, result printed in the caller's\n *     --output-format (json adds the parsed `report`), and the follow pane\n *     (unless --no-pane).\n *   - interactive: no MCP/tool restriction by default, no pane,\n *     ENABLE_TOOL_SEARCH=true. A project that pinned a list with `pai\n *     project mcp` / `pai project tools` gets `--strict-mcp-config\n *     --mcp-config <filtered>` / `--tools <list>` built the same way a\n *     headless run's allowlist is; an explicit --mcp or --tools on this\n *     command line still wins over the project's pin.\n *\n * Auto-routed runs that die of a quota error before the first tool call are\n * restarted on the next provider in routing order (WORKER-REROUTE ledger line).\n */\n\nimport { grantedToolNames, recordToolError } from \"./tool-errors.js\";\nimport { editHintFor } from \"./edit-assist.js\";\nimport { spawn } from \"node:child_process\";\nimport { createInterface } from \"node:readline\";\nimport { join } from \"node:path\";\nimport {\n  existsSync,\n  mkdirSync,\n  openSync,\n  writeFileSync,\n  closeSync,\n  writeSync,\n} from \"node:fs\";\nimport { NOTE_TOKEN_ENV, newNoteToken } from \"./note-delivery.js\";\nimport { appendSystemPromptArgs, parseRunnerArgs, shortText, stripPromptValues } from \"./args.js\";\nimport {\n  ANTHROPIC_NATIVE,\n  assertProviderRunnable,\n  classModelCapability,\n  isLocalProvider,\n  isModelCapability,\n  NATIVE_ANTHROPIC_MODELS,\n  readWorkersSection,\n  resolveModelCapability,\n  type WorkerProvider,\n} from \"./config.js\";\nimport { buildRunEnv, claudeCommand, isLoopbackProvider, routeLoopbackViaRouter } from \"./run-env.js\";\nimport { NoLocalServerError, resolveLocalProvider } from \"./local-provider.js\";\nimport { probeRouter } from \"../router/supervisor.js\";\nimport { detectCurrentModel } from \"./launch.js\";\n\nexport { buildRunEnv } from \"./run-env.js\";\nimport { appendLedger } from \"./ledger.js\";\nimport { decideEndReason, endFields, parentInfo, type EndInfo } from \"./endreason.js\";\nimport { peekLoopStop, takeLoopStop } from \"./loop-stop.js\";\nimport { TroubleWatcher } from \"./worker-trouble.js\";\nimport { reportOrigin, runMessenger } from \"./run-report-wiring.js\";\nimport {\n  ensureNoMcpConfig,\n  eventsPath,\n  ledgerPath,\n  noMcpConfigPath,\n  workersLogDir,\n} from \"./paths.js\";\nimport { slimProfileArgs, WORKER_BRIEF } from \"./slim-profile.js\";\nimport {\n  type WorkerStatus,\n  newWorkerId,\n  loadStatus,\n  saveStatus,\n  markStartFailed,\n  describeTool,\n  nowStamp,\n  parseSleepSecs,\n  UNLABELED,\n} from \"./status.js\";\nimport { certainContextWindow } from \"../utils/model-window.js\";\nimport { resolveSession, resolveSpawnerSession } from \"./scope.js\";\nimport { applySessionProviderEnv } from \"./session-provider.js\";\nimport { returnControlsIfHeld } from \"./controls.js\";\nimport { fallThroughReason, routeRun, type RouteInfo } from \"./policy.js\";\nimport { capacityGate, resolveCap } from \"./capacity.js\";\nimport { recordWarmup, staggerGate } from \"./stagger.js\";\nimport {\n  autoOrder,\n  capabilityForRun,\n  isQuotaFailure,\n  nextAutoProvider,\n  NoProviderError,\n  recordBudgetCooldowns,\n  resolveCapabilityRun,\n  resolveTarget,\n  setCooldown,\n  type CapabilityRunResolution,\n} from \"./routing.js\";\nimport { detectSessionName } from \"./session-name.js\";\nimport { isBatchEnv, liveResolveCtx, resolveWorkers } from \"./session-profile.js\";\nimport { budgetCache } from \"./budget.js\";\nimport { runImageCapability } from \"./engines/image.js\";\nimport { ALLOW_HIDDEN_ENV, headlessAllowed, headlessOverridePath, openPaneForWorker, openVerifiedPane, paneBackend, panePlacement, resolveHostSession } from \"./pane.js\";\nimport { assertChildAllowed, checkOrphanedChildren, isWorkerId, launchParent } from \"./tree.js\";\nimport { deliverHandoff, isHandoffMessage } from \"./handoff.js\";\nimport {\n  addWorktree,\n  adoptTree,\n  markResumed,\n  salvageOnExit,\n  gcWorktreesThrottled,\n  inPlaceSystemPrompt,\n  recordWorktree,\n  worktreeSystemPrompt,\n  worktreeWanted,\n  type WorktreeInfo,\n} from \"./worktree.js\";\nimport {\n  OPERATOR_MARK,\n  AG2_REASK_TEXT,\n  promptTrailer,\n  workerContractPrompt,\n  parseWorkerReport,\n  verifyReportChanges,\n  verifyFailNote,\n  checkProof,\n  newUntracked,\n  untrackedPaths,\n  type BashRun,\n  type WorkerReport,\n} from \"./report.js\";\nimport { parseDenialText, recordDenial } from \"./denials.js\";\nimport { validateAg2 } from \"./agentish.js\";\nimport { loadContractAddendum, type ContractAddendum } from \"./contract-addendum.js\";\nimport { loadPreamble, preambleBlock, preambleLine, type Preamble } from \"./preamble.js\";\nimport { killTree } from \"./kill-tree.js\";\nimport { armResultGrace, leftoverNote } from \"./result-grace.js\";\nimport { armDeadline, deadlinePromptLine, resolveLimit, type RunLimit } from \"./deadline.js\";\nimport { stripBrowserArgs, stripBrowserNames } from \"./browser-tools.js\";\nimport { expandMcpNames, grantsChrome, mcpServersFromToolGrants, writeMcpConfig } from \"./mcp.js\";\nimport { pinNotices, projectLaunchConfig, type ProjectLaunchConfig } from \"./project-config.js\";\nimport { createOperatorServer } from \"./operator.js\";\nimport { inputSideTokens, type UsageBlock } from \"../utils/input-side-tokens.js\";\nimport { DEFAULT_PROXY_PORT, ensureProxyRunning } from \"./proxy/server.js\";\nimport {\n  buildCodexArgs,\n  buildCodexEnv,\n  codexDroppedFlags,\n  codexInstalled,\n  emptyCodexResult,\n  foldCodexLine,\n  parseCodexLine,\n} from \"./codex.js\";\nimport {\n  poolIneligibleReason,\n  poolSettings,\n  postTaskToPool,\n  type PoolTaskResponse,\n} from \"./pool.js\";\n\nexport interface RunOptions {\n  providerFlag?: string;\n  /** --class value (the old --role): a task class from workers.classes. */\n  className?: string;\n  modelFlag?: string;\n  label?: string;\n  noPane?: boolean;\n  /** --no-stagger: skip the same-provider start gate. */\n  noStagger?: boolean;\n  /** --no-queue: skip the per-provider concurrency cap. */\n  noQueue?: boolean;\n  /** --now: wait at the front of the provider's queue (capacity.ts). */\n  priority?: \"front\";\n  /** --model fast without a provider: the routed provider's fast model. */\n  modelFast?: boolean;\n  /** --model default without a provider: the routed provider's default model, not its worker_model. */\n  modelDefault?: boolean;\n  /** --spec value, resolved for display/recording (\"-\" for stdin). */\n  specPath?: string;\n  /** --mcp value: server/set names, comma-separated. */\n  mcpFlag?: string;\n  /** Everything after `--` (the claude args). */\n  claudeArgs: string[];\n  /** Working directory for the run (default: this process's cwd). */\n  cwd?: string;\n  /** Chain stage bookkeeping: the chain id this stage belongs to. */\n  parent?: string;\n  /** Chain stage bookkeeping: the class name of this stage. */\n  stage?: string;\n  /** Suppress result printing (MCP worker_run: its stdout is the RPC channel). */\n  quiet?: boolean;\n  /** Internal: notified with the worker id once it exists (resume uses it). */\n  onWorkerStart?: (wid: string) => void;\n  /** Internal: preset worker id (the planner mints its id before phase 1). */\n  id?: string;\n  /** --worktree/--no-worktree; undefined lets the class default decide. */\n  worktreeFlag?: boolean;\n  /** Resume: the id whose worktree this run takes over (see adoptTree). */\n  resumeOf?: string;\n  /** --max-minutes: stop the run after N minutes (0 = no limit; default workers.defaultMaxMinutes). */\n  maxMinutes?: number;\n  /** --deadline HH:MM (local): stop the run then; exclusive with maxMinutes. */\n  deadline?: string;\n  /** --browser / --no-browser: undefined follows workers.noBrowserByDefault. */\n  browser?: boolean;\n  /** --print-cmd: print the assembled claude argv as JSON and exit, no spawn. */\n  printCmd?: boolean;\n  /** \"provider/model (why)\" — one line on how the provider was chosen. */\n  routeWhy?: string;\n  /** --urgent: wants a fast turnaround (policy auto/prefer-local route to the cloud). */\n  urgent?: boolean;\n  /** --local-ok: this run may go local under policy prefer-cloud. */\n  localOk?: boolean;\n  /** --cloud: this run goes to the cloud under policy prefer-local/auto. */\n  cloud?: boolean;\n  /** --local: run on the local model server PAI resolves (resolveLocalProvider); beats --provider. */\n  localFlag?: boolean;\n  /** Internal: the policy already decided (fall-through re-run); carries its route and the run it repeats. */\n  _route?: RouteInfo;\n  _fallThroughOf?: string;\n  /** Internal: suppress recursion depth on reroute. */\n  _reroutes?: number;\n  /** Internal: this run is the one automatic re-launch after an empty model response. */\n  _emptyRetried?: boolean;\n  /** Internal: this run is the planner's phase-1 worker, not a new orchestration. */\n  _planner?: boolean;\n  /** --report json|ag2: which contract/parser the run uses (default: ag2, or PAI_WORKER_REPORT). */\n  reportFormatFlag?: \"json\" | \"ag2\";\n  /** --no-report-retry: skip the one bounded re-ask on an invalid AG2 final message. */\n  noReportRetry?: boolean;\n  /** --orchestrate: the worker plans and reviews; code edits are denied (PAI_WORKER_ORCHESTRATOR=1). */\n  orchestrate?: boolean;\n  /** --capability/--for: run through resolveCapability instead of resolveTarget. */\n  capabilityFlag?: string;\n  /** --out: image-engine output path (default: <logDir>/<id>.png). */\n  imageOut?: string;\n  /** --size: image-engine \"WIDTHxHEIGHT\" (default: 1024x1024). */\n  imageSize?: string;\n  /** --timeout-ms: image-engine request timeout (default: 120000). */\n  imageTimeoutMs?: number;\n}\n\n/**\n * ag2 unless the caller passed --report json or PAI_WORKER_REPORT=json is\n * set in the environment; an explicit flag always wins over the env default.\n */\nexport function resolveReportFormat(\n  flag: \"json\" | \"ag2\" | undefined,\n  env: NodeJS.ProcessEnv = process.env\n): \"json\" | \"ag2\" {\n  if (flag) return flag;\n  return env.PAI_WORKER_REPORT === \"json\" ? \"json\" : \"ag2\";\n}\n\n/** The strict empty MCP config for headless workers, written on demand. */\nexport { ensureNoMcpConfig } from \"./paths.js\";\n\n/** A stream-json user message for the child's stdin. */\nexport function stdinUserMessage(text: string): string {\n  return JSON.stringify({ type: \"user\", message: { role: \"user\", content: text } });\n}\n\n/** An operator line as the worker sees it: carrying the contract's marker. */\nexport function operatorUserText(text: string): string {\n  return `${OPERATOR_MARK} ${text}`;\n}\n\n/**\n * ISO stamp with seconds, attached to every mirrored event (2g): local time\n * with its offset (`2026-09-17T14:19:23+02:00`), so the viewer can render the\n * wall clock the operator lives in. `offMin` is east-positive minutes —\n * injectable so tests do not depend on the machine's zone.\n */\nexport function isoStamp(d = new Date(), offMin = -d.getTimezoneOffset()): string {\n  const t = new Date(d.getTime() + offMin * 60_000);\n  const sign = offMin < 0 ? \"-\" : \"+\";\n  const abs = Math.abs(offMin);\n  const hh = String(Math.floor(abs / 60)).padStart(2, \"0\");\n  const mm = String(abs % 60).padStart(2, \"0\");\n  return `${t.toISOString().slice(0, 19)}${sign}${hh}:${mm}`;\n}\n\n// a type alias (not an interface): it must stay assignable to\n// Record<string, unknown> when written into the event transcript\nexport type StreamEvent = {\n  type?: string;\n  subtype?: string;\n  session_id?: string;\n  model?: string;\n  cwd?: string;\n  context_window?: number;\n  model_info?: { context_window?: number } | null;\n  message?: {\n    content?: Array<{\n      type?: string;\n      text?: string;\n      name?: string;\n      id?: string;\n      tool_use_id?: string;\n      input?: unknown;\n      /** tool_result blocks: the result payload (string or text blocks). */\n      content?: unknown;\n      is_error?: boolean;\n    }>;\n    usage?: UsageBlock;\n  };\n  usage?: UsageBlock;\n  result?: string;\n  is_error?: boolean;\n  is_compact?: boolean;\n  num_turns?: number;\n  duration_ms?: number;\n  /** API time of the final turn — the TTFT proxy on zeroed per-turn usage. */\n  duration_api_ms?: number;\n};\n\n/** Context tokens of an assistant/result usage block (input+cache+output). */\nexport function usageContextTokens(u: UsageBlock | undefined): number | null {\n  if (!u) return null;\n  const t =\n    (u.input_tokens ?? 0) +\n    (u.cache_read_input_tokens ?? 0) +\n    (u.cache_creation_input_tokens ?? 0) +\n    (u.output_tokens ?? 0);\n  return t > 0 ? t : null;\n}\n\n/** Current context fill of one assistant turn: the input side, no output. */\nexport function usageContextUsed(u: UsageBlock | undefined): number | null {\n  if (!u) return null;\n  const t = inputSideTokens(u);\n  return t > 0 ? t : null;\n}\n\n/**\n * Context never shrinks mid-segment, so the status keeps the high-water\n * mark of the usage it has seen: a smaller later reading (short reply,\n * sidechain answer) must not drag the meter down. Compaction is the one\n * legitimate drop — see `resetContextTokensOnCompact`.\n */\nexport function bumpContextTokens(status: Pick<WorkerStatus, \"contextTokens\">, tokens: number | null): void {\n  if (tokens === null || tokens <= 0) return;\n  status.contextTokens = Math.max(status.contextTokens ?? 0, tokens);\n}\n\n/**\n * A compact boundary (`system`/`compact_boundary`, the shape Claude Code\n * writes with `compactMetadata.preTokens`; `compact` kept as the older\n * spelling) legitimately restarts the context at a lower size: the floor\n * drops to the event's own usage — usually none — so the next usage\n * reading re-seeds the meter at the fresh, smaller context.\n */\nexport function resetContextTokensOnCompact(status: Pick<WorkerStatus, \"contextTokens\">, e: StreamEvent): void {\n  status.contextTokens = usageContextTokens(e.usage) ?? null;\n}\n\n/** A compact boundary in a worker's stream, in either event spelling. */\nexport function isCompactBoundary(e: StreamEvent): boolean {\n  return e.type === \"system\" && (e.subtype === \"compact_boundary\" || e.subtype === \"compact\");\n}\n\n/** The command string of a Bash tool_use input, \"\" when there is none. */\nfunction bashCommand(input: unknown): string {\n  if (typeof input === \"object\" && input !== null && typeof (input as { command?: unknown }).command === \"string\") {\n    return (input as { command: string }).command;\n  }\n  return \"\";\n}\n\nexport function toolResultText(content: unknown): string {\n  if (typeof content === \"string\") return content;\n  if (Array.isArray(content)) {\n    return content\n      .map((c) =>\n        typeof c === \"object\" && c !== null && typeof (c as { text?: unknown }).text === \"string\"\n          ? (c as { text: string }).text\n          : \"\"\n      )\n      .join(\"\\n\");\n  }\n  return \"\";\n}\n\n/**\n * Whether a tool_result block is a failed execution: the harness's own\n * is_error flag, or — the older Bash spelling — an \"Exit code N\" line with a\n * non-zero N in the result text. Feeds the consecFails counter supervision's\n * thrashing detector reads.\n */\nexport function toolResultFailed(block: { is_error?: boolean; content?: unknown }): boolean {\n  if (block.is_error === true) return true;\n  const m = toolResultText(block.content).match(/Exit code (\\d+)/);\n  return m !== null && Number(m[1]) !== 0;\n}\n\n/** CLI aliases the built-in provider hands to `--model` (NATIVE_ANTHROPIC_MODELS'\n *  values): a bare name like \"sonnet\", not a concrete id, so the init event's\n *  resolved id is always the more useful thing to display. */\nconst NATIVE_MODEL_ALIASES = new Set(Object.values(NATIVE_ANTHROPIC_MODELS));\n\n/**\n * The model the init event announces, adopted into the status when the spawn\n * could not name one (a caller that passed `--model` itself in the claude\n * args, or a provider whose table has no entry for the capability) or named\n * only a CLI alias (the built-in provider's \"sonnet\"/\"haiku\", which tracks\n * whatever release is current — the init event says which one actually ran).\n * The run's real model is then only knowable from the first event it sends.\n * Never overwrites a concrete resolved or pinned model — that stays the\n * recorded truth.\n */\nexport function adoptInitModel(status: Pick<WorkerStatus, \"model\">, e: StreamEvent): void {\n  if (status.model && !NATIVE_MODEL_ALIASES.has(status.model)) return;\n  const m = (e.model ?? \"\").trim();\n  if (m) status.model = m;\n}\n\n/**\n * The model a run goes out on: an explicit `--model` wins; else the class\n * target's alias (\"glm/fast\") names the capability; else the capability the\n * class implies (image → image model, spotcheck/simple → fast, everything\n * else → default), resolved against the provider's model table. The built-in\n * anthropic provider resolves through the same table as any other, so a\n * worker never inherits the orchestrator session's model.\n */\nexport function resolveRunModel(\n  target: { provider: WorkerProvider; modelAlias: string | null },\n  className?: string,\n  modelFlag?: string\n): string {\n  if (modelFlag) return modelFlag;\n  const alias = target.modelAlias;\n  let capability = alias && isModelCapability(alias) ? alias : classModelCapability(className);\n  // nothing named a model (no flag, no class role): the provider's worker_model decides\n  if (!alias && capability === \"default\" && target.provider.workerModel === \"fast\") capability = \"fast\";\n  return resolveModelCapability(target.provider, capability);\n}\n\n/**\n * The `--model` part of the claude argv. Skipped when the caller already\n * pinned one in the claude args (it must not be clobbered) or when nothing\n * resolved — `--model \"\"` would break the spawn.\n */\nexport function modelArgs(model: string, callerPinned: boolean): string[] {\n  return !callerPinned && model ? [\"--model\", model] : [];\n}\n\n/**\n * Two model ids name the same model when their canonical forms do: a\n * bracketed suffix is a context-window variant, not another model\n * (\"glm-5.3[1m]\" IS \"glm-5.3\", announced with a 1M window — the same\n * collision the init event's adoptInitModel sees).\n */\nexport function canonicalModelId(id: string): string {\n  return id.trim().replace(/\\[[^\\]]*\\]$/, \"\");\n}\n\nexport interface ModelStepDown {\n  /** The model id the run goes out on. */\n  model: string;\n  /** One launch-preamble line, or null when resolution is unchanged. */\n  notice: string | null;\n}\n\n/**\n * The model step-down: a worker never runs on the orchestrator's own model —\n * enforced here, not remembered (config.ts states the principle). Until\n * 2026-10-17 it was only enforced where a model id is named explicitly: with\n * no --model, the class map's default tier resolved glm's default model —\n * glm-5.3[1m], the very model the orchestrating session itself ran — and\n * nothing detected the equality. Mechanical now: when the resolved id equals\n * the orchestrating session's (detected from the environment exactly the way\n * `pai launch --list --current` does it, launch.ts's detectCurrentModel), the\n * same provider's fast model replaces it. An explicit operator --model always\n * wins, including \"use your own model\" — the runner's own flag and a --model\n * pinned in the claude args both count as explicit. A provider without a\n * distinct fast model keeps the resolved model with a warning; a run is never\n * refused over this. An undetectable orchestrator model changes nothing.\n */\nexport function stepDownOrchestratorModel(opts: {\n  resolved: string;\n  providerName: string;\n  provider: Pick<WorkerProvider, \"models\">;\n  /** Explicit --model (the runner's own flag): the operator's choice wins. */\n  modelFlag?: string;\n  /** The caller pinned --model in the claude args: also explicit. */\n  callerPinned?: boolean;\n  env?: NodeJS.ProcessEnv;\n}): ModelStepDown {\n  if (opts.modelFlag || opts.callerPinned) return { model: opts.resolved, notice: null };\n  const orchestrator = detectCurrentModel(opts.env ?? process.env);\n  if (!orchestrator) return { model: opts.resolved, notice: null };\n  if (canonicalModelId(opts.resolved) !== canonicalModelId(orchestrator)) {\n    return { model: opts.resolved, notice: null };\n  }\n  const fast = opts.provider.models.fast;\n  if (!fast || canonicalModelId(fast) === canonicalModelId(opts.resolved)) {\n    return {\n      model: opts.resolved,\n      notice:\n        `pai: worker model == orchestrator model — provider \"${opts.providerName}\" has no distinct ` +\n        `fast model, keeping ${opts.resolved} (workers never inherit the orchestrator's model)`,\n    };\n  }\n  return {\n    model: fast,\n    notice:\n      `pai: worker model == orchestrator model — stepped down to ${fast} ` +\n      `(workers never inherit the orchestrator's model); pass --model to override`,\n  };\n}\n\n/**\n * Whether the run's assembled cmd gets a forced --model. Headless workers\n * always take the resolved class/provider model — that table exists so\n * spawned subagents stay cheap. An interactive launch (`pai worker run` with\n * no -p) IS the chat pane, not a subagent: with no --model of the caller's\n * own it gets none here either, so Claude Code's own settings.json model\n * applies, exactly as launching `claude` by hand would (2026-09-20: an\n * interactive supervisor came up on the class model instead of the\n * settings.json [1m] variant, then needed a manual /model switch that\n * rebuilt the whole cache). A caller's own --model, headless or not, is\n * already in the passthrough args and must not be duplicated here.\n */\nexport function modelFlagArgs(headless: boolean, model: string, callerPinned: boolean): string[] {\n  return headless ? modelArgs(model, callerPinned) : [];\n}\n\n/**\n * The prompt text actually sent to the worker and whether the trailer got\n * appended. An instruction at the END of the user turn outweighs one buried\n * in the system prompt (measured 2026-09-20: the AG2 contract alone was\n * ignored by both Haiku and Sonnet). Never applied to an interactive launch\n * (no -p) or when the caller brought its own --append-system-prompt — the\n * trailer's \"format in system prompt\" would then point at nothing.\n */\nexport function headlessPromptText(\n  prompt: string | null,\n  headless: boolean,\n  callerSystemPrompt: boolean,\n  format: \"ag2\" | \"json\"\n): { text: string | null; applied: boolean } {\n  const applied = headless && prompt !== null && !callerSystemPrompt;\n  return { text: applied ? prompt! + promptTrailer(format) : prompt, applied };\n}\n\n/**\n * Whether an invalid final report earns the one bounded re-ask: only when a\n * real validator caught the problem (a missing/broken aibroker must never\n * block the run further), the caller did not opt out, and there is a session\n * to resume into. Cap of exactly one is enforced by the caller never calling\n * this twice for the same run.\n */\nexport function shouldRetryReport(\n  validation: { ok: boolean; validator: \"aibroker\" | \"none\" },\n  noReportRetry: boolean,\n  hasSession: boolean\n): boolean {\n  return !validation.ok && validation.validator === \"aibroker\" && !noReportRetry && hasSession;\n}\n\n/** Context window announced by the init event, when the endpoint sends one. */\n/**\n * An empty model response: the model \"answered\" without producing anything —\n * no tool ran and the result text is empty. A local model can stop at once with an empty reply;\n * it is a harness failure, not a finished run (rc 0 and a result record\n * notwithstanding). Usage plays no part: local servers report 0/0 on every\n * message, normal ones too.\n */\nexport function isEmptyResponse(resultText: string | undefined, tools: number): boolean {\n  return tools === 0 && (resultText ?? \"\").trim() === \"\";\n}\n\n/**\n * Did the run end well? A headless run must have produced a stream-json\n * result event that is not an error; an interactive launch IS the chat pane\n * and never emits one, so its clean exit (rc 0) is the whole verdict —\n * without this every interactive session that ends normally was recorded\n * as `failed rc=0` and supervision pinged the spawner about a non-failure.\n */\nexport function runSucceeded(\n  headless: boolean,\n  rc: number,\n  resultEvent: Pick<StreamEvent, \"is_error\"> | null,\n): boolean {\n  if (rc !== 0) return false;\n  if (!headless) return true;\n  return resultEvent !== null && !resultEvent.is_error;\n}\n\nexport function initContextWindow(e: StreamEvent): number | null {\n  if (typeof e.context_window === \"number\" && e.context_window > 0) return e.context_window;\n  if (e.model_info && typeof e.model_info.context_window === \"number\" && e.model_info.context_window > 0) {\n    return e.model_info.context_window;\n  }\n  // the `[1m]` model variant announces a 1M-token window by suffix\n  if (/\\[1m\\]$/.test((e.model ?? \"\").trim())) return 1_000_000;\n  return null;\n}\n\n/**\n * Run one worker. Returns the process exit code to pass through.\n * Throws WorkersConfigError-shaped Errors for configuration problems.\n */\nexport async function runWorker(opts: RunOptions): Promise<number> {\n  const { raw: _raw, workers: config } = readWorkersSection();\n  void _raw;\n  if (!config.enabled) {\n    throw new Error(\n      `workers are off. Turn them on with: pai worker on` +\n        `\\n(then the Agent-tool hook stops denying Anthropic subagents only when you do)`\n    );\n  }\n  const logDir = workersLogDir(config);\n  mkdirSync(logDir, { recursive: true });\n  try {\n    const gc = gcWorktreesThrottled(logDir)?.filter((r) => r.archive);\n    if (gc?.length) process.stderr.write(`pai worker: archived ${gc.length} leftover worktree(s) (pai worker gc)\\n`);\n  } catch {\n    // best effort\n  }\n\n  // class plan is not one worker but the planner orchestration (planner.ts)\n  if (opts.className === \"plan\" && !opts._planner) {\n    const { runPlanner } = await import(\"./planner.js\");\n    return runPlanner(opts);\n  }\n\n  // Sub-worker bookkeeping: an explicit parent (chain stage, planner child)\n  // wins, else the worker this process runs inside (PAI_WORKER_ID). Both\n  // caps from workers.tree apply to parents that are workers themselves.\n  const parent = launchParent(opts.parent);\n  if (parent) assertChildAllowed(logDir, parent, config.tree);\n\n  // An explicit --provider always bypasses capability resolution entirely;\n  // otherwise --capability, or a class whose implied capability is not\n  // \"default\" and names no provider of its own, resolves cross-provider.\n  const capability = opts.providerFlag\n    ? null\n    : capabilityForRun(config, { capabilityFlag: opts.capabilityFlag, className: opts.className });\n  const capabilityResolution: CapabilityRunResolution | null = capability\n    ? resolveCapabilityRun(config, capability)\n    : null;\n\n  // Worker routing policy (policy.ts): picks local or cloud unless the caller named a provider.\n  let route = opts._route;\n  let providerFlag = opts.providerFlag;\n  // The route reason names the real source: only a --provider the caller\n  // actually typed says \"flag: --provider\"; --local says \"(local)\", a\n  // routing-policy pin says \"(routing policy: <mode>)\" — like the session\n  // profile case below.\n  let providerWhy: string | undefined = opts.providerFlag ? \"flag: --provider\" : undefined;\n  // --local: PAI resolves the running local server itself (local-provider.ts);\n  // the resolved name wins over --provider — a provider literally named\n  // \"local\" is not the mechanism.\n  if (opts.localFlag) {\n    try {\n      const res = await resolveLocalProvider(config, logDir);\n      providerFlag = res.name;\n      providerWhy = \"local\";\n      if (!opts.quiet) process.stderr.write(`pai worker: local provider ${res.name} (${res.why})\\n`);\n    } catch (e) {\n      // --print-cmd is a dry run: nothing must answer a port for the argv\n      // audit, so an unresolved local pin falls back to the first configured\n      // loopback provider and the route line still says (local). A real run\n      // keeps the hard error — nothing spawns onto a server that is down.\n      if (!(opts.printCmd && e instanceof NoLocalServerError)) throw e;\n      const first = Object.entries(config.providers).find(\n        ([, p]) => p.enabled && isLoopbackProvider(p)\n      );\n      if (!first) throw e;\n      providerFlag = first[0];\n      providerWhy = \"local\";\n      if (!opts.quiet) process.stderr.write(`pai worker: local provider ${first[0]} (dry run: no local server up)\\n`);\n    }\n  }\n  // The session's profile (workers, budget fallback) comes before routing; an explicit provider/--local skipped it above.\n  let profileModel: string | undefined;\n  if (!providerFlag && !capability && !route && (await detectSessionName())) {\n    const r = resolveWorkers(\n      { explicit: { model: opts.modelFlag ?? (opts.modelFast ? \"fast\" : opts.modelDefault ? \"default\" : undefined) }, batch: isBatchEnv() },\n      await liveResolveCtx()\n    );\n    if (r.source === \"none\") throw new NoProviderError(r.description);\n    if (r.provider && (r.source === \"profile\" || r.source === \"fallback\")) {\n      providerFlag = r.provider;\n      profileModel = r.model;\n      providerWhy = r.source === \"fallback\" ? \"session profile fallback\" : \"session profile\";\n      if (!opts.quiet) process.stderr.write(`pai worker: ${r.description}\\n`);\n    }\n  }\n  if (!route && !providerFlag && !capability && opts.className !== \"plan\" && parseRunnerArgs(opts.claudeArgs).headless) {\n    const routed = await routeRun(config, logDir, opts);\n    if (routed) {\n      route = routed.route;\n      providerFlag = routed.providerFlag ?? undefined;\n      if (providerFlag) providerWhy = `routing policy: ${route.policy}`;\n    }\n  }\n\n  // Budget-aware fallback: probe live budgets (5-min cache) and cooldown any\n  // provider at/above its wall before the walk, so resolveTarget picks the\n  // first priority provider that still has room. Probing must never block a\n  // spawn: failures read as \"unknown\" inside the cache, never as \"full\".\n  if (!providerFlag && !capabilityResolution && config.routing.policy !== \"order\") {\n    try {\n      await budgetCache.warm(config);\n      recordBudgetCooldowns(config, logDir);\n    } catch {\n      /* no readings: budget routing degrades to plain order */\n    }\n  }\n\n  const target = capabilityResolution\n    ? {\n        providerName: capabilityResolution.providerName,\n        provider: capabilityResolution.provider,\n        modelAlias: null,\n        classMcp: null,\n        via: \"class\" as const,\n      }\n    : resolveTarget(config, logDir, {\n        flagProvider: providerFlag,\n        className: opts.className,\n        cwd: opts.cwd,\n      });\n  assertProviderRunnable(target.providerName, target.provider);\n  if (opts.modelFast && !opts.modelFlag) target.modelAlias = \"fast\";\n  if (opts.modelDefault && !opts.modelFlag) target.modelAlias = \"default\";\n  const modelFlag = opts.modelFlag ?? (profileModel && profileModel !== \"fast\" && profileModel !== \"default\" ? profileModel : undefined);\n  if (profileModel === \"fast\" && !opts.modelFlag) target.modelAlias = \"fast\";\n  if (profileModel === \"default\" && !opts.modelFlag) target.modelAlias = \"default\";\n\n  const noBrowser = opts.browser === undefined ? config.noBrowserByDefault : !opts.browser;\n  const parsed = parseRunnerArgs(noBrowser ? stripBrowserArgs(opts.claudeArgs) : opts.claudeArgs);\n  // The config default is a headless-run guard; an interactive launch is the operator's own session and is\n  // limited only by an explicit --max-minutes / --deadline.\n  const limit = resolveLimit(opts, parsed.headless ? config.defaultMaxMinutes : 0);\n  const label =\n    opts.label ??\n    shortText(parsed.prompt ?? UNLABELED, 70);\n\n  let model = capabilityResolution\n    ? capabilityResolution.model\n    : resolveRunModel(target, opts.className, modelFlag);\n  if (!capabilityResolution) {\n    // capability runs pin their model on purpose (an image prompt on the\n    // image model); the step-down guards the class/provider resolution only\n    const step = stepDownOrchestratorModel({\n      resolved: model,\n      providerName: target.providerName,\n      provider: target.provider,\n      modelFlag,\n      callerPinned: parsed.callerModel,\n    });\n    model = step.model;\n    if (step.notice && !opts.quiet) process.stderr.write(`${step.notice}\\n`);\n  }\n  const reportFormat = resolveReportFormat(opts.reportFormatFlag);\n  // the route and why, once (also recorded in the status as routeWhy)\n  const routeReason = target.via === \"flag\" && providerWhy ? providerWhy : target.routeWhy;\n  const routeWhy = routeReason ? `${target.providerName}/${model} (${routeReason})` : undefined;\n  if (routeWhy && !opts.quiet) process.stderr.write(`pai worker: route ${routeWhy}\\n`);\n\n  // tracked across every engine (including a quota reroute's recursive\n  // runWorker call) so the exit hook below knows which status to check,\n  // whatever opts.id/onWorkerStart the caller did or didn't pass\n  let workerId: string | undefined = opts.id;\n  const trackStart = (wid: string) => {\n    workerId = wid;\n    opts.onWorkerStart?.(wid);\n  };\n\n  try {\n    let rc: number;\n    if (target.provider.engine === \"image\") {\n      rc = await executeImageRun({\n        config,\n        logDir,\n        target,\n        model,\n        label,\n        parsed,\n        capability: capability ?? \"image\",\n        outPath: opts.imageOut,\n        size: opts.imageSize,\n        timeoutMs: opts.imageTimeoutMs,\n        cwd: opts.cwd,\n        specPath: opts.specPath,\n        parent: parent ?? undefined,\n        stage: opts.stage,\n        quiet: opts.quiet,\n        onWorkerStart: trackStart,\n        id: opts.id,\n      });\n    } else if (target.provider.engine === \"codex\") {\n      rc = await executeCodexRun({\n        config,\n        logDir,\n        target,\n        model,\n        label,\n        parsed,\n        claudeArgs: opts.claudeArgs,\n        noPane: opts.noPane ?? false,\n        cwd: opts.cwd,\n        specPath: opts.specPath,\n        parent: parent ?? undefined,\n        stage: opts.stage,\n        quiet: opts.quiet,\n        onWorkerStart: trackStart,\n        id: opts.id,\n        worktreeFlag: opts.worktreeFlag,\n        className: opts.className,\n        reportFormat,\n        capability: capability ?? undefined,\n        limit,\n        noBrowser,\n      });\n    } else {\n      const execArgs: ExecuteArgs = {\n        config,\n        logDir,\n        target,\n        model,\n        label,\n        parsed,\n        claudeArgs: opts.claudeArgs,\n        noPane: opts.noPane ?? false,\n        noStagger: opts.noStagger,\n        noQueue: opts.noQueue,\n        priority: opts.priority,\n        mcpFlag: opts.mcpFlag,\n        cwd: opts.cwd,\n        specPath: opts.specPath,\n        parent: parent ?? undefined,\n        stage: opts.stage,\n        quiet: opts.quiet,\n        onWorkerStart: trackStart,\n        id: opts.id,\n        capability: capability ?? undefined,\n        worktreeFlag: opts.worktreeFlag,\n        resumeOf: opts.resumeOf,\n        className: opts.className,\n        reroutes: opts._reroutes ?? 0,\n        emptyRetried: opts._emptyRetried ?? false,\n        route,\n        routeWhy,\n        fallThroughOf: opts._fallThroughOf,\n        printCmd: opts.printCmd,\n        reportFormat,\n        noReportRetry: opts.noReportRetry ?? false,\n        orchestrate: opts.orchestrate,\n        limit,\n        noBrowser,\n        opts,\n      };\n      // the session pool (workers.pool) gets first crack: an eligible task\n      // runs as one more turn of a warm claude instead of a fresh spawn\n      await gateStart(execArgs);\n      const pooledRc = await tryPoolRun(execArgs);\n      if (pooledRc !== null) {\n        await returnControlsIfHeld(logDir, workerId);\n        return pooledRc;\n      }\n      rc = await executeRun(execArgs);\n    }\n    await returnControlsIfHeld(logDir, workerId);\n    return rc;\n  } catch (e) {\n    await returnControlsIfHeld(logDir, workerId);\n    if (e instanceof Error && e.message.startsWith(\"key file\")) {\n      throw new Error(\n        `provider \"${target.providerName}\": ${e.message}` +\n          `\\nPut the token in that file (chmod 600) or point keyFile elsewhere.`\n      );\n    }\n    throw e;\n  }\n}\n\n/**\n * The core tools a headless run grants when the caller brings none of its\n * own. Permission-gated tools (Bash, Read, Write, …) are never offered to a\n * headless session that has no allow rule for them — the child starts with\n * only the tools that never ask (tool search, web, cron, tasks) and cannot\n * touch a file or shell (2026-09-18). A caller's own --allowedTools is a\n * deliberate restriction and passes through untouched.\n */\nexport const DEFAULT_WORKER_TOOLS = \"Read,Edit,Write,Bash,Grep,Glob\";\n\n/** The --allowedTools args a headless run needs; [] when the caller granted. */\nexport function headlessToolGrants(allowedTools: string[]): string[] {\n  return allowedTools.length ? [] : [\"--allowedTools\", DEFAULT_WORKER_TOOLS];\n}\n\n/**\n * `--tools` narrows which built-in tool *schemas* claude loads into the\n * system prompt — distinct from `--allowedTools`, which narrows which of\n * those loaded tools may run without asking. A headless worker with a small\n * grant (say, just Read) still pays for every built-in schema (Bash, Web*,\n * NotebookEdit, …) it never uses: ~9k tokens per spawn (29,270 -> 20,352,\n * measured 2026-09-20). Passing --tools built from the same grant removes\n * the unused schemas.\n *\n * MCP grants (`mcp__server__tool` / `mcp__server__*`) are left out of the\n * --tools list: they are not built-in tool names, --tools does not\n * recognize them, and the MCP server's tools load through --mcp-config\n * regardless. Tested 2026-09-20: with an --allowedTools grant of\n * `Read,mcp__pai__memory_search`, passing `--tools Read` (mcp name\n * omitted) still let the worker call memory_search successfully; the tool\n * loads from the filtered MCP config, not from --tools.\n */\nexport function headlessToolsFlag(allowedTools: string[]): string[] {\n  const names: string[] = [];\n  for (const entry of allowedTools) {\n    for (const raw of entry.split(\",\").map((s) => s.trim()).filter(Boolean)) {\n      if (raw.startsWith(\"mcp__\")) continue; // loads via --mcp-config, not --tools\n      const patterned = raw.match(/^([A-Za-z]+)\\(.*\\)$/); // e.g. Bash(git *) -> Bash\n      const name = patterned ? patterned[1] : raw;\n      if (!names.includes(name)) names.push(name);\n    }\n  }\n  return names.length ? [\"--tools\", names.join(\",\")] : [];\n}\n\n/**\n * A `--tools` value with no ToolSearch silently disables MCP tool deferral\n * (measured 2026-09-20: a run with `--tools \"Bash,Read,Grep,Glob,Agent\"` paid\n * 65,300 first-turn tokens with 5 MCP servers, 230,448 with 16, versus\n * 24,889 / 37,133 with ToolSearch present). Applied to the fully-assembled\n * argv so it catches a `--tools` from any source — the computed\n * `headlessToolsFlag`/project-pin flag, or one the caller put directly on\n * the command line.\n */\nexport function ensureToolSearch(cmd: string[]): string[] {\n  const flagIdx = cmd.findIndex((a) => a === \"--tools\");\n  if (flagIdx >= 0 && flagIdx + 1 < cmd.length) {\n    const value = cmd[flagIdx + 1];\n    if (value && !value.split(\",\").includes(\"ToolSearch\")) {\n      const out = [...cmd];\n      out[flagIdx + 1] = `${value},ToolSearch`;\n      process.stderr.write(\"pai: added ToolSearch to --tools (keeps MCP tool deferral on)\\n\");\n      return out;\n    }\n    return cmd;\n  }\n  const eqIdx = cmd.findIndex((a) => a.startsWith(\"--tools=\"));\n  if (eqIdx >= 0) {\n    const value = cmd[eqIdx].slice(\"--tools=\".length);\n    if (value && !value.split(\",\").includes(\"ToolSearch\")) {\n      const out = [...cmd];\n      out[eqIdx] = `--tools=${value},ToolSearch`;\n      process.stderr.write(\"pai: added ToolSearch to --tools (keeps MCP tool deferral on)\\n\");\n      return out;\n    }\n  }\n  return cmd;\n}\n\n/**\n * The claude flag that turns on the browser bridge, when the run asked for it.\n *\n * The bridge is not an MCP server — it rides the Chrome native-host channel,\n * is absent from `mcpServers`, and is off in a spawned claude until `--chrome`\n * is passed. A grant such as `mcp__claude-in-chrome__tabs_context_mcp` is\n * therefore a request for that flag, not for a server to load; without this\n * the grant names a tool that never exists. `rest` is the caller's own argv:\n * a `--chrome` they passed themselves is kept rather than duplicated.\n */\nexport function chromeGrantArgs(wanted: string[], rest: string[] = []): string[] {\n  if (rest.includes(\"--chrome\")) return [];\n  return grantsChrome(wanted) ? [\"--chrome\"] : [];\n}\n\n/**\n * Which MCP server names and --tools list an interactive launch (`pai\n * worker run`, no -p) uses: an explicit --mcp on this command line beats\n * the project's `pai project mcp` pin; an explicit --tools beats `pai\n * project tools`. Neither given: [] — today's \"everything loads\" default.\n */\nexport function interactiveMcpTools(\n  explicitMcp: string[],\n  callerTools: boolean,\n  projectLaunch: Omit<ProjectLaunchConfig, \"slug\"> | null\n): { mcpNames: string[]; tools: string[] } {\n  return {\n    mcpNames: explicitMcp.length ? explicitMcp : (projectLaunch?.mcp ?? []),\n    tools: !callerTools && projectLaunch?.tools?.length ? projectLaunch.tools : [],\n  };\n}\n\n// ---------------------------------------------------------------------------\n// image engine (2i) — no process spawn: one HTTP request, one file written.\n// ---------------------------------------------------------------------------\n\ninterface ImageExecuteArgs {\n  logDir: string;\n  target: ReturnType<typeof resolveTarget>;\n  model: string;\n  label: string;\n  parsed: ReturnType<typeof parseRunnerArgs>;\n  capability: string;\n  outPath?: string;\n  size?: string;\n  timeoutMs?: number;\n  cwd?: string;\n  specPath?: string;\n  parent?: string;\n  stage?: string;\n  quiet?: boolean;\n  onWorkerStart?: (wid: string) => void;\n  id?: string;\n}\n\ninterface FinaliseArgs {\n  logDir: string;\n  ledger: string;\n  status: WorkerStatus;\n  /** The process's real outcome; recordWorktree sees this, never the orphan verdict. */\n  ok: boolean;\n  rc: number;\n  secs: number;\n  /** Engine-specific WORKER-END fields (provider, mode, engine, model, label, ...). */\n  end: Record<string, unknown>;\n  report: WorkerReport | null;\n  /** Handoff text when the report has no notes. */\n  fallbackText?: string;\n  worktree?: WorktreeInfo | null;\n  /** The deadline stopped the run after this many minutes. */\n  timedOut?: number;\n  /**\n   * Runs after the worktree outcome is recorded, before the parent handoff\n   * (print the result, quota reroute). A returned number ends the run with\n   * it, skipping the handoff — the reroute's own run reports instead.\n   */\n  beforeHandoff?: (status: WorkerStatus, report: WorkerReport | null) => Promise<number | void> | number | void;\n}\n\n/**\n * The finalisation every engine shares: orphaned-children check, state, the\n * WORKER-END ledger line, worktree outcome, parent handoff, final rc. A worker\n * owns its children's results (the worker contract says so): if it\n * backgrounded a sub-worker and exited without waiting, the run must not\n * report success, whatever the process returned.\n */\n/** Per-git-call bound for the salvage a kill signal runs before exiting. */\nconst SIGNAL_SALVAGE_MS = 5_000;\n\n/** The deadline fired: record it on the status and in the ledger (the caller then stops the child). */\nexport function fireDeadline(logDir: string, status: WorkerStatus, ledger: string, limit: RunLimit): void {\n  status.timedOut = true;\n  status.last = `deadline reached after ${limit.minutes} min`;\n  saveStatus(logDir, status);\n  appendLedger(ledger, \"WORKER-DEADLINE\", { id: status.id, minutes: limit.minutes });\n  // the deadline stops the run's own process; its sub-workers go with it\n  void killTree(logDir, status.id, { skipRoot: true }).catch(() => undefined);\n}\n\n/** Decide why a signal ended the run and put it on the status; the caller writes WORKER-END. */\nexport function recordSignalEnd(logDir: string, status: WorkerStatus, signal: string): EndInfo {\n  const end = decideEndReason({\n    logDir,\n    id: status.id,\n    signal,\n    timedOut: status.timedOut,\n    parentPid: status.parentPid,\n    parentComm: status.parentComm,\n    parentBackground: status.parentBackground,\n  });\n  status.endReason = end.reason;\n  status.endBy = end.by;\n  status.endNote = end.note;\n  return end;\n}\n\nexport async function finaliseRun(f: FinaliseArgs): Promise<number> {\n  const { logDir, ledger, ok, rc } = f;\n  let { status, report } = f;\n  const wid = status.id;\n  // first, whatever the outcome (rc 143 included): uncommitted edits in the\n  // worktree must reach the branch before anything can drop the worktree\n  const salvaged = f.worktree\n    ? salvageOnExit(ledger, wid, status.label || UNLABELED, f.worktree.dir)\n    : [];\n  if (salvaged.length) {\n    const msg = `WORKER-SALVAGE: committed uncommitted edits (${salvaged.join(\", \")})`;\n    report = { ...(report ?? {}), notes: [report?.notes ?? f.fallbackText, msg].filter(Boolean).join(\"\\n\"), result: report?.result ?? \"-\" };\n  }\n  if (f.timedOut) {\n    const reason = `deadline reached after ${f.timedOut} min`;\n    status.timedOut = true;\n    status.last = reason;\n    // partial state = the salvage summary (r=~: stopped, not failed outright)\n    report = { ...(report ?? {}), result: \"~\", why: reason, notes: [reason, report?.notes ?? f.fallbackText].filter(Boolean).join(\"\\n\") };\n  }\n  const loopStop = takeLoopStop(logDir, wid);\n  if (loopStop) {\n    const reason = `loop-stopped: ${loopStop.reason}`;\n    status.loopStopped = true;\n    status.last = shortText(reason, 90);\n    report = { ...(report ?? {}), result: \"-\", why: reason, notes: [reason, report?.notes ?? f.fallbackText].filter(Boolean).join(\"\\n\") };\n  }\n  const orphanReason = checkOrphanedChildren(logDir, wid);\n  const succeeded = ok && !orphanReason && !f.timedOut && !loopStop;\n  status.state = succeeded ? \"done\" : \"failed\";\n  status.rc = rc;\n  status.secs = f.secs;\n  if (orphanReason) {\n    status.last = shortText(orphanReason, 90);\n    report = { ...(report ?? {}), notes: orphanReason, result: \"-\" };\n    appendLedger(ledger, \"WORKER-ORPHAN-CHILDREN\", { id: wid, reason: orphanReason });\n  }\n  const end = decideEndReason({ logDir, id: wid, timedOut: f.timedOut !== undefined, loopStopped: !!loopStop });\n  status.endReason = end.reason;\n  // r=~ (partial) means the work continues: saveStatus then keeps the issue claims\n  status.claimsContinue = report?.result === \"~\";\n  saveStatus(logDir, status);\n  appendLedger(ledger, \"WORKER-END\", { id: wid, ...f.end, rc, secs: f.secs, ...endFields(end) });\n\n  if (f.worktree) status = recordWorktree(logDir, status, f.worktree, ok);\n\n  const early = await f.beforeHandoff?.(status, report);\n  if (typeof early === \"number\") return early;\n\n  const finalRc = rc !== 0 ? rc : succeeded ? 0 : 1;\n  if (status.parent && isWorkerId(logDir, status.parent)) {\n    try {\n      await deliverHandoff(logDir, {\n        from: wid,\n        to: status.parent,\n        kind: \"result\",\n        text: shortText(report?.notes ?? f.fallbackText ?? (succeeded ? \"done\" : \"failed\"), 400),\n        data: {\n          rc: finalRc,\n          ok: succeeded,\n          ...(status.branch ? { branch: status.branch, commits: status.commits ?? 0 } : {}),\n          ...(report ? { report } : {}),\n        },\n      });\n    } catch {\n      // the inbox line is best effort; it must never fail the exit path\n    }\n  }\n  return finalRc;\n}\n\nasync function executeImageRun(a: ImageExecuteArgs & { config: ReturnType<typeof readWorkersSection>[\"workers\"] }): Promise<number> {\n  const { logDir, target, model, label, parsed } = a;\n  if (!parsed.headless || parsed.prompt === null) {\n    throw new Error(\n      `provider \"${target.providerName}\" (engine image) supports headless runs only: ` +\n        `pass the task with -p '<prompt>'`\n    );\n  }\n  const wid = a.id ?? newWorkerId();\n  const cwd = a.cwd ?? process.cwd();\n  const term = process.env.ITERM_SESSION_ID ?? \"\";\n  const outPath = a.outPath ?? join(logDir, `${wid}.png`);\n\n  const status: WorkerStatus = {\n    id: wid,\n    pid: process.pid,\n    runPid: process.pid,\n    label,\n    cwd,\n    term,\n    provider: target.providerName,\n    model,\n    state: \"running\",\n    started: nowStamp(),\n    updated: nowStamp(),\n    turns: 0,\n    tools: 0,\n    last: \"generating image\",\n    rc: null,\n    secs: null,\n    origin: \"spawn\",\n    outputFormat: parsed.outputFormat,\n    reportFormat: \"json\",\n    ...(a.parent ? { parent: a.parent, stage: a.stage } : {}),\n    ...(a.specPath ? { spec: a.specPath } : {}),\n  };\n  saveStatus(logDir, status);\n  a.onWorkerStart?.(wid);\n  const ledger = ledgerPath(logDir);\n  appendLedger(ledger, \"WORKER-START\", {\n    id: wid,\n    provider: target.providerName,\n    mode: \"headless\",\n    engine: \"image\",\n    model,\n    cwd,\n    label,\n    capability: a.capability,\n    ...(a.specPath ? { spec: a.specPath } : {}),\n  });\n\n  const imageEnd = {\n    provider: target.providerName,\n    mode: \"headless\",\n    engine: \"image\",\n    model,\n    label,\n    capability: a.capability,\n  };\n  const t0 = Date.now();\n  try {\n    const result = await runImageCapability({\n      providerName: target.providerName,\n      provider: target.provider,\n      model,\n      prompt: parsed.prompt,\n      outPath,\n      size: a.size,\n      timeoutMs: a.timeoutMs,\n    });\n    const secs = Math.round((Date.now() - t0) / 1000);\n    status.last = `wrote ${result.path}`;\n    return await finaliseRun({\n      logDir,\n      ledger,\n      status,\n      ok: true,\n      rc: 0,\n      secs,\n      end: imageEnd,\n      report: null,\n      beforeHandoff: () => {\n        if (!a.quiet) process.stdout.write(JSON.stringify(result) + \"\\n\");\n      },\n    });\n  } catch (e) {\n    const secs = Math.round((Date.now() - t0) / 1000);\n    status.last = e instanceof Error ? e.message : String(e);\n    await finaliseRun({ logDir, ledger, status, ok: false, rc: 1, secs, end: imageEnd, report: null });\n    throw e;\n  }\n}\n\n/**\n * The fail-closed pane gate: a headless run proceeds only behind a pane that\n * was opened and verified visible (see openVerifiedPane). Runs BEFORE the\n * worker has an id on disk, so a refusal leaves nothing in `pai worker ps`.\n *\n * Deterministic (no hidden workers): the ONLY skips are headlessAllowed() —\n * a worker's own child (PAI_WORKER=1), the operator's PAI_WORKER_ALLOW_HIDDEN=1\n * or their override file. `dryRun` (--print-cmd audits) skips too: it spawns\n * nothing. An explicit hidden request (noPane from a daemon, keepalive or an\n * in-process caller) without that consent is refused, not silently honoured —\n * a spawning session with no window (daemon) has no pane to attach to and\n * cannot run workers.\n */\nexport async function requireVisiblePane(\n  logDir: string,\n  config: ReturnType<typeof readWorkersSection>[\"workers\"],\n  wid: string,\n  term: string,\n  noPane: boolean,\n  dryRun: boolean,\n  ledger: string\n): Promise<boolean> {\n  if (dryRun) return false;\n  const allow = headlessAllowed();\n  if (allow) {\n    process.stderr.write(`[pai worker] hidden run allowed for ${wid}: ${allow}\\n`);\n    return false;\n  }\n  const how = `hidden runs need the operator's ${ALLOW_HIDDEN_ENV}=1 or ${headlessOverridePath()}`;\n  if (noPane) {\n    appendLedger(ledger, \"WORKER-REFUSED\", { id: wid, reason: `headless requested, no override (${how})`.slice(0, 300) });\n    throw new Error(`worker not started, no visible pane: headless requested but nothing may run hidden (${how})`);\n  }\n  try {\n    const where = await openVerifiedPane(logDir, config, wid, term);\n    process.stderr.write(`[pai worker] pane verified for ${wid}: ${where}\\n`);\n    return true;\n  } catch (e) {\n    const reason = e instanceof Error ? e.message : String(e);\n    appendLedger(ledger, \"WORKER-REFUSED\", { id: wid, reason: `${reason} (${how})`.slice(0, 300) });\n    throw new Error(`worker not started, no visible pane: ${reason} (${how})`);\n  }\n}\n\n/** status.last for a claude start that died before any model event: its stderr, not a bare \"starting\". */\nexport function preEventFailure(rc: number, turns: number, stderrTail: string): string | null {\n  if (rc === 0 || turns > 0 || !stderrTail.trim()) return null;\n  return \"failed before any model event: \" + shortText(stderrTail, 150);\n}\n\n/**\n * Follow pane, made observable on stderr (stdout stays pure JSON for\n * `--output-format json`): one line naming the outcome — opened, skipped\n * (with reason), or failed (with reason, alongside the existing PANE-FAIL\n * ledger line). Fire-and-forget, never blocks the worker.\n */\nexport async function announcePane(\n  logDir: string,\n  config: ReturnType<typeof readWorkersSection>[\"workers\"],\n  wid: string,\n  term: string,\n  noPane: boolean,\n  ledger: string,\n  status?: WorkerStatus\n): Promise<void> {\n  const setPane = (p: NonNullable<WorkerStatus[\"pane\"]>): void => {\n    if (status) status.pane = p;\n  };\n  const skip = !noPane\n    ? !config.pane.enabled\n      ? \"workers.pane.enabled is false\"\n      : process.env.PAI_WORKER_AUTOPANE === \"0\"\n        ? \"PAI_WORKER_AUTOPANE=0\"\n        : paneBackend(process.env, process.platform, term) === \"none\"\n          ? \"no tmux ($TMUX) or iTerm2 (ITERM_SESSION_ID) here\"\n          : null\n    : \"--no-pane\";\n  if (skip) {\n    process.stderr.write(`[pai worker] no pane for ${wid}: ${skip}\\n`);\n    setPane({ opened: false, reason: skip });\n    return;\n  }\n  try {\n    const r = await openPaneForWorker(logDir, config, wid, term);\n    const suffix = r.session ? ` (iTerm session ${r.session})` : \"\";\n    process.stderr.write(`[pai worker] pane opened for ${wid}${suffix}\\n`);\n    setPane({ opened: true, ...(r.session ? { session: r.session } : {}) });\n  } catch (e) {\n    const message = e instanceof Error ? e.message : String(e);\n    process.stderr.write(`[pai worker] no pane for ${wid}: ${message.slice(0, 200)}\\n`);\n    appendLedger(ledger, \"PANE-FAIL\", { id: wid, error: message.slice(0, 200) });\n    setPane({ opened: false, reason: message.slice(0, 200) });\n  }\n}\n\nexport interface ExecuteArgs {\n  /** capacity + stagger gates already passed (set by gateStart) */\n  gated?: boolean;\n  config: ReturnType<typeof readWorkersSection>[\"workers\"];\n  logDir: string;\n  target: ReturnType<typeof resolveTarget>;\n  model: string;\n  label: string;\n  parsed: ReturnType<typeof parseRunnerArgs>;\n  claudeArgs: string[];\n  noPane: boolean;\n  noStagger?: boolean;\n  noQueue?: boolean;\n  priority?: \"front\";\n  mcpFlag?: string;\n  cwd?: string;\n  specPath?: string;\n  parent?: string;\n  stage?: string;\n  quiet?: boolean;\n  onWorkerStart?: (wid: string) => void;\n  id?: string;\n  worktreeFlag?: boolean;\n  resumeOf?: string;\n  className?: string;\n  reroutes: number;\n  emptyRetried?: boolean;\n  route?: RouteInfo;\n  fallThroughOf?: string;\n  printCmd?: boolean;\n  /** \"provider/model (why)\" — one line on how the provider was chosen. */\n  routeWhy?: string;\n  reportFormat: \"json\" | \"ag2\";\n  noReportRetry?: boolean;\n  /** --orchestrate: PAI_WORKER_ORCHESTRATOR=1 in the env and the orchestrator addendum in the contract. */\n  orchestrate?: boolean;\n  /** Capability name this run resolved through (--capability, or an implied class capability), when it did. */\n  capability?: string;\n  /** Time limit of the run; null = none. */\n  limit: RunLimit | null;\n  /** Browser tools are stripped from this run (and denied by the worker guard). */\n  noBrowser: boolean;\n  /** The options this run was launched with; a relaunch starts from these (see relaunchOptions). */\n  opts: RunOptions;\n  /** Set once the follow pane was handled (tryPoolRun); executeRun then neither opens nor verifies a second one. */\n  panePrepared?: { verified: boolean };\n}\n\n/**\n * The worker session pool attempt (src/workers/pool.ts), behind\n * workers.pool.enabled: an eligible headless task is shipped to the pool\n * host and runs as the next user turn of a warm claude slot, so the\n * provider prompt cache carries over. Returns the exit code when the task\n * ran pooled; null sends the caller down the normal fresh-spawn path (host\n * unreachable, or the task needs a setup a slot cannot provide — worktree on a non-loopback provider,\n * own system prompt, MCP, another cwd, native Anthropic).\n */\nexport async function tryPoolRun(a: ExecuteArgs): Promise<number | null> {\n  const settings = poolSettings(a.config);\n  if (!settings.enabled || a.orchestrate) return null; // an orchestrator needs its own env and contract, not a warm slot\n  const cwd = a.cwd ?? process.cwd();\n  const reason = poolIneligibleReason({\n    headless: a.parsed.headless,\n    prompt: a.parsed.prompt,\n    providerName: a.target.providerName,\n    provider: a.target.provider,\n    nativeAllowed: settings.native,\n    worktreeWanted:\n      a.parsed.headless && !a.printCmd && worktreeWanted(a.worktreeFlag, { cwd, allowedTools: a.parsed.allowedTools }),\n    slotWorktree: isLoopbackProvider(a.target.provider),\n    resumeOf: a.resumeOf,\n    printCmd: a.printCmd,\n    parsed: a.parsed,\n    mcpFlag: a.mcpFlag,\n    noBrowser: a.noBrowser,\n    outputFormat: a.parsed.outputFormat,\n    cwd,\n  });\n  if (reason) {\n    appendLedger(ledgerPath(a.logDir), \"WORKER-POOL-SKIP\", {\n      id: a.id ?? \"-\",\n      provider: a.target.providerName,\n      reason,\n    });\n    if (!a.quiet) process.stderr.write(`[pai worker] pool: not pooled (${reason}) — spawning fresh\\n`);\n    return null;\n  }\n  const wid = a.id ?? newWorkerId();\n  // same follow pane as a fresh spawn, once per run: a decline falls back to executeRun, which reuses this\n  if (!a.panePrepared) {\n    const term = (await resolveHostSession()).term;\n    const ledger = ledgerPath(a.logDir);\n    const verified = await requireVisiblePane(a.logDir, a.config, wid, term, a.noPane, false, ledger);\n    a.panePrepared = { verified };\n    const status = loadStatus(a.logDir, wid);\n    if (status) {\n      if (verified) status.pane = { opened: true, placement: panePlacement(wid) };\n      else await announcePane(a.logDir, a.config, wid, term, a.noPane, ledger, status);\n      saveStatus(a.logDir, status);\n    } else if (!verified) {\n      await announcePane(a.logDir, a.config, wid, term, a.noPane, ledger);\n    }\n  }\n  const limitMinutes = a.limit && a.limit.minutes > 0 ? a.limit.minutes : null;\n  // the socket bounds connect+send only; the answer takes as long as the task\n  const timeoutMs = limitMinutes ? limitMinutes * 2 * 60_000 + 120_000 : 7_200_000;\n  let resp: PoolTaskResponse | null;\n  try {\n    resp = await postTaskToPool(\n      settings.port,\n      {\n        id: wid,\n        label: a.label,\n        prompt: a.parsed.prompt ?? \"\",\n        provider: a.target.providerName,\n        model: a.model,\n        cwd,\n        className: a.className,\n        capability: a.capability,\n        specPath: a.specPath,\n        parent: a.parent,\n        stage: a.stage,\n        clientPid: process.pid,\n        reportFormat: a.reportFormat,\n        outputFormat: a.parsed.outputFormat === \"json\" ? \"json\" : \"text\",\n        maxMinutes: limitMinutes,\n        trailer: promptTrailer(a.reportFormat),\n        worktree: a.parsed.headless && !a.printCmd && worktreeWanted(a.worktreeFlag, { cwd, allowedTools: a.parsed.allowedTools }),\n      },\n      timeoutMs\n    );\n  } catch {\n    resp = null;\n  }\n  if (resp === null) {\n    process.stderr.write(`[pai worker] pool: host unreachable on port ${settings.port} — spawning fresh\\n`);\n    return null;\n  }\n  if (!resp.pooled) {\n    appendLedger(ledgerPath(a.logDir), \"WORKER-POOL-SKIP\", {\n      id: a.id ?? \"-\",\n      provider: a.target.providerName,\n      reason: resp.reason ?? \"refused\",\n    });\n    if (!a.quiet) process.stderr.write(`[pai worker] pool: not pooled (${resp.reason ?? \"refused\"}) — spawning fresh\\n`);\n    return null;\n  }\n  a.onWorkerStart?.(wid);\n  const rc = resp.rc ?? 1;\n  if (!a.quiet) {\n    printResult(a.parsed.outputFormat, resp.resultEvent ?? null, rc, a.logDir, wid, resp.report);\n  }\n  return rc;\n}\n\n/**\n * Capacity gate, then stagger gate, for one headless run — the single place\n * both the pooled and the fresh-spawn path pass through. `status` is the\n * run's saved status; its capacity/warmup/last fields carry the queue line.\n */\nasync function runGates(a: ExecuteArgs, wid: string, status: WorkerStatus): Promise<void> {\n  const { logDir, target, config } = a;\n  const saved = status.last;\n  await capacityGate({\n    logDir,\n    self: { id: wid, provider: target.providerName },\n    cap: resolveCap(target.provider.maxConcurrent, isLocalProvider(target.provider.baseUrl)),\n    config: config.capacity,\n    disabled: a.noQueue,\n    priority: a.priority,\n    log: (line) => {\n      process.stderr.write(`${line}\\n`);\n    },\n    onWait: (w) => {\n      if (w) {\n        // parked at the cap: visible as \"queued\", never as a slot holder\n        status.state = \"queued\";\n        status.capacity = { provider: w.provider, cap: w.cap, total: w.total, position: w.position, elapsedSec: w.elapsedSec };\n        status.last = w.line;\n      } else {\n        // slot granted: back to running, and `started` now counts from the grant\n        // (spawnTimeOf documents the rewrite; wait-on's ceiling and ps ages use it)\n        status.state = \"running\";\n        status.started = nowStamp();\n        delete status.capacity;\n        status.last = saved;\n      }\n      saveStatus(logDir, status);\n    },\n  });\n  await staggerGate({\n    logDir,\n    self: { id: wid, provider: target.providerName },\n    local: isLocalProvider(target.provider.baseUrl),\n    config: config.stagger,\n    disabled: a.noStagger,\n    log: (line) => {\n      if (!a.quiet) process.stderr.write(`${line}\\n`);\n    },\n    onWait: (w) => {\n      if (w) {\n        status.warmup = { for: w.predecessor, provider: w.provider, elapsedSec: w.elapsedSec, limitSec: w.limitSec };\n        status.last = w.line;\n      } else {\n        delete status.warmup;\n        status.last = saved;\n      }\n      saveStatus(logDir, status);\n    },\n  });\n}\n\n/**\n * Gate a headless run once, before the pool attempt. A placeholder status\n * (running, this process's pid) is saved first, as a fresh spawn always did,\n * so the run counts as holding a slot the moment it leaves the queue; the pool\n * host or executeRun overwrites it under the same id.\n */\nexport async function gateStart(a: ExecuteArgs): Promise<void> {\n  if (!a.parsed.headless || a.printCmd || a.gated) return;\n  const wid = a.id ?? newWorkerId();\n  a.id = wid;\n  const status: WorkerStatus = {\n    id: wid,\n    pid: process.pid,\n    runPid: process.pid,\n    label: a.label,\n    cwd: a.cwd ?? process.cwd(),\n    term: \"\",\n    provider: a.target.providerName,\n    model: a.model,\n    state: \"running\",\n    started: nowStamp(),\n    updated: nowStamp(),\n    turns: 0,\n    tools: 0,\n    last: \"starting\",\n    rc: null,\n    secs: null,\n    origin: \"spawn\",\n    outputFormat: a.parsed.outputFormat,\n  };\n  saveStatus(a.logDir, status);\n  await runGates(a, wid, status);\n  // a gate that never had to wait leaves the placeholder \"running\" with the\n  // spawn stamp; one that queued already flipped back to \"running\" with the\n  // grant stamp (runGates onWait)\n  a.gated = true;\n}\n\nasync function executeRun(a: ExecuteArgs): Promise<number> {\n  const { config, logDir, target, model, label, parsed, noPane, limit, noBrowser } = a;\n  const headless = parsed.headless;\n\n  // openai-protocol providers run through the local proxy (started on demand)\n  let proxyUrl: string | undefined;\n  if (target.provider.protocol === \"openai\") {\n    const base = await ensureProxyRunning(DEFAULT_PROXY_PORT, logDir);\n    proxyUrl = `${base}/${target.providerName}`;\n  }\n  let viaRouter: boolean | undefined;\n  if (!proxyUrl && !target.provider.native && isLoopbackProvider(target.provider) && target.provider.router !== false) {\n    viaRouter = routeLoopbackViaRouter(target.provider, await probeRouter());\n    if (!viaRouter) process.stderr.write(`pai: router down, ${target.providerName} runs direct (no router prefix fix)\\n`);\n  }\n  const env = buildRunEnv(target.provider, headless, proxyUrl, target.providerName, viaRouter, a.orchestrate);\n\n  const wid = a.id ?? newWorkerId();\n  // a resume takes over the old id's tree and runs against its repo\n  const adopted = a.resumeOf ? adoptTree(logDir, a.resumeOf) : null;\n  const cwd = adopted?.cwd ?? a.cwd ?? process.cwd();\n  const term = (await resolveHostSession()).term;\n  const paneVerified = a.panePrepared\n    ? a.panePrepared.verified\n    : headless && (await requireVisiblePane(logDir, config, wid, term, noPane, a.printCmd === true, ledgerPath(logDir)));\n  const session = resolveSession(term);\n  // orchestrator Bash children have no terminal identity (see scope.ts) — the\n  // session map supplies the claude session they were spawned by instead\n  const spawnerSession = resolveSpawnerSession(logDir, cwd);\n\n  // One worktree per run whose tools can write (Edit/Write/Bash or no\n  // restriction), in a git cwd; --worktree/--no-worktree override. A git refusal\n  // degrades to an in-place run — the worker itself must still run.\n  // Skipped for --print-cmd: it is a dry-run and must not touch git.\n  let worktree: WorktreeInfo | null = adopted;\n  if (\n    !adopted &&\n    headless &&\n    !a.printCmd &&\n    worktreeWanted(a.worktreeFlag, { cwd, allowedTools: parsed.allowedTools })\n  ) {\n    try {\n      worktree = addWorktree(logDir, wid, cwd);\n    } catch (e) {\n      const why = (e as Error).message;\n      process.stderr.write(`pai worker: no worktree (${why}) — running in place\\n`);\n      appendLedger(ledgerPath(logDir), \"WORKER-NOTE\", { id: wid, note: `no worktree: ${why}` });\n    }\n  }\n  // project preamble (.pai/worker.md): headless only, oversize refuses the run\n  let preamble: Preamble | null = null;\n  if (headless) {\n    const loaded = loadPreamble(cwd);\n    if (\"refused\" in loaded) {\n      process.stderr.write(`pai worker: preamble refused: ${loaded.refused}\\n`);\n      appendLedger(ledgerPath(logDir), \"WORKER-NOTE\", { id: wid, note: `preamble refused: ${loaded.refused}` });\n      return 1;\n    }\n    preamble = loaded.preamble;\n    if (!a.quiet) process.stderr.write(preambleLine(preamble) + \"\\n\");\n  }\n  // provider contract addendum (<PAI_HOME>/contracts/<provider>.md): headless, only with the generic contract\n  const addendum: ContractAddendum | null =\n    headless && !parsed.callerSystemPrompt ? loadContractAddendum(target.providerName, target.provider.contract) : null;\n  if (addendum && !a.quiet) process.stderr.write(`contract addendum: ${addendum.path} sha ${addendum.sha}\\n`);\n  // sub-workers detect themselves (and their parent) through this variable\n  env.PAI_WORKER_ID = wid;\n  const noteToken = newNoteToken();\n  env[NOTE_TOKEN_ENV] = noteToken;\n  applySessionProviderEnv(env, target);\n  if (noBrowser) env.PAI_WORKER_NO_BROWSER = \"1\";\n\n  const mcpFlag = noBrowser ? stripBrowserNames(a.mcpFlag ? [a.mcpFlag] : [])[0] : a.mcpFlag;\n  const classMcp = noBrowser && target.classMcp ? stripBrowserNames(target.classMcp) : target.classMcp;\n  if (noBrowser) parsed.mcp = stripBrowserNames(parsed.mcp);\n  const chromeArgs = noBrowser\n    ? []\n    : chromeGrantArgs(\n        [...(mcpFlag ? [mcpFlag] : []), ...parsed.mcp, ...(classMcp ?? []), ...parsed.allowedTools],\n        parsed.rest\n      );\n\n  // MCP / tools: caller config > allowlist (--mcp flag / --mcp args / role /\n  // mcp__ grants in --allowedTools) > project pin (interactive only, `pai\n  // project mcp` / `pai project tools`) > the strict empty set (headless) /\n  // everything (interactive, today's default).\n  let mcpArgs: string[] = [];\n  // headless without a grant or --tools of its own: load only the default core schemas\n  let toolsFlag: string[] = headless ? headlessToolsFlag(parsed.allowedTools) : [];\n  if (headless && !parsed.allowedTools.length && !parsed.callerTools) {\n    toolsFlag = [\"--tools\", DEFAULT_WORKER_TOOLS];\n  }\n  if (headless && !parsed.callerMcpConfig) {\n    const wanted = [\n      ...(mcpFlag ? [mcpFlag] : []),\n      ...parsed.mcp,\n      ...(classMcp ?? []),\n      ...mcpServersFromToolGrants(parsed.allowedTools),\n    ];\n    if (wanted.length) {\n      const names = expandMcpNames(wanted, config); // unknown names fail fast\n      mcpArgs = [\"--strict-mcp-config\", \"--mcp-config\", writeMcpConfig(logDir, wid, names)];\n    } else {\n      mcpArgs = [\"--strict-mcp-config\", \"--mcp-config\", ensureNoMcpConfig(logDir)];\n    }\n  } else if (!headless && !parsed.callerMcpConfig) {\n    const explicitMcp = [...(mcpFlag ? [mcpFlag] : []), ...parsed.mcp];\n    const projectLaunch = await projectLaunchConfig(cwd);\n    const picked = interactiveMcpTools(explicitMcp, parsed.callerTools, projectLaunch);\n    // applied pins only: an explicit --mcp / --tools overrides its pin\n    const applied = projectLaunch && {\n      ...projectLaunch,\n      mcp: explicitMcp.length ? undefined : projectLaunch.mcp,\n      tools: picked.tools.length ? projectLaunch.tools : undefined,\n    };\n    for (const line of pinNotices(applied)) console.error(line);\n    if (picked.mcpNames.length) {\n      const names = expandMcpNames(picked.mcpNames, config);\n      mcpArgs = [\"--strict-mcp-config\", \"--mcp-config\", writeMcpConfig(logDir, wid, names)];\n    }\n    if (picked.tools.length) toolsFlag = [\"--tools\", picked.tools.join(\",\")];\n  }\n\n  // In stdin mode the prompt moves to the first user message on stdin, so it\n  // must come off the command line (bare -p stays: stream-json needs --print).\n  const restArgs = headless ? stripPromptValues(parsed.rest) : parsed.rest;\n  const toolArgs = headless ? headlessToolGrants(parsed.allowedTools) : [];\n  // A local server prefix-caches system prompt + tools, and a worktree's id,\n  // path, branch and the deadline minute differ per unit: left in the system\n  // prompt they cut the shared prefix before the tool definitions (measured\n  // 2026-10-17: 3.1k of 38k tokens shared). They go at the head of the task\n  // message instead. Anthropic and remote providers keep them in the system prompt.\n  const volatileInTask = headless && !target.provider.native && isLoopbackProvider(target.provider);\n  const volatileParts = volatileInTask\n    ? [\n        ...(worktree ? [worktreeSystemPrompt(wid, worktree.branch, worktree.dir, worktree.snapshot)] : []),\n        ...(limit ? [deadlinePromptLine(limit)] : []),\n      ]\n    : [];\n  const { text: taskText, applied: trailerApplied } = headlessPromptText(\n    parsed.prompt,\n    headless,\n    parsed.callerSystemPrompt,\n    a.reportFormat\n  );\n  const promptText = taskText !== null && volatileParts.length ? volatileParts.join(\"\\n\") + \"\\n\\n\" + taskText : taskText;\n  const claudeCmd = claudeCommand(env, config.caveman);\n  let cmd: string[] = [...claudeCmd];\n  cmd.push(...modelFlagArgs(headless, model, Boolean(parsed.callerModel)));\n  const slimArgs = headless ? slimProfileArgs(logDir, wid, parsed.rest, env, undefined, target.provider) : [];\n  cmd.push(...chromeArgs, ...mcpArgs, ...toolArgs, ...toolsFlag, ...slimArgs, ...restArgs);\n  if (headless) {\n    cmd.push(\"--output-format\", \"stream-json\", \"--verbose\", \"--input-format\", \"stream-json\");\n  }\n  // ONE flag: contract (unless the caller brought their own), placement, caller text\n  cmd.push(\n    ...appendSystemPromptArgs([\n      ...(headless && !parsed.callerSystemPrompt ? [workerContractPrompt(a.className, a.reportFormat, a.orchestrate, noteToken)] : []),\n      ...(addendum ? [addendum.text] : []),\n      ...(slimArgs.length ? [WORKER_BRIEF] : []),\n      ...(preamble ? [preambleBlock(preamble)] : []),\n      ...(headless\n        ? [worktree ? (volatileInTask ? \"\" : worktreeSystemPrompt(wid, worktree.branch, worktree.dir, worktree.snapshot)) : inPlaceSystemPrompt()]\n        : []),\n      ...(headless && limit && !volatileInTask ? [deadlinePromptLine(limit)] : []),\n      ...parsed.callerSystemPrompts,\n    ])\n  );\n  cmd = ensureToolSearch(cmd);\n\n  // Dry run: the argv audit, no status/ledger/pane, no spawn.\n  if (a.printCmd) {\n    console.log(\n      JSON.stringify({\n        cmd,\n        cwd: worktree?.dir ?? cwd,\n        ...(promptText !== null ? { stdin: promptText } : {}),\n        browser: noBrowser ? \"off\" : \"on\",\n        ...(a.routeWhy ? { route: a.routeWhy } : {}),\n        sessionProviderEnv: env.PAI_SESSION_PROVIDER ?? null,\n        ...(limit ? { deadline: new Date(limit.deadlineAt).toISOString(), maxMinutes: limit.minutes } : { limit: \"none\" }),\n      })\n    );\n    return 0;\n  }\n\n  // a gate that already ran (gateStart) rewrote `started` at the slot grant;\n  // keep that stamp so the deadline and ps age count from the grant\n  const gated = a.gated ? loadStatus(logDir, wid) : null;\n  const started = gated && Number.isFinite(Date.parse(gated.started.replace(\" \", \"T\")))\n    ? new Date(Date.parse(gated.started.replace(\" \", \"T\")))\n    : new Date();\n  let status: WorkerStatus = {\n    id: wid,\n    pid: process.pid,\n    runPid: process.pid,\n    ...parentInfo(),\n    label,\n    cwd,\n    term,\n    provider: target.providerName,\n    model,\n    state: \"running\",\n    started: nowStamp(started),\n    updated: nowStamp(),\n    turns: 0,\n    tools: 0,\n    last: headless ? \"starting\" : \"interactive\",\n    rc: null,\n    secs: null,\n    // interactive runs ARE the chat pane, not a spawned subagent of it\n    origin: headless ? \"spawn\" : \"chat\",\n    outputFormat: parsed.outputFormat,\n    ...(a.route ? { route: a.route } : {}),\n    ...(a.routeWhy ? { routeWhy: a.routeWhy } : {}),\n    ...(target.via === \"auto\" && target.switchReason ? { switchReason: target.switchReason } : {}),\n    ...(a.fallThroughOf ? { fallThroughOf: a.fallThroughOf } : {}),\n    ...(headless ? { reportFormat: a.reportFormat } : {}),\n    ...(trailerApplied ? { promptTrailer: true } : {}),\n    ...(preamble ? { preamble: { path: preamble.path, hash: preamble.hash } } : {}),\n    ...(addendum ? { contractAddendum: { path: addendum.path, sha: addendum.sha } } : {}),\n    ...(session ? { session } : {}),\n    ...(spawnerSession ? { spawnerSession } : {}),\n    // no window seed: contextWindow comes from the init event only, and the\n    // meter stays hidden until one is announced (never a guessed default)\n    ...(a.parent ? { parent: a.parent, stage: a.stage } : {}),\n    ...(worktree\n      ? {\n          worktreeDir: worktree.dir,\n          branch: worktree.branch,\n          worktreeBase: worktree.base,\n          worktreeSnapshot: worktree.snapshot,\n        }\n      : {}),\n    ...(adopted ? { resumedFrom: a.resumeOf } : {}),\n    ...(a.specPath ? { spec: a.specPath } : {}),\n    ...(limit ? { deadlineAt: limit.deadlineAt, maxMinutes: limit.minutes } : {}),\n  };\n  saveStatus(logDir, status);\n  if (adopted && a.resumeOf) markResumed(logDir, a.resumeOf, wid);\n  a.onWorkerStart?.(wid);\n  const ledger = ledgerPath(logDir);\n  appendLedger(ledger, \"WORKER-START\", {\n    id: wid,\n    provider: target.providerName,\n    mode: headless ? \"headless\" : \"interactive\",\n    model,\n    cwd,\n    label,\n    ...(a.capability ? { capability: a.capability } : {}),\n    ...(a.specPath ? { spec: a.specPath } : {}),\n    ...(target.switchReason ? { switch: target.switchReason } : {}),\n  });\n\n  // Follow pane: headless only (interactive runs ARE the chat pane). Verified\n  // above when the gate applies; best effort otherwise.\n  if (paneVerified) status.pane = { opened: true, placement: panePlacement(wid) };\n  else if (headless && !a.panePrepared) void announcePane(logDir, config, wid, term, noPane, ledger, status);\n\n  let proc: ReturnType<typeof spawn>;\n  try {\n    if (headless && !a.gated) await runGates(a, wid, status);\n    proc = spawn(cmd[0], cmd.slice(1), {\n      env,\n      cwd: worktree?.dir ?? cwd,\n      stdio: headless ? [\"pipe\", \"pipe\", \"pipe\"] : \"inherit\",\n    });\n  } catch (e) {\n    markStartFailed(logDir, status, e);\n    throw e;\n  }\n  const t0 = Date.now();\n  // claude's stderr: passed through, and the tail kept for a start that dies before any model event\n  let stderrTail = \"\";\n  proc.stderr?.on(\"data\", (d: Buffer) => {\n    process.stderr.write(d);\n    stderrTail = (stderrTail + d.toString()).slice(-2000);\n  });\n\n  // --- stdin lifecycle (2i): prompt in, socket forwards, close 2 s after result\n  let operatorInFlight = 0;\n  let closeTimer: NodeJS.Timeout | null = null;\n  const armStdinClose = () => {\n    if (closeTimer) clearTimeout(closeTimer);\n    closeTimer = setTimeout(() => {\n      if (operatorInFlight === 0) {\n        try {\n          proc.stdin?.end();\n        } catch {\n          /* already closed */\n        }\n      }\n    }, 2_000);\n  };\n\n  let eventsFd: number | null = null;\n  const writeEvent = (obj: Record<string, unknown>): void => {\n    if (eventsFd === null) return;\n    try {\n      writeSync(eventsFd, JSON.stringify({ ...obj, _ts: isoStamp() }) + \"\\n\");\n    } catch {\n      // a full disk must not take the worker transcript's process down\n    }\n  };\n\n  const operatorServer = headless\n    ? createOperatorServer(logDir, wid, async (text) => {\n        const stdin = proc.stdin;\n        if (!stdin || !stdin.writable || stdin.writableEnded) {\n          return \"the worker's stdin is already closed (its turn ended) — use: pai worker resume\";\n        }\n        operatorInFlight += 1;\n        resultGrace.cancel();\n        if (closeTimer) {\n          clearTimeout(closeTimer);\n          closeTimer = null;\n        }\n        // a handoff delivery's mirror carries a flag: the viewer shows the\n        // inbox ◆ line instead, never both\n        writeEvent({ type: \"operator\", text, handoff: isHandoffMessage(text) });\n        return new Promise<void | string>((resolve) => {\n          try {\n            stdin.write(stdinUserMessage(operatorUserText(text)) + \"\\n\", (e) =>\n              resolve(e ? `write to the worker failed: ${e.message}` : undefined)\n            );\n          } catch (e) {\n            resolve(`write to the worker failed: ${(e as Error).message}`);\n          }\n        });\n      })\n    : null;\n\n  // A failed Edit fires no hook, so the closest-region hint rides in as a user turn (harness line, not an operator message to answer).\n  const injectHarnessHint = (text: string): void => {\n    const stdin = proc.stdin;\n    if (!headless || !stdin || !stdin.writable || stdin.writableEnded) return;\n    try {\n      stdin.write(stdinUserMessage(`[harness] ${text}`) + \"\\n\");\n    } catch {\n      // the hint is a courtesy\n    }\n  };\n\n  let killed = false;\n  const resultGrace = armResultGrace(headless ? proc.pid : undefined);\n  const stopDeadline = limit ? armDeadline(proc, limit, () => fireDeadline(logDir, status, ledger, limit)) : null;\n  const cleanup = () => {\n    stopDeadline?.();\n    if (closeTimer) clearTimeout(closeTimer);\n    operatorServer?.close();\n  };\n  const onSignal = (sig: string) => {\n    killed = true;\n    status.state = \"killed\";\n    status.rc = 143;\n    status.secs = Math.floor((Date.now() - t0) / 1000);\n    const end = recordSignalEnd(logDir, status, sig);\n    status.last = `killed by signal ${sig} (${end.reason}${end.by ? ` by ${end.by}` : \"\"})`;\n    saveStatus(logDir, status);\n    appendLedger(ledger, \"WORKER-END\", {\n      id: wid,\n      provider: target.providerName,\n      mode: \"headless\",\n      model,\n      rc: 143,\n      secs: status.secs,\n      killed: 1,\n      ...endFields(end),\n      note: end.note,\n      label,\n    });\n    // a killed worktree run leaves nothing to merge — drop its worktree and\n    // branch too, or every kill strands them for hand-pruning (2026-09-18)\n    if (worktree) {\n      salvageOnExit(ledger, wid, label, worktree.dir, SIGNAL_SALVAGE_MS);\n      try {\n        recordWorktree(logDir, status, worktree, false);\n      } catch {\n        /* best effort: the status already says killed */\n      }\n    }\n    cleanup();\n    try {\n      proc.kill();\n    } catch {\n      /* already gone */\n    }\n    process.exit(143);\n  };\n  process.once(\"SIGTERM\", () => onSignal(\"SIGTERM\"));\n  process.once(\"SIGINT\", () => onSignal(\"SIGINT\"));\n  process.once(\"SIGHUP\", () => onSignal(\"SIGHUP\"));\n\n  // Holder for the last result event + its parsed report: assigned inside the\n  // readline callback below, read after the await.\n  const ctx: {\n    resultEvent: StreamEvent | null;\n    resultReport: WorkerReport | null;\n  } = {\n    resultEvent: null,\n    resultReport: null,\n  };\n  // every Bash call + outcome, and the untracked files present at spawn: the\n  // end-of-run proof check (checkProof) and stray-file listing read these\n  const bashRuns: BashRun[] = [];\n  let trouble: TroubleWatcher | undefined;\n  let troubleTimer: ReturnType<typeof setInterval> | undefined;\n  const untrackedAtStart = new Set(headless ? untrackedPaths(worktree?.dir ?? cwd) : []);\n\n  if (headless) {\n    // the first user message carries the prompt (the -p value was stripped)\n    if (promptText !== null) {\n      try {\n        proc.stdin!.write(stdinUserMessage(promptText) + \"\\n\");\n      } catch {\n        /* child died instantly; the close handler reports it */\n      }\n    }\n    const origin = reportOrigin();\n    if (origin) {\n      trouble = new TroubleWatcher(wid, label, runMessenger(logDir), origin);\n      troubleTimer = setInterval(() => trouble?.tick(), 60_000);\n      troubleTimer.unref();\n    }\n    eventsFd = openSync(eventsPath(logDir, wid), \"a\");\n    writeEvent({ type: \"preamble\", text: preambleLine(preamble), ...(preamble ? { hash: preamble.hash } : {}) });\n    if (addendum) writeEvent({ type: \"contract-addendum\", text: `${addendum.path} sha ${addendum.sha}`, sha: addendum.sha });\n    const rl = createInterface({ input: proc.stdout! });\n    const toolUses = new Map<string, { name: string; input: unknown }>();\n    rl.on(\"line\", (line) => {\n      trouble?.activity();\n      if (parsed.outputFormat === \"stream-json\") {\n        process.stdout.write(line + \"\\n\");\n      }\n      if (!line.startsWith(\"{\")) return;\n      let e: StreamEvent;\n      try {\n        e = JSON.parse(line) as StreamEvent;\n      } catch {\n        return;\n      }\n      writeEvent(e as Record<string, unknown>);\n      if (e.type === \"system\" && e.subtype === \"init\") {\n        if (e.session_id) status.claudeSession = e.session_id;\n        adoptInitModel(status, e);\n        const cw =\n          initContextWindow(e) ?? target.provider.contextWindow ?? certainContextWindow(status.model);\n        if (cw) status.contextWindow = cw;\n        saveStatus(logDir, status);\n      } else if (isCompactBoundary(e)) {\n        resetContextTokensOnCompact(status, e);\n        saveStatus(logDir, status);\n      } else if (e.type === \"assistant\") {\n        status.turns += 1;\n        if (status.turns === 1) recordWarmup(logDir, status.provider, (Date.now() - t0) / 1000);\n        bumpContextTokens(status, usageContextTokens(e.message?.usage));\n        status.contextUsed = usageContextUsed(e.message?.usage) ?? status.contextUsed;\n        for (const block of e.message?.content ?? []) {\n          if (block.type === \"tool_use\") {\n            status.tools += 1;\n            if (block.id) toolUses.set(block.id, { name: block.name ?? \"?\", input: block.input });\n            status.last = describeTool(block.name ?? \"?\", block.input);\n            // a long single sleep is worth seeing while it runs (supervision's\n            // \"sleeping\" kind) — set when issued, cleared when it completes\n            if (block.name === \"Bash\") status.sleepSec = parseSleepSecs(bashCommand(block.input));\n          } else if (block.type === \"text\" && (block.text ?? \"\").trim()) {\n            status.last = \"says: \" + shortText(block.text, 70);\n          }\n        }\n        saveStatus(logDir, status);\n      } else if (e.type === \"user\") {\n        // tool results arrive as user events: each one advances (or resets)\n        // the consecutive-failure counter supervision's thrashing detector\n        // reads, and retires a pending sleep observation. Plain user turns\n        // (operator input) have no tool_result blocks and change nothing.\n        const blocks = e.message?.content;\n        if (Array.isArray(blocks)) {\n          let sawResult = false;\n          for (const block of blocks) {\n            if (block.type !== \"tool_result\") continue;\n            sawResult = true;\n            status.consecFails = toolResultFailed(block) ? (status.consecFails ?? 0) + 1 : 0;\n            status.sleepSec = null;\n            if (recordDenial(status, block, toolResultText(block.content), toolUses, parsed.prompt, new Date().toISOString())) {\n              const d = parseDenialText(toolResultText(block.content), \"?\");\n              if (d) trouble?.onDenial(d.hook, d.reason);\n            }\n            if (block.is_error === true) {\n              recordToolError(logDir, {\n                worker: wid,\n                provider: target.providerName,\n                label,\n                tool: toolUses.get(block.tool_use_id ?? \"\")?.name ?? \"?\",\n                text: toolResultText(block.content),\n                input: toolUses.get(block.tool_use_id ?? \"\")?.input,\n                granted: headless ? grantedToolNames(toolsFlag.slice(1), parsed.allowedTools) : undefined,\n              });\n            }\n            const use = block.tool_use_id ? toolUses.get(block.tool_use_id) : undefined;\n            if (use?.name === \"Edit\" && block.is_error === true) {\n              const hint = editHintFor(use.input, toolResultText(block.content), worktree?.dir ?? cwd);\n              if (hint) injectHarnessHint(hint);\n            }\n            if (use?.name === \"Bash\") bashRuns.push({ command: bashCommand(use.input), failed: toolResultFailed(block), output: toolResultText(block.content).slice(-400) });\n          }\n          if (sawResult) saveStatus(logDir, status);\n        }\n      } else if (e.type === \"result\") {\n        const tokens = usageContextTokens(e.usage);\n        // a compact result legitimately restarts the context lower\n        if (e.is_compact) status.contextTokens = tokens ?? status.contextTokens;\n        else bumpContextTokens(status, tokens);\n        const report = parseWorkerReport(e.result ?? \"\");\n        if (report?.notes) status.last = shortText(report.notes, 90);\n        else if (e.result) status.last = shortText(e.result, 90);\n        saveStatus(logDir, status);\n        operatorInFlight = 0;\n        armStdinClose();\n        ctx.resultEvent = e;\n        ctx.resultReport = report;\n        resultGrace.onResult();\n      }\n    });\n  }\n\n  let rc = await new Promise<number>((resolve, reject) => {\n    proc.on(\"error\", (e) => {\n      markStartFailed(logDir, status, e);\n      reject(e);\n    });\n    proc.on(\"close\", (code) => resolve(code ?? (killed ? 143 : 1)));\n  });\n  if (troubleTimer) clearInterval(troubleTimer);\n  if (trouble) {\n    const stop = peekLoopStop(logDir, wid);\n    if (stop) trouble.onLoopStop(stop.reason);\n    await trouble.flush();\n  }\n  resultGrace.cancel();\n  await resultGrace.settled();\n  // the result already received is the outcome; the signal that ended the leftovers is not\n  if (resultGrace.fired && ctx.resultEvent) rc = ctx.resultEvent.is_error ? 1 : 0;\n  if (eventsFd !== null) closeSync(eventsFd);\n  cleanup();\n\n  const secs = Math.floor((Date.now() - t0) / 1000);\n  const resultEvent = ctx.resultEvent;\n  const empty = headless && rc === 0 && resultEvent !== null && isEmptyResponse(resultEvent.result, status.tools);\n  const ok = !empty && runSucceeded(headless, rc, resultEvent);\n  if (resultEvent) status.last = shortText(resultEvent.result ?? \"\", 90);\n  else if (headless) status.last = preEventFailure(rc, status.turns, stderrTail) ?? status.last;\n  if (ctx.resultReport?.notes) status.last = shortText(ctx.resultReport.notes, 90);\n  if (empty) {\n    status.last = \"harness: empty-response (model returned nothing)\";\n    recordToolError(logDir, {\n      worker: wid,\n      provider: target.providerName,\n      label,\n      tool: \"model\",\n      text: \"empty-response: model answered with zero usage and no tool call\",\n    });\n  }\n  if (headless && a.reportFormat === \"ag2\" && resultEvent?.result) {\n    const v = validateAg2(resultEvent.result);\n    status.reportValid = v.ok;\n    status.reportErrors = v.errors;\n    // one bounded re-ask, cap exactly one — see shouldRetryReport\n    if (shouldRetryReport(v, a.noReportRetry ?? false, Boolean(status.claudeSession))) {\n      status.reportRetried = true;\n      saveStatus(logDir, status);\n      appendLedger(ledger, \"WORKER-REPORT-RETRY\", { id: wid, reason: v.errors.join(\"; \") || \"invalid AG2 message\" });\n      try {\n        const reaskText = await reaskAg2Report({\n          env,\n          cwd: worktree?.dir ?? cwd,\n          model,\n          callerPinnedModel: Boolean(parsed.callerModel),\n          chromeArgs,\n          mcpArgs,\n          toolArgs,\n          toolsFlag,\n          slimArgs,\n          sessionId: status.claudeSession!,\n          claudeCmd,\n        });\n        const v2 = validateAg2(reaskText);\n        status.reportValid = v2.ok;\n        status.reportErrors = v2.errors;\n        if (v2.ok) {\n          resultEvent.result = reaskText;\n          ctx.resultReport = parseWorkerReport(reaskText);\n          if (ctx.resultReport?.notes) status.last = shortText(ctx.resultReport.notes, 90);\n        }\n      } catch {\n        // the re-ask is best effort; the original invalid report stands\n      }\n    }\n  }\n  if (headless && a.reportFormat === \"ag2\" && resultEvent?.result) {\n    const stray = newUntracked(worktree?.dir ?? cwd, untrackedAtStart);\n    const chk = checkProof(resultEvent.result, bashRuns, stray);\n    if (chk.rewritten || stray.length) {\n      resultEvent.result = chk.text;\n      ctx.resultReport = parseWorkerReport(chk.text);\n      if (ctx.resultReport) ctx.resultReport.untracked = stray.length ? stray : undefined;\n    }\n    if (chk.rewritten) {\n      status.reportValid = false;\n      status.last = shortText(`claimed proof not run or failed: ${chk.proof}`, 90);\n      appendLedger(ledger, \"REPORT-PROOF-UNVERIFIED\", { id: wid, proof: chk.proof });\n    }\n    if (stray.length) process.stderr.write(`pai worker: warning: ${stray.length} untracked file(s) left by the worker: ${stray.join(\", \")}\\n`);\n  }\n  if (ctx.resultReport && status.denials?.length) ctx.resultReport.denials = status.denials;\n  if (headless && ctx.resultReport?.changed?.length) {\n    const verify = verifyReportChanges(ctx.resultReport.changed, worktree?.dir ?? cwd, t0);\n    if (!verify.ok) {\n      status.reportValid = false;\n      const note = verifyFailNote(verify);\n      status.last = shortText(note, 90);\n      ctx.resultReport.notes = ctx.resultReport.notes ? `${ctx.resultReport.notes} — ${note}` : note;\n      appendLedger(ledger, \"REPORT-UNVERIFIED\", {\n        id: wid,\n        failures: verify.failures.length,\n        paths: verify.failures.map((f) => f.path).slice(0, 5).join(\",\"),\n      });\n    }\n  }\n  if (resultGrace.fired && resultEvent) {\n    status.last = leftoverNote(resultGrace.leftover);\n    appendLedger(ledger, \"WORKER-LEFTOVER-ENDED\", { id: wid, processes: resultGrace.leftover });\n  }\n  return finaliseRun({\n    logDir,\n    ledger,\n    status,\n    ok,\n    rc,\n    secs,\n    end: {\n      provider: target.providerName,\n      mode: headless ? \"headless\" : \"interactive\",\n      model,\n      turns: status.turns,\n      tools: status.tools,\n      label,\n    },\n    report: ctx.resultReport,\n    fallbackText: resultEvent?.result,\n    worktree,\n    timedOut: status.timedOut ? limit?.minutes : undefined,\n    beforeHandoff: async (st, rep) => {\n      // Fall-through: a local run that failed its own report is repeated once on the cloud.\n      const why = headless ? fallThroughReason(a.route, st, rep) : null;\n      if (why && a.route) {\n        appendLedger(ledger, \"WORKER-FALLTHROUGH\", { id: wid, reason: why });\n        process.stderr.write(`pai worker: ${wid} on ${target.providerName} ended badly (${why}) — re-running on the cloud\\n`);\n        return runWorker({\n          providerFlag: ANTHROPIC_NATIVE,\n          label: `${label} (fall-through)`,\n          noPane: a.noPane,\n          mcpFlag: a.mcpFlag,\n          cwd: a.cwd,\n          specPath: a.specPath,\n          parent: a.parent,\n          stage: a.stage,\n          claudeArgs: a.claudeArgs,\n          quiet: a.quiet,\n          worktreeFlag: a.worktreeFlag,\n          className: a.className,\n          _route: { policy: a.route.policy, reason: `fall-through (${why})`, local: false },\n          _fallThroughOf: wid,\n          onWorkerStart: (id2) => {\n            st.fallThroughTo = id2;\n            saveStatus(logDir, st);\n            a.onWorkerStart?.(id2);\n          },\n        });\n      }\n      if (headless && !a.quiet) {\n        printResult(parsed.outputFormat, resultEvent, rc, logDir, wid, rep, worktreeExtras(st));\n      }\n\n    // Empty response: one automatic re-launch of the same spec in the same cwd.\n    if (empty && !a.emptyRetried) {\n      appendLedger(ledger, \"WORKER-EMPTY-RETRY\", { id: wid, provider: target.providerName });\n      return runWorker(\n        relaunchOptions(a.opts, {\n          providerFlag: target.providerName,\n          onWorkerStart: a.onWorkerStart,\n          _emptyRetried: true,\n        })\n      );\n    }\n\n    // Quota reroute: only auto-routed runs, dead before the first tool call.\n    const resultText = resultEvent?.result ?? \"\";\n    if (\n      !ok &&\n      headless &&\n      a.target.via === \"auto\" &&\n      config.routing.retryOnQuota &&\n      status.turns <= 1 &&\n      status.tools === 0 &&\n      isQuotaFailure(resultText)\n    ) {\n      setCooldown(logDir, target.providerName, config.routing.cooldownMinutes);\n      const next = nextAutoProvider(config, logDir, target.providerName);\n      if (next && a.reroutes < autoOrder(config).length) {\n        appendLedger(ledger, \"WORKER-REROUTE\", {\n          from: target.providerName,\n          to: next,\n          reason: \"quota\",\n        });\n        return runWorker(\n          relaunchOptions(a.opts, {\n            providerFlag: next,\n            modelFlag: undefined,\n            onWorkerStart: a.onWorkerStart,\n            _reroutes: a.reroutes + 1,\n          })\n        );\n      }\n    }\n    },\n  });\n}\n\n/**\n * Options for a relaunch (empty-response retry, quota reroute): the original\n * run's options, minus the preset id (the relaunch is a new worker), with the\n * given changes applied. Nothing is copied field by field, so a new RunOptions\n * field is carried over by default.\n */\nexport function relaunchOptions(orig: RunOptions, changes: Partial<RunOptions>): RunOptions {\n  return { ...orig, id: undefined, ...changes };\n}\n\n/** The worktree fields printResult adds to a json payload, when there is one. */\nexport function worktreeExtras(s: WorkerStatus): Record<string, unknown> | undefined {\n  return s.branch ? { branch: s.branch, commits: s.commits ?? 0 } : undefined;\n}\n\nexport interface Ag2ReaskArgs {\n  env: NodeJS.ProcessEnv;\n  cwd: string;\n  model: string;\n  callerPinnedModel: boolean;\n  chromeArgs: string[];\n  mcpArgs: string[];\n  toolArgs: string[];\n  toolsFlag: string[];\n  /** Slim-profile args of the original launch, so the resumed turn loads the same setup. */\n  slimArgs?: string[];\n  sessionId: string;\n  timeoutMs?: number;\n  /** Argv head of the original launch (claudeCommand); defaults to plain claude. */\n  claudeCmd?: string[];\n}\n\n/**\n * The one bounded re-ask, cap exactly one: `claude --resume <session>` with\n * AG2_REASK_TEXT, single-shot `--output-format json` (one turn, no streaming\n * plumbing needed). Same env/model/mcp/tool flags as the original launch —\n * only --resume and the fixed re-ask prompt are new — so the resumed turn\n * sees the same grants the worker ran with.\n */\nexport async function reaskAg2Report(a: Ag2ReaskArgs): Promise<string> {\n  let cmd: string[] = [...(a.claudeCmd ?? [\"claude\"])];\n  cmd.push(...modelFlagArgs(true, a.model, a.callerPinnedModel));\n  cmd.push(...a.chromeArgs, ...a.mcpArgs, ...a.toolArgs, ...a.toolsFlag, ...(a.slimArgs ?? []));\n  cmd.push(\"--resume\", a.sessionId, \"-p\", AG2_REASK_TEXT, \"--output-format\", \"json\");\n  cmd = ensureToolSearch(cmd);\n  const proc = spawn(cmd[0], cmd.slice(1), { env: a.env, cwd: a.cwd, stdio: [\"ignore\", \"pipe\", \"inherit\"] });\n  const timer = setTimeout(() => {\n    try {\n      proc.kill(\"SIGKILL\");\n    } catch {\n      /* already gone */\n    }\n  }, a.timeoutMs ?? 60_000);\n  let out = \"\";\n  proc.stdout.on(\"data\", (chunk: Buffer) => {\n    out += chunk.toString(\"utf8\");\n  });\n  await new Promise<void>((resolve) => {\n    proc.on(\"error\", () => resolve());\n    proc.on(\"close\", () => resolve());\n  });\n  clearTimeout(timer);\n  return resultFromOutput(out);\n}\n\n// ---------------------------------------------------------------------------\n// codex engine (2d)\n// ---------------------------------------------------------------------------\n\ninterface CodexArgs extends Omit<ExecuteArgs, \"reroutes\" | \"mcpFlag\" | \"opts\"> {}\n\nasync function executeCodexRun(a: CodexArgs): Promise<number> {\n  const { config, logDir, target, model, label, parsed, noPane } = a;\n  if (!parsed.headless || parsed.prompt === null) {\n    throw new Error(\n      `provider \"${target.providerName}\" (engine codex) supports headless runs only: ` +\n        `pass the task with -p '<prompt>'`\n    );\n  }\n  const env = buildCodexEnv(target.provider);\n  const wid = a.id ?? newWorkerId();\n  const cwd = a.cwd ?? process.cwd();\n  const term = (await resolveHostSession()).term;\n  const paneVerified = await requireVisiblePane(logDir, config, wid, term, noPane, false, ledgerPath(logDir));\n  const session = resolveSession(term);\n  const spawnerSession = resolveSpawnerSession(logDir, cwd);\n\n  let worktree: WorktreeInfo | null = null;\n  if (worktreeWanted(a.worktreeFlag, { cwd, allowedTools: parsed.allowedTools })) {\n    try {\n      worktree = addWorktree(logDir, wid, cwd);\n    } catch (e) {\n      const why = (e as Error).message;\n      process.stderr.write(`pai worker: no worktree (${why}) — running in place\\n`);\n      appendLedger(ledgerPath(logDir), \"WORKER-NOTE\", { id: wid, note: `no worktree: ${why}` });\n    }\n  }\n  env.PAI_WORKER_ID = wid;\n  // codex takes instructions through the prompt, not a system prompt flag\n  const prompt =\n    (a.limit ? deadlinePromptLine(a.limit) + \"\\n\\n\" : \"\") +\n    (worktree ? worktreeSystemPrompt(wid, worktree.branch, worktree.dir, worktree.snapshot) + \"\\n\\n\" : \"\") +\n    parsed.prompt;\n\n  let status: WorkerStatus = {\n    id: wid,\n    pid: process.pid,\n    runPid: process.pid,\n    ...parentInfo(),\n    label,\n    cwd,\n    term,\n    provider: target.providerName,\n    model,\n    state: \"running\",\n    started: nowStamp(),\n    updated: nowStamp(),\n    turns: 0,\n    tools: 0,\n    last: \"starting\",\n    rc: null,\n    secs: null,\n    origin: \"spawn\",\n    outputFormat: parsed.outputFormat,\n    // codex takes instructions through the prompt, not the AG2 contract flag\n    reportFormat: \"json\",\n    ...(session ? { session } : {}),\n    ...(spawnerSession ? { spawnerSession } : {}),\n    // codex has no init event of its own: the synthetic one below announces\n    // an explicitly configured window (never a guessed default)\n    ...(target.provider.contextWindow ? { contextWindow: target.provider.contextWindow } : {}),\n    ...(a.parent ? { parent: a.parent, stage: a.stage } : {}),\n    ...(worktree\n      ? {\n          worktreeDir: worktree.dir,\n          branch: worktree.branch,\n          worktreeBase: worktree.base,\n          worktreeSnapshot: worktree.snapshot,\n        }\n      : {}),\n    ...(a.specPath ? { spec: a.specPath } : {}),\n    ...(a.limit ? { deadlineAt: a.limit.deadlineAt, maxMinutes: a.limit.minutes } : {}),\n  };\n  saveStatus(logDir, status);\n  a.onWorkerStart?.(wid);\n  const ledger = ledgerPath(logDir);\n  appendLedger(ledger, \"WORKER-START\", {\n    id: wid,\n    provider: target.providerName,\n    mode: \"headless\",\n    engine: \"codex\",\n    model,\n    cwd,\n    label,\n    ...(a.capability ? { capability: a.capability } : {}),\n  });\n  const dropped = codexDroppedFlags(a.claudeArgs);\n  if (dropped.length) {\n    appendLedger(ledger, \"WORKER-NOTE\", {\n      id: wid,\n      note: `dropped for codex: ${dropped.join(\", \")}`,\n    });\n  }\n\n  if (paneVerified) status.pane = { opened: true, placement: panePlacement(wid) };\n  else void announcePane(logDir, config, wid, term, noPane, ledger, status);\n\n  const t0 = Date.now();\n  const proc = spawn(\"codex\", buildCodexArgs(prompt, parsed.callerModel ? undefined : model), {\n    env,\n    cwd: worktree?.dir ?? cwd,\n    stdio: [\"ignore\", \"pipe\", \"inherit\"],\n  });\n\n  const fold = emptyCodexResult();\n  const eventsFd = openSync(eventsPath(logDir, wid), \"a\");\n  const writeEvent = (obj: Record<string, unknown>) => {\n    try {\n      writeSync(eventsFd, JSON.stringify({ ...obj, _ts: isoStamp() }) + \"\\n\");\n    } catch {\n      // best effort transcript\n    }\n  };\n  writeEvent({\n    type: \"system\",\n    subtype: \"init\",\n    model,\n    cwd,\n    ...(target.provider.contextWindow ? { context_window: target.provider.contextWindow } : {}),\n  });\n\n  let killed = false;\n  const stopDeadline = a.limit ? armDeadline(proc, a.limit, () => fireDeadline(logDir, status, ledger, a.limit!)) : null;\n  process.once(\"SIGTERM\", onCodexSignal(\"SIGTERM\"));\n  process.once(\"SIGINT\", onCodexSignal(\"SIGINT\"));\n  process.once(\"SIGHUP\", onCodexSignal(\"SIGHUP\"));\n  function onCodexSignal(sig: string) {\n    return () => {\n      killed = true;\n      status.state = \"killed\";\n      status.rc = 143;\n      status.secs = Math.floor((Date.now() - t0) / 1000);\n      const end = recordSignalEnd(logDir, status, sig);\n      status.last = `killed by signal ${sig} (${end.reason}${end.by ? ` by ${end.by}` : \"\"})`;\n      saveStatus(logDir, status);\n      appendLedger(ledger, \"WORKER-END\", {\n        id: wid,\n        provider: target.providerName,\n        mode: \"headless\",\n        model,\n        rc: 143,\n        secs: status.secs,\n        killed: 1,\n        ...endFields(end),\n        note: end.note,\n        label,\n      });\n      // same as the claude path: a killed run's worktree and branch go now\n      if (worktree) {\n        salvageOnExit(ledger, wid, label, worktree.dir, SIGNAL_SALVAGE_MS);\n        try {\n          recordWorktree(logDir, status, worktree, false);\n        } catch {\n          /* best effort: the status already says killed */\n        }\n      }\n      try {\n        proc.kill();\n      } catch {\n        /* already gone */\n      }\n      process.exit(143);\n    };\n  }\n\n  const rl = createInterface({ input: proc.stdout! });\n  rl.on(\"line\", (line) => {\n    if (parsed.outputFormat === \"stream-json\") process.stdout.write(line + \"\\n\");\n    const parsedLine = parseCodexLine(line);\n    if (parsedLine === null) return;\n    foldCodexLine(parsedLine, fold);\n    if (fold.threadId && !status.claudeSession) status.claudeSession = fold.threadId;\n    status.turns = fold.turns;\n    status.tools = fold.tools;\n    if (fold.last) status.last = shortText(fold.last, 90);\n    bumpContextTokens(status, fold.contextTokens);\n    saveStatus(logDir, status);\n    for (const ev of fold.events.splice(0)) writeEvent(ev);\n  });\n\n  const rc = await new Promise<number>((resolve, reject) => {\n    proc.on(\"error\", reject);\n    proc.on(\"close\", (code) => resolve(code ?? (killed ? 143 : 1)));\n  });\n  stopDeadline?.();\n  closeSync(eventsFd);\n\n  const secs = Math.floor((Date.now() - t0) / 1000);\n  const finalText = fold.finalText ?? \"\";\n  const report = parseWorkerReport(finalText);\n  const resultEvent: StreamEvent = {\n    type: \"result\",\n    result: finalText,\n    is_error: fold.isError || rc !== 0,\n    num_turns: fold.turns,\n    duration_ms: secs * 1000,\n  };\n  writeEvent(resultEvent);\n\n  const ok = rc === 0 && !fold.isError;\n  status.last = shortText(report?.notes ?? finalText, 90) || (ok ? \"done\" : \"failed\");\n  if (report?.changed?.length) {\n    const verify = verifyReportChanges(report.changed, worktree?.dir ?? cwd, t0);\n    if (!verify.ok) {\n      status.reportValid = false;\n      const note = verifyFailNote(verify);\n      status.last = shortText(note, 90);\n      report.notes = report.notes ? `${report.notes} — ${note}` : note;\n      appendLedger(ledger, \"REPORT-UNVERIFIED\", {\n        id: wid,\n        failures: verify.failures.length,\n        paths: verify.failures.map((f) => f.path).slice(0, 5).join(\",\"),\n      });\n    }\n  }\n  return finaliseRun({\n    logDir,\n    ledger,\n    status,\n    ok,\n    rc,\n    secs,\n    end: {\n      provider: target.providerName,\n      mode: \"headless\",\n      engine: \"codex\",\n      model,\n      turns: status.turns,\n      tools: status.tools,\n      label,\n    },\n    report,\n    fallbackText: finalText,\n    worktree,\n    timedOut: status.timedOut ? a.limit?.minutes : undefined,\n    beforeHandoff: (st, rep) => {\n      if (!a.quiet) printResult(parsed.outputFormat, resultEvent, rc, logDir, wid, rep, worktreeExtras(st));\n    },\n  });\n}\n\n// ---------------------------------------------------------------------------\n// result printing\n// ---------------------------------------------------------------------------\n\nexport function printResult(\n  fmt: \"text\" | \"json\" | \"stream-json\",\n  resultEvent: StreamEvent | null,\n  rc: number,\n  logDir: string,\n  wid: string,\n  report?: WorkerReport | null,\n  extras?: Record<string, unknown>\n): void {\n  if (fmt === \"stream-json\") return; // already mirrored live\n  if (fmt === \"json\") {\n    const payload = report\n      ? { ...(resultEvent ?? { is_error: true, result: \"no result event\", rc }), report, ...extras }\n      : { ...(resultEvent ?? { is_error: true, result: \"no result event\", rc }), ...extras };\n    console.log(JSON.stringify(payload));\n    return;\n  }\n  if (resultEvent) {\n    console.log(resultEvent.result ?? \"\");\n  } else {\n    process.stderr.write(\n      `pai worker: run produced no result (rc=${rc}); see ${eventsPath(logDir, wid)}\\n`\n    );\n  }\n}\n\n// ---------------------------------------------------------------------------\n// providers test: the 90-second pong probe\n// ---------------------------------------------------------------------------\n\nexport interface ProviderTestResult {\n  provider: string;\n  model: string;\n  latencyMs: number;\n  result: string;\n  ok: boolean;\n  /** Set when the probe could not run (e.g. \"codex not installed\"). */\n  skipped?: string;\n}\n\n/**\n * Run a one-word pong probe through the provider (headless, no pane) and\n * report provider, model, latency and the reply. ok is false unless the reply\n * was exactly \"pong\" (case-insensitive, whitespace-trimmed).\n */\nexport async function testProvider(\n  providerName: string,\n  provider: WorkerProvider,\n  logDir: string,\n  timeoutMs = 90_000,\n  caveman = false\n): Promise<ProviderTestResult> {\n  assertProviderRunnable(providerName, provider);\n  const model = provider.models.default;\n\n  if (provider.engine === \"codex\") {\n    const skipped = codexInstalled() ? undefined : \"codex not installed\";\n    return {\n      provider: providerName,\n      model,\n      latencyMs: 0,\n      result: skipped ?? \"codex engine: pong probe through codex exec not implemented\",\n      ok: false,\n      ...(skipped ? { skipped } : {}),\n    };\n  }\n\n  let proxyUrl: string | undefined;\n  if (provider.protocol === \"openai\") {\n    const base = await ensureProxyRunning(DEFAULT_PROXY_PORT, logDir);\n    proxyUrl = `${base}/${providerName}`;\n  }\n  const env = buildRunEnv(provider, true, proxyUrl, providerName);\n  const [bin, ...head] = claudeCommand(env, caveman);\n  const t0 = Date.now();\n  const proc = spawn(\n    bin,\n    [\n      ...head,\n      \"--model\", model,\n      \"--strict-mcp-config\", \"--mcp-config\", ensureNoMcpConfig(logDir),\n      \"-p\", \"Reply with exactly one word: pong\",\n      \"--output-format\", \"json\",\n    ],\n    { env, stdio: [\"ignore\", \"pipe\", \"inherit\"] }\n  );\n  const timer = setTimeout(() => {\n    try { proc.kill(\"SIGKILL\"); } catch { /* already gone */ }\n  }, timeoutMs);\n\n  let out = \"\";\n  proc.stdout.on(\"data\", (chunk: Buffer) => {\n    out += chunk.toString(\"utf8\");\n  });\n  const rc = await new Promise<number>((resolve) => {\n    proc.on(\"error\", () => resolve(1));\n    proc.on(\"close\", (code) => resolve(code ?? 1));\n  });\n  clearTimeout(timer);\n\n  return {\n    provider: providerName,\n    model,\n    latencyMs: Date.now() - t0,\n    result: resultFromOutput(out),\n    ok: rc === 0 && resultFromOutput(out).trim().toLowerCase() === \"pong\",\n  };\n}\n\n/**\n * Pull the reply out of claude's stdout. With --verbose, `--output-format\n * json` dumps a JSON array of stream events and the reply sits in the last\n * \"result\" event; without it, stdout is the single result object. Accept\n * either shape, plus a bare-text fallback for error output.\n */\nexport function resultFromOutput(out: string): string {\n  const trimmed = out.trim();\n  if (!trimmed) return \"\";\n  const parse = (s: string): unknown => {\n    try {\n      return JSON.parse(s);\n    } catch {\n      return undefined;\n    }\n  };\n  const fromValue = (v: unknown): string | null => {\n    if (Array.isArray(v)) {\n      for (let i = v.length - 1; i >= 0; i--) {\n        const r = fromValue(v[i]);\n        if (r !== null) return r;\n      }\n      return null;\n    }\n    if (typeof v === \"object\" && v !== null) {\n      const o = v as StreamEvent;\n      if (o.type === \"result\" && typeof o.result === \"string\") return o.result;\n    }\n    return null;\n  };\n  const direct = fromValue(parse(trimmed));\n  if (direct !== null) return direct;\n  const lines = trimmed.split(\"\\n\");\n  for (let i = lines.length - 1; i >= 0; i--) {\n    const r = fromValue(parse(lines[i]));\n    if (r !== null) return r;\n  }\n  return trimmed.slice(0, 200);\n}\n"],"mappings":"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"}