@ordewell/core 0.10.7 → 0.10.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/plan-utils.ts","../src/models/Task.ts","../src/conversation/skillTokens.ts","../src/services/PlanTree.ts","../src/services/TaskRefs.ts","../src/services/TaskOps.ts","../src/taskRow/status.ts","../src/services/PlannedTask.ts","../src/services/ModelAllowlistResolver.ts","../src/services/researchStepSummary.ts","../src/conversation/format.ts","../src/services/harness/agentTools.ts","../src/conversation/records.ts","../src/services/blocking.ts","../src/services/SessionMessage.ts","../src/services/conflictFiles.ts","../src/services/runSettingsText.ts","../src/models/Usage.ts","../src/conversation/lanes.ts","../src/conversation/reduce.ts","../src/conversation/transcript.ts","../src/utils/sameMessage.ts","../src/conversation/taskLog.ts","../src/conversation/promptHold.ts","../src/conversation/turnGate.ts","../src/conversation/detail.ts","../src/conversation/notices.ts","../src/conversation/markdown.ts","../src/conversation/taskLogFollow.ts","../src/taskRow/actions.ts","../src/services/AssignmentScope.ts","../src/taskRow/view.ts","../src/taskRow/texts.ts","../src/services/runView.ts"],"sourcesContent":["/**\n * Browser-safe entry point: pure plan-validation utilities with no Node or\n * AI-service dependencies. UI surfaces (the VS Code webview runs in a browser)\n * import runtime values from here instead of the main barrel, which bundles the\n * Gemini/OpenAI services and their `fs`/`child_process` imports.\n */\nexport { canMergeTasks, canSplitTask, canSetDependencies, dependencyCandidates, dependentsOf } from './services/TaskOps';\nexport type { TaskRef } from './services/TaskOps';\nexport { summarizeToolCall } from './services/researchStepSummary';\nexport { truncateCheckpointSummary, CHECKPOINT_TRUNCATE_LENGTH } from './services/SessionMessage';\nexport { capConflictFiles } from './services/conflictFiles';\nexport { blockingFailures, type BlockingSubject } from './services/blocking';\nexport { SUPERVISOR_LEVEL_LABEL, parseCount } from './services/runSettingsText';\n// The shared conversation view (#51) is pure too, so every surface — a webview\n// included — draws from the same reducer.\nexport * from './conversation';\n// The task row view is pure for the same reason: the webview draws a task card\n// from the facts the TUI paints its plan row from.\nexport * from './taskRow';\nexport { taskOrderLabel, taskRef, taskRefOf, titledTaskRef, titledTaskRefOf, resolveTaskRef, resolveUserTaskRef } from './services/TaskRefs';\nexport type { RefTask } from './services/TaskRefs';\n// The one runner default, shared with the webview so its initial state cannot\n// drift from the plans the host builds.\nexport { DEFAULT_RUNNERS, pausedOnLimit } from './models/Task';\n// The run view is pure too: a surface seeds its state from the one empty run\n// rather than re-declaring the shape.\nexport { EMPTY_RUN } from './services/runView';\n\nexport * from './models/Usage';\n\nexport { walkPlan, taskPlacement, subtreeIds } from './services/PlanTree';\nexport type { TreeTask, TaskPlacement } from './services/PlanTree';\n\n// The one rule for the effort a model change keeps, so a surface's model\n// picker lands where core's resolver would.\nexport { clampThinkingEffort } from './services/ModelAllowlistResolver';\n","import { v4 as uuidv4 } from 'uuid';\nimport type { PlanIsolation } from '../interfaces/IWorktreeIsolation';\nimport type { AttemptUsage, PlannerUsage, UsageRecord, UsageTotals } from './Usage';\nimport type { ExecutionRecord, SupervisorLevel } from './Execution';\nimport type { SkillSource } from '../services/SkillsService';\nimport type { SupervisionMemorySnapshot } from '../services/LoopGuards';\nimport type { SupervisorSnapshot } from '../services/Supervisor';\nimport { SKILL_NAME_PATTERN } from '../conversation/skillTokens';\nimport { subtreeIds, walkPlan } from '../services/PlanTree';\n\nexport interface UserStep {\n order: number;\n instruction: string;\n completed: boolean;\n}\n\n/** One deterministic signal gathered while verifying a completed task. `completion_marker` is only in verdicts saved before completion was reported through `task_complete` alone. */\nexport interface VerificationCheck {\n name: 'exit_code' | 'completion_marker' | 'task_complete' | 'manual';\n passed: boolean;\n /** A check that did not apply. Skipped checks don't affect the verdict. */\n skipped: boolean;\n detail: string;\n}\n\n/** Evidence-based verdict for a completed task. Single end-to-end outcome produced by verification. */\nexport interface Verdict {\n outcome: 'pass' | 'fail';\n reason: string;\n checks: VerificationCheck[];\n decidedAt: string;\n}\n\nexport interface TaskOutputSummary {\n reviewReason: string;\n /** The `task_complete` summary, the task's report; absent when the attempt ended without one, and from sessions saved before it was kept. */\n report?: string;\n /** Empty when there is a report: the turn's final text is the report itself. */\n logTail: string;\n capturedAt: string;\n}\n\nexport type TaskType = 'ai' | 'user';\n/**\n * `skipped` is terminal and verdict-less: the task will not be waited for, and\n * nothing it did lands. Its dependents go ahead without it once the work it\n * waited on is done. There is no stored `blocked`: a task is blocked when a\n * failed dependency says so (ADR-0034), and a file that kept the old status\n * loads as pending.\n */\nexport type TaskStatus = 'pending' | 'approved' | 'in_progress' | 'completed' | 'failed' | 'awaiting_user' | 'skipped';\nexport type TaskMode = string;\n\n/**\n * Why an `awaiting_user` task waits (ADR-0018, W1): a structured turn that\n * ended without a `task_complete` call, a checkpoint question, work that did not\n * land, an ops task that changed tracked files (ADR-0020), or its runner's\n * usage limit. Saved, so no surface has to guess it from whether an attempt\n * is live.\n */\nexport type AwaitingReason = 'input' | 'checkpoint' | 'conflict' | 'files-changed' | 'usage-limit';\n\nexport function isAwaitingReason(value: unknown): value is AwaitingReason {\n return value === 'input' || value === 'checkpoint' || value === 'conflict' || value === 'files-changed' || value === 'usage-limit';\n}\n\nexport interface TaskModelAssignment {\n modelId: string;\n modelLabel: string;\n thinkingEffort?: string;\n /**\n * All variant ids the model offered when this assignment was made. Carried\n * on the assignment because runners need it at spawn time (opencode's TUI\n * only honors an assigned variant when the others are config-disabled) and\n * the discovery catalog isn't available there.\n */\n availableVariants?: string[];\n}\n\nexport type RunnerId = string;\n\n/**\n * Bring loaded tasks to the structured-only shape, in place. A task saved\n * while the terminal transport existed may say it ran there, and why; neither\n * means anything now, and such a task left no session to continue. Its\n * completion marker id went with the text markers: completion is reported\n * only through `task_complete`.\n */\nexport function migrateLoadedTasks(tasks: readonly Task[]): void {\n for (const task of tasks) {\n if (typeof task.runnerSessionId !== 'string') delete task.runnerSessionId;\n if (typeof task.carriedFrom !== 'string') delete task.carriedFrom;\n if (typeof task.runnerSessionOwner !== 'string') delete task.runnerSessionOwner;\n const legacy = task as Task & { transport?: { kind?: unknown; nativeSessionId?: unknown } };\n if (!task.runnerSessionId && legacy.transport?.kind === 'structured' && typeof legacy.transport.nativeSessionId === 'string') {\n task.runnerSessionId = legacy.transport.nativeSessionId;\n }\n delete legacy.transport;\n delete (task as { completionMarker?: unknown }).completionMarker;\n // The effort once had a second home on the task; the spawn reads only the model's.\n const effort = (task as { thinkingEffort?: unknown }).thinkingEffort;\n if (typeof effort === 'string' && task.assignedModel && !task.assignedModel.thinkingEffort) task.assignedModel.thinkingEffort = effort;\n delete (task as { thinkingEffort?: unknown }).thinkingEffort;\n migrateLoadedTasks(task.subtasks ?? []);\n }\n}\n\n/**\n * A task skill as one attempt received it: read from the task's own worktree\n * (or global) at spawn, kept so the user can see what the runner was told\n * even after the skill's file changes.\n */\nexport interface TaskSkillSnapshot {\n name: string;\n source: SkillSource;\n path: string;\n content: string;\n}\n\n/** A task skill as a surface is told of it: the body stays in the task's log file and the session. */\nexport type TaskSkillNotice = Omit<TaskSkillSnapshot, 'content'>;\n\nexport interface Task {\n id: string;\n order: number;\n title: string;\n description: string;\n type: TaskType;\n status: TaskStatus;\n dependencies: string[];\n prompt?: string;\n userSteps?: UserStep[];\n subtasks: Task[];\n verdict?: Verdict;\n outputSummary?: TaskOutputSummary;\n assignedModel?: TaskModelAssignment;\n assignedRunner: RunnerId;\n taskMode?: TaskMode;\n autonomy?: 'AFK' | 'HITL';\n sliceType?: 'HITL' | 'AFK';\n userStoriesCovered?: string[];\n /** The runner's saved session for a later continue; cleared when a fresh attempt starts. */\n runnerSessionId?: string;\n /**\n * The runner that session belongs to: a session cannot cross runners, so\n * Continue is offered only while the task is still assigned to it. Absent\n * on a plan saved before it was recorded; the last attempt's runner stands\n * in (see `sessionOwner`).\n */\n runnerSessionOwner?: RunnerId;\n /** Set only while `status` is `awaiting_user`, and not always then — a pause saved by an older build has none. */\n awaitingReason?: AwaitingReason;\n /**\n * When a task paused on its runner's usage limit is resumed on its own (ISO\n * time): the reset the runner announced, plus a short margin. Absent when no\n * reset time could be read or the user cancelled the resume — the task then\n * waits for a manual retry. Set only with `awaitingReason` `usage-limit`.\n */\n resumeAt?: string;\n /**\n * The runner a task paused on its usage limit was moved off (ADR-0018, U1):\n * its next attempt is a carry-over, a fresh session that starts from that\n * attempt's files. Cleared once that attempt runs, and by a retry.\n */\n carriedFrom?: RunnerId;\n /** Why the task was skipped, as whoever skipped it put it; set only while `status` is `skipped`, and not always then. */\n skipReason?: string;\n /**\n * An ops task (ADR-0020): it changes no repository files, runs at the\n * workspace root rather than in a worktree, and waits for the change tasks\n * it depends on to be merged into the user's branch. Top-level AI tasks\n * only; absent means a change task.\n */\n ops?: boolean;\n /**\n * The dependencies, by title, whose work was not merged into the user's\n * branch when the user force-started this task past its merge gate\n * (ADR-0020). Cleared when the task is retried.\n */\n forcedPastGate?: string[];\n /**\n * Task skills (`applies-to: task`) attached by name. Their bodies are put in\n * the runner's prompt at spawn, resolved where the task runs — a subtask's\n * are its own, never its parent's. Absent means none.\n */\n skills?: string[];\n /** The skills the latest attempt was given, as read when it spawned. */\n attemptSkills?: TaskSkillSnapshot[];\n /**\n * Who put the task in the plan, when it was not the user's own planning:\n * `supervisor` for a task an Act supervisor added during a run, which\n * counts as approved to run (ADR-0029). Set by the session, never by an op.\n */\n addedBy?: 'supervisor';\n attemptUsage?: AttemptUsage[];\n}\n\nexport interface DiscoveredMode {\n id: string;\n label: string;\n description: string;\n}\n\nexport type ResearchToolType =\n | 'read_file' | 'read_files' | 'glob' | 'grep' | 'find_symbol' | 'list_dir'\n | 'bash' | 'fetch' | 'web_search' | 'spawn_research_agent'\n | 'task_query' | 'task_output' | 'task_diff'\n /**\n * A tool belonging to a harness planner's own toolbox (ADR-0009) that has no\n * Ordewell equivalent — Edit, WebFetch, TodoWrite, whatever a coding agent\n * ships next. The real name travels in `toolLabel` rather than being\n * relabelled as a tool it is not; the union stays closed so the\n * exhaustiveness checks in every surface's icon/label switch survive.\n */\n | 'agent_tool';\n\n/**\n * What happened when a research tool call ran, for honest per-surface\n * rendering. The broadcast seam carries this on every `research_step_done` so\n * surfaces do not have to pattern-match refusal text to tell a refused `rm`\n * from a successful `rm` — the old render path flipped a `✓` for both.\n */\nexport type ResearchStepOutcome = 'success' | 'failure' | 'refused' | 'denied' | 'not_executed';\n\nexport interface ResearchStep {\n id: string;\n tool: ResearchToolType;\n /** The tool's own name when it came from a harness planner — always set for `agent_tool`. */\n toolLabel?: string;\n args: string;\n result: string;\n success: boolean;\n outcome: ResearchStepOutcome;\n /** The model's tool_call id, so a surface can match `tool_result` to the\n * pending `tool_call` it announced — robust under parallel same-tool rounds. */\n toolCallId?: string;\n /** The research subagent that ran the call, so a reload regroups it under that subagent. */\n subagentId?: string;\n timestamp: string;\n thinkingText?: string;\n}\n\nexport interface UserPromptEntry {\n id: string;\n type: 'user_prompt' | 'system';\n content: string;\n timestamp: string;\n}\n\nexport type SubagentOutcome = 'done' | 'failed' | 'stopped';\n\n/**\n * One subagent's whole run, logged when it finishes: what it was asked, how it\n * ended and what it reported. Its steps stay separate entries carrying the same\n * `subagentId`, so an older reader that knows only steps still shows them.\n */\nexport interface SubagentLogEntry {\n id: string;\n type: 'subagent';\n subagentId: string;\n brief: string;\n model?: string;\n outcome: SubagentOutcome;\n digest: string;\n usage?: UsageTotals;\n timestamp: string;\n}\n\nexport type ResearchLogEntry = ResearchStep | UserPromptEntry | SubagentLogEntry;\n\nexport interface ResearchProgress {\n // 'liveness' carries no content: a raw-line signal from the harness process\n // (ADR-0009) that reaches a surface even when a turn is producing nothing\n // visible — a subagent's filtered chatter, most often — so an idle watchdog\n // downstream doesn't mistake \"nothing to show\" for \"nothing happening\".\n //\n // The turn-scoped kinds below carry one planner turn's stream (#47); see the\n // matching SessionMessage variants for the invariants each one keeps.\n // 'text_delta' is reply text as the model streams it (`text`, `segmentId`),\n // an envelope included: the turn's owner routes each segment to prose or to\n // the plan display, so no backend has to tell them apart. 'text_retracted'\n // takes back an attempt's text: `segmentId`'s, or when absent everything the\n // backend call that sends it has streamed.\n // 'usage' reports one model call (`record`). 'subagent_started' carries\n // `brief` and `model`; 'subagent_finished' carries `outcome`, `digest` and\n // `usage`.\n type:\n | 'thinking' | 'tool_call' | 'tool_result' | 'plan_token' | 'interrupted' | 'liveness'\n | 'text_delta' | 'text_retracted' | 'usage' | 'subagent_started' | 'subagent_finished';\n /** Minted by whoever runs the turn and passed through untouched; absent outside a turn. */\n turnId?: string;\n /** One continuous run of model text — text before a tool call is its own segment. */\n segmentId?: string;\n text?: string;\n tool?: string;\n /** Harness planners (ADR-0009): the agent's own name for a tool Ordewell has no member for. */\n toolLabel?: string;\n toolArgs?: string;\n toolResult?: string;\n planToken?: string;\n step?: ResearchStep;\n /** The model's tool_call id, threaded on tool_call and tool_result so a\n * surface can match the result to its pending call — robust under parallel\n * same-tool rounds where LIFO-by-name matching mislabels summaries. */\n toolCallId?: string;\n /** Present when this event originates from (or reports on) one spawned research subagent (issue #34). */\n subagentId?: string;\n record?: UsageRecord;\n brief?: string;\n model?: string;\n outcome?: SubagentOutcome;\n digest?: string;\n usage?: UsageTotals;\n}\n\nexport interface ThinkingBlock {\n id: string;\n text: string;\n}\n\nexport interface StreamThinkingEvent {\n type: 'thinking';\n block: ThinkingBlock;\n}\n\nexport interface StreamStepEvent {\n type: 'step';\n step: ResearchStep;\n}\n\nexport type StreamEvent = StreamThinkingEvent | StreamStepEvent;\n\nexport interface DiscoveredModel {\n modelId: string;\n modelLabel: string;\n runnerProvider?: string;\n /**\n * Human-facing provider name as the runner itself reports it (e.g.\n * \"OpenCode Zen\" for `runnerProvider: 'opencode'`). Populated from the\n * runner's own provider catalog when available; when absent the UI derives a\n * label from `runnerProvider` by title-casing.\n */\n runnerProviderLabel?: string;\n /**\n * The runner whose catalog listed this model. Stamped once, at the single\n * `ModelDiscovery.discover` choke point, so a flat cross-runner list can\n * still say where each entry came from — `runnerProvider` alone cannot:\n * OpenCode reports most of its catalog as `openrouter`, which names the\n * serving backend, not the agent Ordewell would spawn.\n */\n runnerId?: string;\n /** The runner's display name (`OpenCode`), from its manifest. */\n runnerLabel?: string;\n variants: { id: string; label: string }[];\n /**\n * The model's context window when the runner or catalog reports it (#49).\n * Read by the planner-model lookup so context fill can be shown; absent when\n * unknown rather than defaulted to zero.\n */\n contextWindow?: number;\n}\n\nexport type PlanStatus = 'draft' | 'approved' | 'rejected' | 'running' | 'completed';\n\n/**\n * One entry of the planner's persisted dialogue (ADR-0002). The single source\n * of truth for both UI redisplay and conversational context. Tool-call results\n * are NOT stored here — they live in the AI service's tool-use history;\n * `researchLog` remains the persisted tool trace for the UI.\n */\nexport interface ConversationMessage {\n role: 'user' | 'assistant';\n content: string;\n timestamp: string;\n /**\n * Timeline marker: 'plan_generated' records the point in the dialogue where\n * the plan was committed (the UI anchors the plan card there on restore);\n * 'system' is a host-injected notice; 'compaction' is the summary a\n * user-triggered compaction left in place of the earlier messages — always\n * the transcript's first entry. 'skill_load' is a skill loaded into the\n * conversation, its snapshot in `skill`; one the user invoked follows the\n * message that named it. 'execution' is a call at the command seam\n * (ADR-0029), its record in `execution`. 'wake_up' is the digest a wake-up\n * gave the supervisor (role 'user': the model was told it), and\n * 'supervisor' what the supervisor said in a wake-up turn (ADR-0029).\n * 'error' is a planner turn that ended on the planner's usage limit, drawn\n * as a failure and never replayed to the planner: it is not the planner's\n * answer, and its inputs are sent again (see {@link PlannerResendState}).\n * Absent for ordinary chat turns, so sessions saved before markers existed\n * degrade gracefully.\n */\n kind?: 'plan_generated' | 'system' | 'compaction' | 'skill_load' | 'execution' | 'wake_up' | 'supervisor' | 'error';\n actor?: 'Ordewell setting';\n /** Present exactly when `kind` is 'skill_load'. */\n skill?: SkillLoad;\n /** Present exactly when `kind` is 'execution'. */\n execution?: ExecutionRecord;\n /** A user's message that was force sent, stopping the turn before it (ADR-0023). */\n forced?: true;\n /**\n * What a reply showed, run by run, where each began (ADR-0017 A1). Beside\n * `content`, which stays the reply as the planner is told it. Absent on\n * entries saved before runs were kept, which reload as one message.\n */\n runs?: ReplyRun[];\n}\n\n/**\n * One run of a planner reply's text: the segment it streamed under, its\n * settled text, and when it began. A run that never streamed (a message the\n * conversation wrote in the planner's place) has a segment no stream used.\n */\nexport interface ReplyRun {\n segmentId: string;\n text: string;\n /** ISO timestamp. */\n startedAt: string;\n}\n\n/**\n * A skill's SKILL.md as it was when loaded into a planner conversation. A\n * snapshot rather than a reference: a resumed, forked or rewound conversation\n * replays the body the planner originally saw, even after the file changed or\n * was deleted.\n */\nexport interface SkillLoad {\n invokedBy: 'user' | 'planner';\n name: string;\n source: SkillSource;\n /** The SKILL.md that won, home-abbreviated (`~/...`): which copy loaded is what a reader needs from it. */\n path: string;\n content: string;\n /**\n * Set when the user named a task skill: it is not loaded into the planner's\n * context, which is only told to attach it to the tasks it fits. `content`\n * is empty; the description is what the planner's directive quotes.\n */\n attaches?: { description: string };\n}\n\n/** A skill load as a surface announces it — the body stays with the transcript. */\nexport type SkillLoadNotice = Omit<SkillLoad, 'content'>;\n\n/** A message the user sent, as opposed to a skill load their message caused or a wake-up digest. */\nexport function isUserMessage(entry: Pick<ConversationMessage, 'role' | 'kind'>): boolean {\n return entry.role === 'user' && entry.kind !== 'skill_load' && entry.kind !== 'wake_up';\n}\n\n/** A follow-up an older build queued behind a run's batch boundary; read only to carry it over as a {@link PendingPlanTurn}. */\nexport interface QueuedMessage {\n id: string;\n text: string;\n timestamp: string;\n skills?: SkillLoad[];\n}\n\n/** Who a planner turn answers (ADR-0029): the user's message, or a wake-up batch the supervisor is given. */\nexport type PlanTurnSource = 'user' | 'supervisor';\n\n/**\n * A planner turn's input not yet answered by a turn that ended. It leaves the\n * plan with the change its turn made, in the same save, so a reload replays\n * exactly the inputs no turn answered — once. A supervisor's input is a\n * wake-up batch not yet delivered (ADR-0029): it stays until a turn lands\n * with it, whatever turns fail meanwhile.\n */\nexport interface PendingPlanTurn {\n id: string;\n source: PlanTurnSource;\n /** The user's message, or a wake-up batch's digest. */\n text: string;\n timestamp: string;\n /** What its `/name` tokens loaded when it was sent, so a replay sends the same skills. */\n skills?: SkillLoad[];\n /** Force sent: it waits ahead of every input not forced, and its turn is its own (ADR-0023, F2). */\n forced?: true;\n}\n\n/**\n * The run's own copy of the user's run settings (ADR-0030): taken when the\n * user starts it, changed at once by a change made in this session, and\n * lowered by a tripped guard or a failed supervisor.\n */\nexport interface RunSettings {\n mergeAtGatesAutomatically: boolean;\n /** Absent on a run started before supervisor levels existed: Off. */\n supervisorLevel?: SupervisorLevel;\n /** Absent on a run started before ADR-0030: the user's setting. */\n supervisorRetryLimit?: number;\n /** Absent on a run started before ADR-0030: the user's setting. */\n wakeUpReadBudget?: number;\n /** Why the supervisor stopped for the rest of this run, which carries on as Off; absent while it watches. */\n unsupervised?: string;\n}\n\n/**\n * What supervision remembers across a daemon restart (ADR-0029): the loop\n * guards' memory and the wake-up state not yet delivered with a turn.\n */\nexport interface SupervisionSnapshot {\n /** Retries, failed-attempt shapes, the supervisor's edits and what the user was told. */\n guards?: SupervisionMemorySnapshot;\n /** The events inside their debounce window and the wake-up rate's timestamps. */\n wake?: SupervisorSnapshot;\n}\n\n/**\n * What waits on the planner's usage limit. With `at`, the inputs no turn\n * answered are sent again then, on their own; without it — the reset could\n * not be read, the resend hit the limit again, or it was cancelled — they go\n * with the next input: the user's message, or a wake-up.\n */\nexport interface PlannerResendState {\n /** The runner whose account hit the limit; a planner on another one is not held by it. */\n runner?: RunnerId;\n at?: string;\n}\n\nexport interface LegacyPlanState {\n runSettings?: RunSettings;\n /** What supervision remembers across a daemon restart (ADR-0029); absent on plans saved before it existed. */\n supervision?: SupervisionSnapshot;\n tasks: Task[];\n generatedAt: string;\n status: PlanStatus;\n runners: RunnerId[];\n lastUpdated: string;\n researchLog?: ResearchLogEntry[];\n /** The planner dialogue — user messages and assistant messages, in order (ADR-0002). */\n conversationHistory?: ConversationMessage[];\n /** Full markdown PRD once written by the planner (PRD mode), also saved to .scratch/<slug>/PRD.md. */\n prdMarkdown?: string;\n /** Planner turn inputs no turn has answered yet (ADR-0029); a reload replays them. */\n pendingTurns?: PendingPlanTurn[];\n /** Written by builds that queued mid-run edits; a load moves it into {@link pendingTurns}. */\n queuedMessages?: QueuedMessage[];\n /**\n * The plan's isolation run (ADR-0013), written from the orchestrator at\n * persist time and read back only when a saved plan is adopted. It names\n * branches and worktrees that belong to this plan alone: a fork of the plan\n * must leave it behind rather than share it.\n */\n isolation?: PlanIsolation;\n /** Kept so a reopened session shows the same token line (#49). */\n plannerUsage?: PlannerUsage;\n /** The planner hit its usage limit and the inputs its turn took wait to be sent again; absent otherwise. */\n plannerResend?: PlannerResendState;\n /**\n * The tasks the user approved to run: every task when they executed the\n * plan, and each one they started or retried themselves since. A command\n * from anyone else starts only these (ADR-0029); a task the planner added\n * after the approval waits for the user's. Only tasks still in the plan: a\n * task that leaves takes its approval with it.\n */\n approvedTasks?: string[];\n /**\n * The user approved the plan to run: Execute plan, signing off a review, or\n * autorun's start (ADR-0029, ADR-0030). Kept apart from {@link status},\n * which surfaces rewrite for display; a user's start of one task approves\n * that task, not the plan.\n */\n approved?: boolean;\n}\n\nexport interface Message {\n id: string;\n role: 'user' | 'planner' | 'system';\n content: string;\n timestamp: number;\n}\n\nexport interface TaskSnapshot extends Task {\n completedAt: number;\n verdict?: Verdict;\n retryCount: number;\n finalized: boolean;\n}\n\n/** The plan a surface reads whole carries the approval record, so it can tell which tasks wait for the user (ADR-0035). */\nexport type PlanState = (\n | {\n phase: 'planning';\n history: Message[];\n message: string;\n pendingTasks: Task[];\n }\n | {\n phase: 'executing';\n history: Message[];\n message: string;\n executionLog: TaskSnapshot[];\n pendingTasks: Task[];\n goal: string;\n runners: string[];\n status: PlanStatus;\n }\n) & ApprovalRecord;\n\nfunction hasPhase(raw: unknown): raw is PlanState {\n return typeof raw === 'object' && raw !== null && 'phase' in raw;\n}\n\nfunction hasTasks(raw: unknown): raw is LegacyPlanState {\n return typeof raw === 'object' && raw !== null && 'tasks' in raw && Array.isArray((raw as Record<string, unknown>).tasks);\n}\n\nfunction logEntryToMessage(entry: ResearchLogEntry): Message {\n const timestamp = new Date(entry.timestamp).getTime();\n if (!('type' in entry)) {\n return { id: entry.id, role: 'system', content: JSON.stringify({ tool: entry.tool, args: entry.args, result: entry.result }), timestamp };\n }\n if (entry.type === 'subagent') {\n const { subagentId, brief, outcome, digest } = entry;\n return { id: entry.id, role: 'system', content: JSON.stringify({ subagentId, brief, outcome, digest }), timestamp };\n }\n return { id: entry.id, role: entry.type === 'user_prompt' ? 'user' : 'system', content: entry.content, timestamp };\n}\n\nfunction migrateHistory(raw: LegacyPlanState): Message[] {\n const messages: Message[] = [];\n\n if (raw.researchLog) {\n messages.push(...raw.researchLog.map(logEntryToMessage));\n }\n\n if (raw.queuedMessages) {\n for (const qm of raw.queuedMessages) {\n messages.push({\n id: qm.id,\n role: 'system',\n content: qm.text,\n timestamp: new Date(qm.timestamp).getTime(),\n });\n }\n }\n\n return messages;\n}\n\nexport function migratePlanState(raw: unknown): PlanState {\n if (hasPhase(raw)) return raw;\n\n if (!hasTasks(raw)) {\n return {\n phase: 'planning',\n history: [],\n message: '',\n pendingTasks: [],\n };\n }\n\n const hasExecution = raw.tasks.some(\n (t) => t.status === 'completed' || t.status === 'failed',\n );\n\n const messages = migrateHistory(raw);\n const record = approvalRecordOf(raw);\n\n if (hasExecution) {\n const executionLog: TaskSnapshot[] = raw.tasks\n .filter((t) => t.status === 'completed' || t.status === 'failed')\n .map((t) => ({\n ...t,\n completedAt: new Date(raw.lastUpdated).getTime(),\n verdict: t.verdict,\n retryCount: 0,\n finalized: true,\n }));\n\n const pendingTasks = raw.tasks.filter(\n (t) => t.status !== 'completed' && t.status !== 'failed',\n );\n\n return {\n phase: 'executing',\n history: messages,\n message: '',\n executionLog,\n pendingTasks,\n goal: '',\n runners: raw.runners,\n status: raw.status,\n ...record,\n };\n }\n\n return {\n phase: 'planning',\n history: messages,\n message: '',\n pendingTasks: raw.tasks,\n ...record,\n };\n}\n\nexport { taskOrderLabel, taskRef, taskRefOf, titledTaskRef, titledTaskRefOf, resolveTaskRef, resolveUserTaskRef } from '../services/TaskRefs';\n\nexport function createTask(overrides: Partial<Task> = {}): Task {\n const skills = skillNames(overrides.skills);\n return {\n id: overrides.id ?? uuidv4(),\n order: overrides.order ?? 0,\n title: overrides.title ?? '',\n description: overrides.description ?? '',\n type: overrides.type ?? 'ai',\n status: overrides.status ?? 'pending',\n dependencies: overrides.dependencies ?? [],\n prompt: overrides.prompt,\n userSteps: overrides.userSteps,\n subtasks: overrides.subtasks ?? [],\n verdict: overrides.verdict,\n outputSummary: overrides.outputSummary,\n ...(overrides.attemptUsage ? { attemptUsage: structuredClone(overrides.attemptUsage) } : {}),\n assignedModel: overrides.assignedModel,\n assignedRunner: overrides.assignedRunner ?? DEFAULT_RUNNERS[0],\n taskMode: overrides.taskMode ?? 'build',\n autonomy: overrides.autonomy,\n sliceType: overrides.sliceType,\n userStoriesCovered: overrides.userStoriesCovered,\n ...(opsFlag(overrides.ops, overrides.type) ? { ops: true } : {}),\n ...(skills ? { skills } : {}),\n ...(overrides.addedBy === 'supervisor' ? { addedBy: 'supervisor' as const } : {}),\n };\n}\n\n/**\n * A name a skill can have, lower-cased as `/name` is. Anything else — a path\n * separator, `..` — is joined into a path and could only reach outside the\n * skill dirs.\n */\nconst SKILL_NAME = new RegExp(`^${SKILL_NAME_PATTERN}$`);\n\nexport function isSkillName(name: string): boolean {\n return SKILL_NAME.test(name);\n}\n\n/**\n * The `skills` field as a task stores it, however it arrived: the planner's\n * JSON is untyped. Names are trimmed, lower-cased and deduplicated, and one\n * no skill could have is dropped; none at all is stored absent, so a plan\n * without skills reads exactly as it did before them.\n */\nexport function skillNames(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const names = [...new Set(value.filter((v): v is string => typeof v === 'string').map((v) => v.trim().toLowerCase()).filter(isSkillName))];\n return names.length > 0 ? names : undefined;\n}\n\n/**\n * The skills of a task a merge or a split makes from others: what the edit\n * chose when it named any, none when it chose an explicit `[]`, else what the\n * tasks it came from had — a malformed value is not a request to drop them.\n */\nexport function inheritedSkills(chosen: unknown, inherited: readonly string[] | undefined): string[] | undefined {\n if (Array.isArray(chosen) && chosen.length === 0) return undefined;\n return skillNames(chosen) ?? skillNames(inherited);\n}\n\n/**\n * The `ops` flag as a task stores it (ADR-0020), however it arrived. Only a\n * literal `true` on an AI task marks an ops task: the planner's JSON is\n * untyped, and a quoted \"true\" read as ops would move a task out of its\n * worktree. Anything else is a change task, stored absent so saved plans need\n * no migration. Whether the task may be ops at all — a subtask may not — is\n * for whoever knows where it sits: the planner intake refuses it (`checkPlanInvariants`).\n */\nexport function opsFlag(value: unknown, type: Task['type'] = 'ai'): true | undefined {\n return value === true && type === 'ai' ? true : undefined;\n}\n\n/**\n * The flag of a task a merge or a split makes from others: what the edit\n * chose, else ops only when every task it came from was. A merge that takes\n * in a change edits files, so it is a change; a split part runs where its\n * task did.\n */\nexport function inheritedOps(from: readonly Pick<Task, 'ops'>[], chosen?: boolean): boolean {\n return chosen ?? from.every((t) => opsFlag(t.ops) === true);\n}\n\n/**\n * The runner set a plan has until one is chosen. The one runner named outside\n * its declaration on purpose: a default is a product choice that no manifest\n * or connector implies.\n */\nexport const DEFAULT_RUNNERS: readonly RunnerId[] = ['claude-code'];\n\nexport function createEmptyPlan(): LegacyPlanState {\n return {\n tasks: [],\n generatedAt: new Date().toISOString(),\n status: 'draft',\n runners: [...DEFAULT_RUNNERS],\n lastUpdated: new Date().toISOString(),\n };\n}\n\nexport function flattenTasks(tasks: readonly Task[]): Task[] {\n return [...walkPlan(tasks)].map(({ task }) => task);\n}\n\n/**\n * A phase-tagged plan rejoined into its tree. The execution log is flat — a\n * finished subtask is logged on its own as well as inside its parent — and in\n * the order tasks finished, so read as a list it puts subtasks at the top level\n * under orders that clash with real top-level tasks. A task's own entry is the\n * latest word on it: its parent's copy was taken when the parent last changed.\n */\nexport function rejoinPlanTree<T extends { id: string; order: number; subtasks?: T[] }>(pending: readonly T[], log: readonly T[]): T[] {\n const latest = new Map<string, T>();\n for (const task of [...pending, ...log]) latest.set(task.id, task);\n const nested = new Set<string>();\n const markNested = (task: T): void => {\n for (const sub of task.subtasks ?? []) {\n nested.add(sub.id);\n markNested(sub);\n }\n };\n for (const task of latest.values()) markNested(task);\n const rebuild = (task: T): T => {\n const own = latest.get(task.id) ?? task;\n return own.subtasks?.length ? { ...own, subtasks: own.subtasks.map(rebuild) } : own;\n };\n return [...latest.values()].filter((task) => !nested.has(task.id)).map(rebuild).sort((a, b) => a.order - b.order);\n}\n\n/**\n * A flattened task with the parent it hangs under, null for a top-level task,\n * and the path label and reference (`#2.1.3`) `TaskRefs` renders for it.\n */\nexport interface TaskWithParent {\n task: Task;\n parent: Task | null;\n label: string;\n ref: string;\n}\n\nexport function flattenTasksWithParents(tasks: readonly Task[]): TaskWithParent[] {\n return [...walkPlan(tasks)].map(({ task, parent, label }) => ({ task, parent: parent ?? null, label, ref: `#${label}` }));\n}\n\nexport function addTaskToPlan(tasks: readonly Task[], partial: Partial<Task>): Task[] {\n const maxOrder = tasks.reduce((max, t) => Math.max(max, t.order), 0);\n const newTask = createTask({\n ...partial,\n order: partial.order ?? maxOrder + 1,\n status: 'pending',\n });\n return renumberTasks([...tasks, newTask]);\n}\n\nexport function removeTaskFromPlan(tasks: readonly Task[], taskId: string): Task[] {\n const removed = subtreeIds(tasks, taskId);\n const prune = (level: readonly Task[]): Task[] => level\n .filter((t) => !removed.has(t.id))\n .map((t) => ({\n ...t,\n dependencies: t.dependencies.filter((depId) => !removed.has(depId)),\n subtasks: prune(t.subtasks),\n }));\n return renumberTasks(prune(tasks));\n}\n\nexport function updateTaskInPlan(tasks: readonly Task[], taskId: string, changes: Partial<Task>): Task[] {\n return renumberTasks(\n tasks.map((t) => {\n if (t.id === taskId) return { ...t, ...changes, id: t.id };\n return { ...t, subtasks: updateTaskInPlan(t.subtasks, taskId, changes) };\n })\n );\n}\n\nexport function renumberTasks(tasks: readonly Task[]): Task[] {\n return tasks.map((t, i) => ({\n ...t,\n order: i + 1,\n subtasks: renumberTasks(t.subtasks),\n }));\n}\n\n/** A task paused on its runner's usage limit, whether it resumes on its own or waits for the user (#84). */\nexport function pausedOnLimit(task: Readonly<Task>): boolean {\n return task.status === 'awaiting_user' && task.awaitingReason === 'usage-limit';\n}\n\n/** A task paused on a usage limit that resumes on its own when the limit resets (#84). */\nexport function waitsForReset(task: Readonly<Task>): boolean {\n return pausedOnLimit(task) && !!task.resumeAt;\n}\n\n/** The user's approval record, as a plan carries it (ADR-0029). */\nexport type ApprovalRecord = Pick<LegacyPlanState, 'approved' | 'approvedTasks'>;\n\n/** A copy of the plan's approval record, for a plan read whole; a field the plan lacks stays absent. */\nexport function approvalRecordOf(plan: ApprovalRecord): ApprovalRecord {\n return {\n ...(plan.approved !== undefined ? { approved: plan.approved } : {}),\n ...(plan.approvedTasks ? { approvedTasks: [...plan.approvedTasks] } : {}),\n };\n}\n\n/**\n * A task the scheduler leaves for the user (ADR-0035): an AI task not started\n * yet, in a plan they approved, outside their approval record — the planner\n * added it since. It starts once they start it or execute the plan. In a plan\n * they never approved nothing is theirs yet, so nothing is singled out.\n */\nexport function waitsForApproval(task: Pick<Task, 'id' | 'type' | 'status'>, record: ApprovalRecord): boolean {\n return record.approved === true\n && task.type === 'ai'\n && (task.status === 'pending' || task.status === 'approved')\n && !(record.approvedTasks ?? []).includes(task.id);\n}\n\n/**\n * Who put each task of an adopted list in the plan. A task the plan already\n * had keeps its origin, whatever the planner wrote; a new one is the\n * supervisor's when `bySupervisor`, and nobody's in particular otherwise, so\n * no planner can mark its own task as the supervisor's. `added` lists the new\n * tasks, subtasks included.\n */\nexport function stampOrigin(before: readonly Task[], after: readonly Task[], bySupervisor: boolean): { tasks: Task[]; added: string[] } {\n const prior = new Map(flattenTasks([...before]).map((t) => [t.id, t]));\n const added: string[] = [];\n const stamp = (tasks: readonly Task[]): Task[] => tasks.map((t) => {\n const was = prior.get(t.id);\n const origin = was ? was.addedBy : bySupervisor ? 'supervisor' : undefined;\n if (!was) added.push(t.id);\n const stamped: Task = { ...t, subtasks: stamp(t.subtasks ?? []) };\n if (origin) stamped.addedBy = origin;\n else delete stamped.addedBy;\n return stamped;\n });\n return { tasks: stamp(after), added };\n}\n\n/** Done, running, or held for the user: execution state only a runner or the user can change. */\nconst SETTLED_STATUSES: ReadonlySet<TaskStatus> = new Set<TaskStatus>(['completed', 'in_progress', 'awaiting_user']);\n\nfunction holdsSettledWork(task: Task): boolean {\n return SETTLED_STATUSES.has(task.status) || (task.subtasks ?? []).some(holdsSettledWork);\n}\n\n/**\n * Lay a planner-written task list over the plan it rewrites without letting it\n * change execution state. A planner restates tasks; it never witnessed one run,\n * so the status it writes is not evidence. A settled task is kept exactly as\n * it stands wherever the rewrite names it, and put back beside its old\n * neighbour where the rewrite leaves it out. Every other task keeps the status\n * it had; a task the rewrite adds starts pending.\n */\nexport function keepExecutionState(current: readonly Task[], rewrite: Task[]): Task[] {\n const existing = new Map(flattenTasks(current).map((t) => [t.id, t]));\n const named = new Set(flattenTasks(rewrite).map((t) => t.id));\n\n const overlay = (tasks: Task[], was: readonly Task[]): Task[] => {\n const result = tasks.map((t): Task => {\n const prior = existing.get(t.id);\n if (prior && SETTLED_STATUSES.has(prior.status)) return { ...prior };\n return {\n ...t,\n status: prior?.status ?? 'pending',\n skipReason: prior?.skipReason,\n verdict: prior?.verdict,\n outputSummary: prior?.outputSummary,\n runnerSessionId: prior?.runnerSessionId,\n runnerSessionOwner: prior?.runnerSessionOwner,\n carriedFrom: prior?.carriedFrom,\n attemptSkills: prior?.attemptSkills,\n attemptUsage: prior?.attemptUsage,\n // Where a task that has run ran is fixed, like its runner session (ADR-0020).\n ...(prior?.status === 'failed' ? { ops: prior.ops } : {}),\n forcedPastGate: prior?.forcedPastGate,\n subtasks: overlay(t.subtasks ?? [], prior?.subtasks ?? []),\n };\n });\n was.forEach((left, i) => {\n if (named.has(left.id) || !holdsSettledWork(left)) return;\n const neighbour = was.slice(0, i).reverse().find((t) => result.some((r) => r.id === t.id));\n const at = neighbour ? result.findIndex((r) => r.id === neighbour.id) + 1 : 0;\n result.splice(at, 0, { ...left });\n });\n return result;\n };\n\n return renumberTasks(overlay(rewrite, current));\n}\n","/** A name a skill can have, lower-cased: the one pattern for a `/name` token and for a skill folder. */\nexport const SKILL_NAME_PATTERN = '[a-z0-9][a-z0-9_-]*';\n\n/**\n * A `/skill-name` token anywhere in a message: whitespace (or string start)\n * before it, a skill name in any case, optional trailing punctuation that\n * isn't part of the name, then whitespace (or string end). The punctuation\n * group is what lets \"/grilling,\" name \"grilling\".\n */\nconst SKILL_TOKEN = new RegExp(`(^|\\\\s)\\\\/(${SKILL_NAME_PATTERN})([,.!?;:]*)(?=\\\\s|$)`, 'gi');\n\n/** Where a skill name is invoked: `start` is its `/`, `end` is just past the name, before any punctuation. */\nexport interface SkillToken {\n name: string;\n start: number;\n end: number;\n}\n\n/**\n * The first `/name` token for each name in `text`, names lower-cased. Only\n * the first counts because a skill loads once per message however often it is\n * named, so a later repeat is plain text.\n */\nexport function skillTokens(text: string): SkillToken[] {\n const tokens: SkillToken[] = [];\n const seen = new Set<string>();\n for (const match of text.matchAll(SKILL_TOKEN)) {\n const name = match[2].toLowerCase();\n if (seen.has(name)) continue;\n seen.add(name);\n const start = match.index + match[1].length;\n tokens.push({ name, start, end: start + 1 + match[2].length });\n }\n return tokens;\n}\n\n/** The tokens in a sent message that loaded one of `loaded` — what a surface highlights in the user's bubble. */\nexport function loadedSkillTokens(text: string, loaded: readonly string[]): SkillToken[] {\n return skillTokens(text).filter((t) => loaded.includes(t.name));\n}\n","/** Plan placement and dependency rules, shared with browser-bundled surfaces. */\nexport interface TreeTask<T> {\n id: string;\n order: number;\n title: string;\n subtasks?: readonly T[];\n}\n\nexport interface DependencyTask<T> extends TreeTask<T> {\n dependencies: readonly string[];\n}\n\nexport interface TaskPlacement<T> {\n task: T;\n parent?: T;\n ancestors: readonly T[];\n siblings: readonly T[];\n label: string;\n}\n\nexport function* walkPlan<T extends TreeTask<T>>(tasks: readonly T[]): Generator<TaskPlacement<T>> {\n function* walk(level: readonly T[], ancestors: readonly T[], parentLabel?: string): Generator<TaskPlacement<T>> {\n for (const task of level) {\n const label = parentLabel ? `${parentLabel}.${task.order}` : String(task.order);\n yield { task, parent: ancestors.at(-1), ancestors, siblings: level, label };\n yield* walk(task.subtasks ?? [], [...ancestors, task], label);\n }\n }\n yield* walk(tasks, []);\n}\n\nexport function taskPlacement<T extends TreeTask<T>>(tasks: readonly T[], id: string): TaskPlacement<T> | undefined {\n for (const row of walkPlan(tasks)) if (row.task.id === id) return row;\n return undefined;\n}\n\n/** Includes the root: deletion has to detach every edge into the removed tree. */\nexport function subtreeIds<T extends TreeTask<T>>(tasks: readonly T[], id: string): Set<string> {\n const found = taskPlacement(tasks, id);\n return new Set(found ? [...walkPlan([found.task])].map(({ task }) => task.id) : []);\n}\n\n/** Pickers offer earlier siblings; API validity is independent of display order. */\nexport function dependencyCandidates<T extends TreeTask<T>>(tasks: readonly T[], taskId?: string): T[] {\n if (!taskId) return [...tasks];\n const found = taskPlacement(tasks, taskId);\n return found ? found.siblings.filter((t) => t.order < found.task.order) : [];\n}\n\n/** The surviving tasks whose dependency lists a subtree removal will change. */\nexport function dependentsOf<T extends DependencyTask<T>>(tasks: readonly T[], taskId: string): T[] {\n const removed = subtreeIds(tasks, taskId);\n return [...walkPlan(tasks)].map(({ task }) => task)\n .filter((t) => !removed.has(t.id) && t.dependencies.some((id) => removed.has(id)));\n}\n\nexport interface DependencyCheck { ok: boolean; error?: string }\n\n/** Target restrictions, separate from cycles so a planner batch can check its final graph. */\nexport function dependencyTargetErrors<T extends TreeTask<T>>(\n tasks: readonly T[], taskId: string, dependencies: readonly string[],\n): string[] {\n const found = taskPlacement(tasks, taskId);\n if (!found) return ['Task not found'];\n const descendants = subtreeIds(tasks, taskId);\n const errors: string[] = [];\n for (const dep of dependencies) {\n if (dep === taskId) { errors.push(`\"${found.task.title}\" cannot depend on itself`); continue; }\n const target = taskPlacement(tasks, dep)?.task;\n if (!target) { errors.push(`Unknown dependency \"${dep}\"`); continue; }\n if (found.ancestors.some((t) => t.id === dep) || descendants.has(dep)) {\n errors.push(`\"${found.task.title}\" cannot depend on \"${target.title}\", its ancestor or descendant`);\n }\n }\n return errors;\n}\n\n/** The tasks on one dependency cycle, in dependency order, or null. */\nexport function findDependencyCycle<T extends DependencyTask<T>>(tasks: readonly T[]): T[] | null {\n const byId = new Map([...walkPlan(tasks)].map(({ task }) => [task.id, task]));\n const path: string[] = [];\n const done = new Set<string>();\n const visit = (id: string): string[] | null => {\n if (done.has(id)) return null;\n const at = path.indexOf(id);\n if (at >= 0) return path.slice(at);\n path.push(id);\n for (const dep of byId.get(id)?.dependencies ?? []) {\n const hit = visit(dep);\n if (hit) return hit;\n }\n path.pop();\n done.add(id);\n return null;\n };\n for (const id of byId.keys()) {\n const hit = visit(id);\n if (hit) return hit.map((key) => byId.get(key)!);\n }\n return null;\n}\n\nexport function canSetDependencies<T extends DependencyTask<T>>(\n tasks: readonly T[], taskId: string, dependencies: readonly string[],\n): DependencyCheck {\n const [error] = dependencyTargetErrors(tasks, taskId, dependencies);\n if (error) return { ok: false, error };\n const replace = (level: readonly T[]): T[] => level.map((t) => ({\n ...t,\n dependencies: t.id === taskId ? dependencies : t.dependencies,\n subtasks: replace(t.subtasks ?? []),\n }));\n const cycle = findDependencyCycle(replace(tasks));\n return cycle\n ? { ok: false, error: `Dependency cycle detected: ${[...cycle, cycle[0]].map((t) => `\"${t.title}\"`).join(' → ')}` }\n : { ok: true };\n}\n","import { taskPlacement, walkPlan, type TreeTask } from './PlanTree';\n\n/**\n * Task references: the one grammar for naming a task in a plan, both ways.\n * A label is rendered from a task's order under its parent (\"2\", \"2.1\"), and\n * a reference written by anyone — the planner, a tool call, a command — is\n * resolved back against the plan tree. Pure so a\n * browser-bundled surface can use it through `@ordewell/core/plan-utils`.\n */\n\n/** The shape a reference resolves over: the plan's task tree, or a surface's projection of it. */\nexport type RefTask<T> = TreeTask<T>;\n\n/**\n * The parent a label extends. A label is the full path (\"3.2.1\"), so a parent\n * below the top level carries the label it was itself reached by; without one\n * the parent's order stands for it, which is right for a top-level parent.\n */\nexport interface RefParent {\n order: number;\n label?: string;\n}\n\n/** Dotted path label for a task, e.g. \"2.1\" for the first subtask of task 2, \"2.1.3\" one level down. */\nexport function taskOrderLabel(task: { order: number }, parent?: RefParent): string {\n return parent ? `${parent.label ?? parent.order}.${task.order}` : String(task.order);\n}\n\n/** How a surface refers to a task in prose: \"#2\", or \"#2.1\" for a subtask. */\nexport function taskRef(task: { order: number }, parent?: RefParent): string {\n return `#${taskOrderLabel(task, parent)}`;\n}\n\n/** A task named in full, as a confirmation or a picker title does: \"#2 Deploy\". */\nexport function titledTaskRef(task: { order: number; title: string }, parent?: RefParent): string {\n return `${taskRef(task, parent)} ${task.title}`;\n}\n\n/** A task found in a plan tree, with its parent and the full path label its reference extends. */\nexport interface RefTaskMatch<T> {\n task: T;\n parent?: T;\n label: string;\n}\n\n/** The task a plan tree holds, by id, with its parent; undefined when the tree holds none. */\nexport function findTaskRef<T extends RefTask<T>>(tasks: readonly T[], id: string): RefTaskMatch<T> | undefined {\n return taskPlacement(tasks, id);\n}\n\n/**\n * The reference {@link taskRef} renders for the task a plan tree holds, by id\n * — its full path, dotted, for a subtask. Undefined when the tree holds no such task.\n */\nexport function taskRefOf<T extends RefTask<T>>(tasks: readonly T[], id: string): string | undefined {\n const found = findTaskRef(tasks, id);\n return found && `#${found.label}`;\n}\n\n/**\n * The reference and title {@link titledTaskRef} renders for the task a plan\n * tree holds, by id — its full path, dotted, for a subtask. Undefined when the\n * tree holds no such task.\n */\nexport function titledTaskRefOf<T extends RefTask<T>>(tasks: readonly T[], id: string): string | undefined {\n const found = findTaskRef(tasks, id);\n return found && `#${found.label} ${found.task.title}`;\n}\n\n/**\n * Resolve a written reference to a task at any depth: an id, then an order\n * label with or without \"#\" (\"#2\", \"2\", \"#2.1\"), then an exact title.\n *\n * An order label is read against the tree, never a flattened list: subtask\n * orders restart at 1 under each parent, so \"#2\" always means top-level task 2\n * and a subtask is reachable only by its dotted path (\"#2.1\", \"#2.1.3\").\n */\nexport function resolveTaskRef<T extends RefTask<T>>(tasks: readonly T[], ref: string | number): T | undefined {\n const s = String(ref).trim();\n if (!s) return undefined;\n for (const { task } of walkPlan(tasks)) if (task.id === s) return task;\n const label = s.startsWith('#') ? s.slice(1) : s;\n if (/^\\d+(\\.\\d+)*$/.test(label)) {\n let level: readonly T[] | undefined = tasks;\n let found: T | undefined;\n for (const order of label.split('.').map(Number)) {\n found = level?.find((t) => t.order === order);\n level = found?.subtasks;\n }\n return found;\n }\n for (const { task } of walkPlan(tasks)) if (task.title === s) return task;\n return undefined;\n}\n\n/**\n * A reference as the user types one: {@link resolveTaskRef}, then a unique\n * prefix of a task's id at any depth. Only the user's: a model's reference\n * that names no task is refused, never matched to the one task a fragment of\n * it happens to fit.\n */\nexport function resolveUserTaskRef<T extends RefTask<T>>(tasks: readonly T[], ref: string | number): T | undefined {\n const found = resolveTaskRef(tasks, ref);\n if (found) return found;\n const prefix = String(ref).trim();\n const matches = prefix ? [...walkPlan(tasks)].filter(({ task }) => task.id.startsWith(prefix)) : [];\n return matches.length === 1 ? matches[0].task : undefined;\n}\n","import {\n Task, RunnerId, flattenTasks,\n addTaskToPlan, removeTaskFromPlan, updateTaskInPlan, renumberTasks,\n opsFlag, inheritedOps, skillNames,\n} from '../models/Task';\nimport { v4 as uuidv4 } from 'uuid';\nimport { resolveTaskRef } from './TaskRefs';\nimport { taskPlacement } from './PlanTree';\nimport { extractObjectsWithKey, stripTrailingCommas, escapeControlCharsInStrings, PlanParseError, TASK_OPS_ENVELOPE_KEY } from './JsonExtractor';\nimport { validateTaskEdit, lockedTaskRefusal, type TaskEditActor, type TaskEditCheck } from './TaskEditValidator';\nimport { resolveAssignment, type AssignmentAdjustment, type AssignmentCatalog } from './TaskAssignment';\nimport { plannedTask, checkPlanInvariants, detectCycle, taskWhere, MODE_NOT_THE_PLANNERS, MANUAL_NOT_READ_ONLY, OPS_NOT_READ_ONLY, type IntakeCatalog, type PlannedTask, type PlanTaskError } from './PlannedTask';\nimport { taggedReadOnlyMode } from './ModeResolver';\n\n/**\n * Targeted task edits emitted by the planner conversation (the 'task_ops'\n * ConversationTurn). Task references accept a task id, a \"#<order>\" ref, or a\n * bare order number — cheap models rarely echo UUIDs correctly.\n */\n/**\n * A task as the planner writes it: its fields, less the mode, plus whether it\n * must not change files (ADR-0031), and `thinkingEffort` as a name for its\n * model's effort, so an effort can change without restating the model.\n */\nexport type PlannerTaskSpec = Partial<Task> & { readOnly?: boolean; thinkingEffort?: string | null };\n\nexport type TaskOp =\n | { op: 'update'; taskId: string; changes: PlannerTaskSpec }\n | { op: 'add'; task: PlannerTaskSpec; handle?: string }\n | { op: 'remove'; taskId: string }\n | { op: 'reorder'; taskIds: string[] }\n | { op: 'merge'; taskIds: string[]; merged: PlannerTaskSpec; handle?: string }\n | { op: 'split'; taskId: string; parts: PlannerTaskSpec[]; handle?: string }\n | { op: 'rearm'; taskId: string; changes?: PlannerTaskSpec };\n\n/** Fields the planner may change on an existing task. Everything else (id, status, verdict…) is system-owned. */\nexport const UPDATABLE_FIELDS: (keyof Task)[] = [\n 'title', 'description', 'prompt', 'dependencies', 'assignedRunner', 'assignedModel', 'taskMode', 'type', 'userSteps', 'autonomy', 'sliceType', 'ops', 'skills',\n];\n\n/**\n * The edit protocol as the planner reads it, kept beside the applier so the\n * prose can never undersell (or oversell) what {@link applyTaskOps} accepts.\n * `executionNote` rides on the ordering rule because that is the rule a\n * running execution changes.\n */\nexport function taskOpsProtocol(executionNote = '', tools = false): string[] {\n const updateChanges = [...UPDATABLE_FIELDS.filter((f) => f !== 'taskMode'), 'thinkingEffort', 'readOnly']\n .map((f) => (f === 'dependencies' ? '\"dependencies\"?:[\"<id or #order>\"]' : `\"${f}\"?`))\n .join(',');\n return [\n tools ? '- To modify specific tasks, call edit_plan, never a JSON reply. Its argument is:' : '- To modify specific tasks, reply with ONLY this JSON object:',\n tools ? ' {\"ops\": [' : ' {\"taskOps\": [',\n ` {\"op\":\"update\",\"taskId\":\"<id or #order>\",\"changes\":{${updateChanges}}},`,\n ' {\"op\":\"add\",\"task\":{\"title\",\"description\",\"prompt\",\"dependencies\":[\"<id or #order>\"],\"assignedRunner\"?,\"assignedModel\"?,\"readOnly\"?,\"ops\"?},\"handle\"?:\"<name>\"},',\n ' {\"op\":\"remove\",\"taskId\":\"<id or #order>\"},',\n ' {\"op\":\"reorder\",\"taskIds\":[\"<id or #order>\", \"... every task exactly once\"]}, // only to re-prioritise INDEPENDENT tasks',\n ' {\"op\":\"merge\",\"taskIds\":[\"<id or #order>\", \"...\"],\"merged\":{\"title\",\"description\",\"prompt\"?,\"assignedRunner\"?,\"assignedModel\"?,...},\"handle\"?:\"<name>\"},',\n ' {\"op\":\"split\",\"taskId\":\"<id or #order>\",\"parts\":[{\"title\",\"description\",\"prompt\"?,\"assignedRunner\"?,\"assignedModel\"?,...}, ...],\"handle\"?:\"<name>\"},',\n ` {\"op\":\"rearm\",\"taskId\":\"<id or #order>\",\"changes\"?:{${updateChanges}}}`,\n ' ]}',\n tools ? '- For sweeping changes, you may instead call submit_plan with the full plan.' : '- For sweeping changes, you may instead emit a full {\"tasks\":[...]} plan JSON.',\n 'Every \"<id or #order>\" ref in a batch resolves against the plan shown above, before any op in the batch runs — an earlier remove/merge/split never shifts what a later \"#N\" means. \"#N\" is top-level task N; a subtask is named by its dotted label (\"#2.1\"), as the plan lists it.',\n 'Give \"add\", \"merge\", or \"split\" a \"handle\" (any name you choose, unused elsewhere in this batch) to let a LATER op in the same batch reference the task it produces — for \"split\", the handle names its last part. A handle used before its defining op is rejected.',\n `When creating or changing tasks, set \"assignedRunner\" and \"assignedModel\" ({\"modelId\",\"modelLabel\",\"thinkingEffort\"?}) using only the runners and models ${tools ? 'list_runners and list_models return' : 'listed in <available_models>'}.`,\n 'Set \"readOnly\": true on a task that must not change any file, never on one that must run commands (tests, scripts, builds) or an ops task, and \"readOnly\": false to lift it; you never set \"taskMode\". A task you move, split or edit keeps being read-only or not unless you say otherwise, and so do the subtasks of a read-only task you add.',\n 'Keep dependencies consistent: no cycles, no references to removed tasks, and never touch running or completed tasks — \"rearm\" is the one exception, below.',\n ...(tools ? ['edit_plan checks the batch when you call it and answers with what it will change, or with the error to fix — call it again in the same reply. The edit is applied when your reply ends; edits you make in one reply join one batch.'] : []),\n 'Just declare the dependencies you want — display order is repaired for you afterwards, so a rewire or a newly added prerequisite never needs a \"reorder\" op. Only a task that is running or completed cannot be shifted, so an edit that would need one to move is rejected.' + executionNote,\n 'Flipping \"type\" between \"ai\" and \"user\" is a content change, not just a label: an update to \"user\" needs \"userSteps\" in the SAME op, and an update to \"ai\" needs \"prompt\" in the SAME op — the model/mode/effort/autonomy fields (flipping to \"user\", which also makes the task HITL) or the userSteps (flipping to \"ai\") are cleared automatically.',\n '\"skills\" in \"changes\" REPLACES the task\\'s whole skill list. To add one, send the names the plan block shows in its skills:[...] plus the new one; to drop one, send the rest; [] removes them all.',\n '\"rearm\" puts a failed OR completed task back to pending — verdict and output summary are cleared, any dependents it had blocked are released, and it may carry field changes (e.g. a corrected \"prompt\") applied in the same op. A running task cannot be re-armed. Never rearm a task just to relabel it — only when it should actually run again.',\n ];\n}\n\nexport function textHasTaskOps(text: string): boolean {\n return text.includes(`\"${TASK_OPS_ENVELOPE_KEY}\"`);\n}\n\n/** Parse a `{\"taskOps\":[...]}` reply. Throws PlanParseError when the JSON is unusable. */\nexport function parseTaskOpsJson(text: string): TaskOp[] {\n // Extract by the taskOps key specifically — a reply may also carry a\n // tasks-keyed object (schema echo, example), which must not shadow the ops.\n // Candidates are tried back to front: the last emission is the final answer.\n const { matches, fallback } = extractObjectsWithKey(text, TASK_OPS_ENVELOPE_KEY);\n const candidates = matches.length > 0 ? [...matches].reverse() : [fallback.json];\n\n let lastError: PlanParseError | null = null;\n for (const json of candidates) {\n try {\n return parseTaskOpsObject(json, text);\n } catch (err) {\n if (!(err instanceof PlanParseError)) throw err;\n if (!lastError) lastError = err;\n }\n }\n throw lastError ?? new PlanParseError('No JSON object found in task-ops reply', text);\n}\n\nfunction parseTaskOpsObject(json: string, text: string): TaskOp[] {\n let parsed: unknown;\n try {\n parsed = JSON.parse(escapeControlCharsInStrings(stripTrailingCommas(json)));\n } catch (err) {\n throw new PlanParseError(`Task-ops JSON is invalid: ${err instanceof Error ? err.message : String(err)}`, text);\n }\n const ops = (parsed as { taskOps?: unknown }).taskOps;\n if (!Array.isArray(ops) || ops.length === 0) {\n throw new PlanParseError('\"taskOps\" must be a non-empty array', text);\n }\n for (const op of ops) {\n if (typeof op !== 'object' || op === null || typeof (op as { op?: unknown }).op !== 'string') {\n throw new PlanParseError('Every task op needs an \"op\" field (update | add | remove | reorder | merge | split)', text);\n }\n }\n return ops as TaskOp[];\n}\n\ntype RefResolution = { id: string } | { error: string };\n\n/**\n * Resolve an op's task reference to a task id: a batch handle, or anything\n * {@link resolveTaskRef} reads.\n *\n * Order labels and title matches are pinned to `originalTree` — the plan as it\n * stood before the batch began — so an earlier op's renumbering can never\n * make a later op's \"#4\" land on a different task than the planner saw. A\n * literal id has no such drift (ids are stable across mutations), so id\n * matches check `liveTree` — the batch's current, mutated tasks — which is\n * also how a later op reaches a task created earlier in the same batch\n * without a handle (e.g. a split's own chained parts).\n */\nfunction resolveRef(\n ref: unknown,\n originalTree: readonly Task[],\n liveTree: Task[],\n handleOwner: Map<string, number>,\n handleId: Map<string, string>,\n opIndex: number,\n): RefResolution {\n if (typeof ref !== 'string' && typeof ref !== 'number') return { error: `invalid reference \"${String(ref)}\"` };\n const s = String(ref).trim();\n\n const ownerIdx = handleOwner.get(s);\n if (ownerIdx !== undefined) {\n if (ownerIdx >= opIndex) {\n return { error: `handle \"${s}\" is defined by a later op in this batch and cannot be referenced yet` };\n }\n const id = handleId.get(s);\n if (!id) return { error: `handle \"${s}\" was never resolved` };\n return { id };\n }\n\n if (findInTasks(liveTree, s)) return { id: s };\n const task = resolveTaskRef(originalTree, s);\n return task ? { id: task.id } : { error: `task \"${s}\" not found` };\n}\n\n/** The fields of a planner's `changes` it may set, with the ops flag read as every entry point reads it. */\nfunction updatableChanges(raw: Partial<Task> | undefined): Partial<Task> {\n const changes: Partial<Task> = {};\n for (const key of UPDATABLE_FIELDS) {\n if (raw && key in raw) (changes as Record<string, unknown>)[key] = (raw as Record<string, unknown>)[key];\n }\n if ('ops' in changes) changes.ops = opsFlag(changes.ops);\n if ('skills' in changes) changes.skills = skillNames(changes.skills);\n return changes;\n}\n\nfunction findInTasks(tasks: readonly Task[], id: string): Task | undefined {\n return taskPlacement(tasks, id)?.task;\n}\n\nfunction findTopLevel(tasks: Task[], id: string): Task | undefined {\n return tasks.find((t) => t.id === id);\n}\n\n/** A task the repair may not reposition: execution has already reached it. */\nfunction isPinned(t: Task): boolean {\n return t.status === 'in_progress' || t.status === 'completed';\n}\n\n/** The first task in `parent`'s subtree execution has reached, if any: removing the parent would take it (ADR-0029). */\nfunction lockedInSubtree(parent: Task): string | null {\n for (const sub of parent.subtasks ?? []) {\n const locked = lockedTaskRefusal(sub, 'removed') ?? lockedInSubtree(sub);\n if (locked) return locked;\n }\n return null;\n}\n\n/**\n * Reorder top-level tasks so every dependency comes before its dependents,\n * moving as little as possible: pinned tasks keep the exact slot they are in,\n * and each free slot goes to the earliest-listed movable task whose\n * dependencies are already placed — so tasks the graph does not constrain keep\n * their relative order. Assumes an acyclic graph (the caller checks first).\n */\nfunction repairOrder(tasks: Task[]): { tasks: Task[] } | { error: string } {\n const byId = new Map(tasks.map((t) => [t.id, t]));\n const placed = new Set<string>();\n const movable = tasks.filter((t) => !isPinned(t));\n const result: Task[] = [];\n // Dependencies outside this list (a subtask id) constrain nothing here.\n const blockerOf = (t: Task): Task | undefined => {\n const id = t.dependencies.find((d) => byId.has(d) && !placed.has(d));\n return id ? byId.get(id) : undefined;\n };\n const place = (t: Task) => { result.push(t); placed.add(t.id); };\n\n for (const occupant of tasks) {\n if (isPinned(occupant)) {\n const blocker = blockerOf(occupant);\n if (blocker) return { error: pinnedRefusal(blocker, occupant, 'before') };\n place(occupant);\n continue;\n }\n const next = movable.findIndex((t) => !blockerOf(t));\n if (next < 0) {\n // Nothing is schedulable and the graph is acyclic, so every movable task\n // left waits — directly or through others — on a pinned task further down\n // that would have to come up to free this slot.\n const [stuck, pin] = trailToPin(movable[0], blockerOf);\n return { error: pinnedRefusal(stuck, pin, 'after') };\n }\n place(movable.splice(next, 1)[0]);\n }\n return { tasks: result };\n}\n\n/** Walk the waiting-on chain from `task` down to the pinned task holding it up. */\nfunction trailToPin(task: Task, blockerOf: (t: Task) => Task | undefined): [Task, Task] {\n let at = task;\n for (;;) {\n const blocker = blockerOf(at);\n if (!blocker || isPinned(blocker)) return [at, blocker ?? at];\n at = blocker;\n }\n}\n\n/** `\"B\" #2→#1, \"A\" #1→#3` for every task the repair actually moved, or null. */\nfunction describeMoves(before: Task[], after: Task[]): string | null {\n const wasAt = new Map(before.map((t, i) => [t.id, i + 1]));\n const moved = after\n .map((t, i) => ({ t, from: wasAt.get(t.id)!, to: i + 1 }))\n .filter((m) => m.from !== m.to);\n return moved.length ? moved.map((m) => `\"${m.t.title}\" #${m.from}→#${m.to}`).join(', ') : null;\n}\n\nfunction pinnedRefusal(other: Task, pin: Task, side: 'before' | 'after'): string {\n const word = pin.status === 'in_progress' ? 'running' : 'completed';\n return `\"${other.title}\" would have to run ${side} \"${pin.title}\", which is ${word} and cannot be moved`;\n}\n\nexport interface ApplyTaskOpsResult {\n ok: boolean;\n tasks: readonly Task[];\n errors: string[];\n /** Human-readable summary of what changed, for the chat transcript. */\n summary: string[];\n /** On ok, what the batch's tasks were adjusted to beyond what the planner wrote, as they stand at its end. */\n adjustments?: AssignmentAdjustment[];\n /** On ok, the id of the task each batch handle names. */\n handles?: ReadonlyMap<string, string>;\n}\n\n/**\n * Pre-flight check for a merge: would collapsing the selected tasks into one\n * (rewiring every dependent of any selected task to the survivor) keep the\n * dependency graph valid? Rejects locked tasks and merges whose rewiring would\n * introduce a cycle. Display order is NOT checked here — neither\n * consecutiveness (a UI concern) nor a dependency the merge pulls out of order,\n * which {@link applyTaskOps} repairs; refusing on order would make this\n * pre-flight stricter than the applier it stands in for.\n */\nexport function canMergeTasks(tasks: readonly Task[], selectedIds: string[]): { ok: boolean; error?: string } {\n if (selectedIds.length < 2) return { ok: false, error: 'Select at least two tasks to merge' };\n const idSet = new Set(selectedIds);\n const toMerge = tasks.filter((t) => idSet.has(t.id));\n if (toMerge.length < 2) return { ok: false, error: 'At least two valid tasks are required to merge' };\n for (const t of toMerge) {\n if (t.status === 'in_progress') return { ok: false, error: `\"${t.title}\" is running and cannot be merged` };\n if (t.status === 'completed') return { ok: false, error: `\"${t.title}\" is completed and cannot be merged` };\n }\n const ordered = [...toMerge].sort((a, b) => a.order - b.order);\n const survivorId = '__merge_sim__';\n const sim: Task[] = tasks\n .filter((t) => !idSet.has(t.id))\n .map((t) => ({ ...t, dependencies: t.dependencies.map((d) => (idSet.has(d) ? survivorId : d)).filter((d) => d !== t.id) }));\n const unionDeps = [...new Set(toMerge.flatMap((t) => t.dependencies))].filter((d) => !idSet.has(d));\n sim.push({ ...ordered[0], id: survivorId, title: '__merge_sim__', order: ordered[0].order, dependencies: unionDeps });\n const cycle = detectCycle(sim);\n if (cycle) return { ok: false, error: `Merging would create a dependency cycle involving \"${cycle}\"` };\n return { ok: true };\n}\n\n/**\n * The shape the dependency helpers below read. Structural rather than `Task`,\n * because the TUI projects tasks into its own `TaskView`: a surface's\n * dependency picker and the API's validation must agree on which dependencies\n * are legal, and a signature only core can satisfy would have forced the TUI\n * to keep a second copy of the rule.\n */\nexport interface TaskRef {\n id: string;\n order: number;\n title: string;\n dependencies: string[];\n}\n\nexport { dependencyCandidates, canSetDependencies, dependentsOf } from './PlanTree';\n\n/** Pre-flight check for a split: the task exists and is not locked by execution. */\nexport function canSplitTask(tasks: readonly Task[], taskId: string): { ok: boolean; error?: string } {\n const target = tasks.find((t) => t.id === taskId);\n if (!target) return { ok: false, error: 'Task not found' };\n if (target.status === 'in_progress') return { ok: false, error: `\"${target.title}\" is running and cannot be split` };\n if (target.status === 'completed') return { ok: false, error: `\"${target.title}\" is completed and cannot be split` };\n return { ok: true };\n}\n\n\nfunction askedReadOnly(spec: PlannerTaskSpec | undefined): boolean | undefined {\n return typeof spec?.readOnly === 'boolean' ? spec.readOnly : undefined;\n}\n\nfunction isReadOnly(task: Task, catalog: AssignmentCatalog | undefined): boolean {\n return task.taskMode !== undefined && task.taskMode === taggedReadOnlyMode(catalog?.runnerModes?.[task.assignedRunner]);\n}\n\n/**\n * The fields an edit changed, as the planner names them: those it wrote, and\n * `readOnly` when that flipped, never the mode it landed on (ADR-0031) nor a\n * model the resolver put in, which is reported beside the edit instead.\n */\nfunction changedFields(target: Task, written: Partial<Task>, landed: Partial<Task>, catalog: AssignmentCatalog | undefined): string[] {\n const fields = Object.keys(written).filter((f) => f !== 'taskMode');\n if (isReadOnly({ ...target, ...landed }, catalog) !== isReadOnly(target, catalog)) fields.push('readOnly');\n return fields;\n}\n\n/** Nothing discovered and no runner live: what an edit resolves without a catalog. */\nconst NO_CATALOG: AssignmentCatalog = { modelsByRunner: {} };\n\n/**\n * The ids an op's new tasks get, made once and kept for the op: the open\n * turn's held edit is applied again at each read of the plan as edited and\n * once more as it lands, and a start queued behind it names the task by the\n * id it read.\n */\nconst keptIds = new WeakMap<object, string[]>();\n\nfunction idsOf(op: unknown): () => string {\n if (typeof op !== 'object' || op === null) return uuidv4;\n const ids = keptIds.get(op) ?? [];\n keptIds.set(op, ids);\n let next = 0;\n return () => {\n if (next === ids.length) ids.push(uuidv4());\n return ids[next++];\n };\n}\n\n/**\n * Apply task ops to a snapshot of the plan, atomically: either every op\n * applies and the result validates (deps resolve, no cycles, running and\n * completed tasks untouched), or nothing is returned and `errors` explains\n * why. The caller commits `tasks` on ok.\n */\nexport function applyTaskOps(\n currentTasks: readonly Task[],\n newOps: TaskOp[],\n runners: RunnerId[],\n catalog?: AssignmentCatalog,\n held: readonly TaskOp[] = [],\n): ApplyTaskOpsResult {\n // Ops already accepted earlier in the batch apply first; errors number only\n // the new ones, as the planner wrote them in the call it is answered for.\n const ops = [...held, ...newOps];\n const opLabel = (i: number) => (i < held.length ? `earlier op ${i + 1} (${ops[i].op})` : `op ${i - held.length + 1} (${ops[i].op})`);\n let tasks: Task[] = JSON.parse(JSON.stringify(currentTasks));\n const errors: string[] = [];\n const summary: string[] = [];\n const adjustments: AssignmentAdjustment[] = [];\n\n // Batch handles: planner-chosen names for a task an add/merge/split op is\n // about to create, so a later op in the same batch can reference it before\n // it has a real id. Pre-scanned up front — a bad handle refuses the whole\n // batch before anything mutates.\n const handleOwner = new Map<string, number>();\n const handleId = new Map<string, string>();\n for (const [i, op] of ops.entries()) {\n const handle = (op as { handle?: unknown }).handle;\n if (handle === undefined) continue;\n if (typeof handle !== 'string' || !handle.trim()) {\n errors.push(`${opLabel(i)}: handle must be a non-empty string`);\n continue;\n }\n if (handleOwner.has(handle)) {\n errors.push(`${opLabel(i)}: handle \"${handle}\" is already used earlier in this batch`);\n continue;\n }\n if (resolveTaskRef(currentTasks, handle)) {\n errors.push(`${opLabel(i)}: handle \"${handle}\" collides with an existing task reference`);\n continue;\n }\n handleOwner.set(handle, i);\n }\n if (errors.length) return { ok: false, tasks: currentTasks, errors, summary: [] };\n\n const resolveDeps = (deps: unknown, opIndex: number): { ids: string[]; bad: string[] } => {\n const ids: string[] = [];\n const bad: string[] = [];\n const liveFlat = flattenTasks(tasks);\n for (const d of Array.isArray(deps) ? deps : []) {\n const r = resolveRef(d, currentTasks, tasks, handleOwner, handleId, opIndex);\n if ('error' in r) { bad.push(`${String(d)} (${r.error})`); continue; }\n if (!liveFlat.some((t) => t.id === r.id)) { bad.push(`${String(d)} (no longer exists in this batch)`); continue; }\n ids.push(r.id);\n }\n return { ids, bad };\n };\n\n const intake: IntakeCatalog = { runners, runnerModes: catalog?.runnerModes, autonomousDefault: catalog?.autonomousDefault, models: catalog };\n\n /**\n * A planned task's dependency refs, at every depth, as ids: a subtask may\n * name a task of its own tree by the id the planner gave it, or any task in\n * the plan the way every op does.\n */\n const resolveTree = (planned: PlannedTask, opIndex: number): { task: Task } | { error: string } => {\n const walk = (t: Task, parentTitle?: string): Task | string => {\n const ids: string[] = [];\n const bad: string[] = [];\n for (const d of t.dependencies) {\n const own = planned.renamed.get(d);\n if (own) { ids.push(own); continue; }\n const r = resolveDeps([d], opIndex);\n ids.push(...r.ids);\n bad.push(...r.bad);\n }\n if (bad.length) return `unknown dependencies${parentTitle !== undefined ? ` of ${taskWhere(t.title, parentTitle)}` : ''}: ${bad.join(', ')}`;\n const subtasks: Task[] = [];\n for (const sub of t.subtasks) {\n const done = walk(sub, t.title);\n if (typeof done === 'string') return done;\n subtasks.push(done);\n }\n return { ...t, dependencies: ids, subtasks };\n };\n const done = walk(planned.task);\n return typeof done === 'string' ? { error: done } : { task: done };\n };\n\n /** Why the edit cannot have this planned task: a rule it breaks, or something it asked for that is not the planner's. */\n const refusalOf = (planned: PlannedTask): string | undefined => [...planned.ignored, ...planned.errors][0]?.message;\n\n /**\n * The resolve-and-validate half shared by \"update\" and \"rearm\": resolve the\n * target, apply the field allowlist, run the edit validator under the op's\n * audience and the assignment resolver as the planner's edit, then resolve\n * any dependency refs. `refuseRunning` is rearm's extra lock check, kept\n * before the field work so its message wins. `changes` is what lands;\n * `fields` what the planner changed, as its summary names it.\n */\n const prepareEdit = (\n op: { taskId: string; changes?: PlannerTaskSpec },\n opIndex: number,\n label: string,\n audience: TaskEditActor,\n refuseRunning = false,\n ): { target: Task; changes: Partial<Task>; fields: string[]; check: TaskEditCheck } | { error: string } => {\n const ref = resolveRef(op.taskId, currentTasks, tasks, handleOwner, handleId, opIndex);\n if ('error' in ref) return { error: `${label}: ${ref.error}` };\n const target = findInTasks(tasks, ref.id);\n if (!target) return { error: `${label}: task \"${op.taskId}\" no longer exists in this batch (removed, merged, or split by an earlier op)` };\n if (refuseRunning && target.status === 'in_progress') return { error: `${label}: ${lockedTaskRefusal(target, 're-armed')}` };\n if (op.changes && 'taskMode' in op.changes) return { error: `${label}: ${MODE_NOT_THE_PLANNERS}` };\n const changes = updatableChanges(op.changes);\n if (op.changes && 'thinkingEffort' in op.changes) {\n const model = changes.assignedModel ?? target.assignedModel;\n if (!model) return { error: `${label}: \"thinkingEffort\" is the assigned model's — set \"assignedModel\" with it` };\n changes.assignedModel = { ...model, thinkingEffort: op.changes.thinkingEffort ?? undefined };\n }\n // Dependency refs are still unresolved (e.g. \"#3\") at this point, so the\n // check runs on everything but them. The shared plan invariants check\n // their resolved ids on the final graph: a later op may finish a rewire.\n const changesForCheck: Partial<Task> = { ...changes };\n delete changesForCheck.dependencies;\n const check = validateTaskEdit(audience, tasks, target.id, changesForCheck);\n if (!check.ok) return { error: `${label}: ${check.error}` };\n for (const field of check.clear ?? []) (changes as Record<string, unknown>)[field] = undefined;\n Object.assign(changes, check.set);\n const readOnly = askedReadOnly(op.changes);\n if (readOnly === true && (changes.type ?? target.type) === 'user') return { error: `${label}: ${MANUAL_NOT_READ_ONLY}` };\n if ((changes.ops ?? target.ops) && (readOnly ?? isReadOnly(target, catalog))) return { error: `${label}: ${OPS_NOT_READ_ONLY}` };\n const landed: Partial<Task> = { ...changes };\n const written = { ...target, ...changes };\n // A runner not allowed has nothing to resolve against; the plan's rules refuse it once the op is applied.\n if (written.type === 'user' || runners.includes(written.assignedRunner)) {\n const resolved = resolveAssignment({ writer: 'edit', task: written, before: target, readOnly, catalog: catalog ?? NO_CATALOG });\n if (!resolved.ok) return { error: `${label}: ${resolved.error}` };\n if (resolved.task.assignedModel !== written.assignedModel) landed.assignedModel = resolved.task.assignedModel;\n if (resolved.task.taskMode !== written.taskMode) landed.taskMode = resolved.task.taskMode;\n adjustments.push(...resolved.adjustments);\n }\n if ('dependencies' in changes) {\n const { ids, bad } = resolveDeps(changes.dependencies, opIndex);\n if (bad.length) return { error: `${label}: unknown dependencies: ${bad.join(', ')}` };\n landed.dependencies = ids;\n }\n return { target, changes: landed, fields: changedFields(target, changes, landed, catalog), check };\n };\n\n // A rule the batch ends in breach of is the op's that first broke it. What\n // the plan already broke before the batch — a task on a runner disabled\n // since, say — is not, so it never blocks an unrelated edit. A breach is\n // told by its task and rule, not its wording: the wording carries the title,\n // which an edit may change.\n const breachKey = (e: PlanTaskError) => `${e.taskId ?? ''}\\u0000${e.field}`;\n const standing = new Set(checkPlanInvariants(currentTasks, runners, catalog?.runnerModes).map(breachKey));\n const brokenBy = new Map<string, string>();\n let lastLabel = opLabel(0);\n\n for (const [i, op] of ops.entries()) {\n const label = opLabel(i);\n const newId = idsOf(op);\n switch (op.op) {\n case 'update': {\n const prep = prepareEdit(op, i, label, 'planner');\n if ('error' in prep) { errors.push(prep.error); break; }\n const { target, changes, fields, check } = prep;\n if (fields.length === 0) {\n const readOnly = askedReadOnly(op.changes);\n if (readOnly !== undefined && isReadOnly(target, catalog) === readOnly) { summary.push(`\"${target.title}\" is already ${readOnly ? '' : 'not '}read-only`); break; }\n errors.push(`${label}: no valid changes provided`);\n break;\n }\n tasks = updateTaskInPlan(tasks, target.id, changes);\n const clearedNote = check.clear?.length ? `; cleared ${check.clear.join(', ')}` : '';\n summary.push(`Updated \"${target.title}\"${fields.length ? ` (${fields.join(', ')})` : ''}${clearedNote}`);\n break;\n }\n case 'add': {\n const spec = op.task ?? {};\n if (!spec.title) { errors.push(`${label}: new task needs a title`); break; }\n const planned = plannedTask(spec, intake, { freshIds: true, newId });\n const refused = refusalOf(planned);\n if (refused) { errors.push(`${label}: ${refused}`); break; }\n adjustments.push(...planned.adjustments);\n const resolved = resolveTree(planned, i);\n if ('error' in resolved) { errors.push(`${label}: ${resolved.error}`); break; }\n tasks = addTaskToPlan(tasks, resolved.task);\n if (op.handle) handleId.set(op.handle, resolved.task.id);\n summary.push(`Added \"${spec.title}\"`);\n break;\n }\n case 'remove': {\n const ref = resolveRef(op.taskId, currentTasks, tasks, handleOwner, handleId, i);\n if ('error' in ref) { errors.push(`${label}: ${ref.error}`); break; }\n const target = findInTasks(tasks, ref.id);\n if (!target) { errors.push(`${label}: task \"${op.taskId}\" no longer exists in this batch (removed, merged, or split by an earlier op)`); break; }\n // Removing the task takes its whole subtree, so every task in it meets\n // the same lock rule as the named one (ADR-0029).\n const locked = lockedTaskRefusal(target, 'removed') ?? lockedInSubtree(target);\n if (locked) { errors.push(`${label}: ${locked}`); break; }\n tasks = removeTaskFromPlan(tasks, target.id);\n summary.push(`Removed \"${target.title}\"`);\n break;\n }\n case 'reorder': {\n const refs = (op.taskIds ?? []).map((r) => resolveRef(r, currentTasks, tasks, handleOwner, handleId, i));\n const badRef = refs.find((r): r is { error: string } => 'error' in r);\n if (badRef) { errors.push(`${label}: ${badRef.error}`); break; }\n const resolved = (refs as { id: string }[]).map((r) => findTopLevel(tasks, r.id));\n if (resolved.some((t) => !t)) { errors.push(`${label}: unknown task in reorder list`); break; }\n const orderIds = resolved.map((t) => t!.id);\n if (new Set(orderIds).size !== tasks.length) {\n errors.push(`${label}: reorder must list every top-level task exactly once (${tasks.length} tasks)`);\n break;\n }\n const byId = new Map(tasks.map((t) => [t.id, t]));\n tasks = renumberTasks(orderIds.map((id) => byId.get(id)!));\n summary.push('Reordered tasks');\n break;\n }\n case 'merge': {\n const refs = (op.taskIds ?? []).map((r) => resolveRef(r, currentTasks, tasks, handleOwner, handleId, i));\n const badRef = refs.find((r): r is { error: string } => 'error' in r);\n if (badRef) { errors.push(`${label}: ${badRef.error}`); break; }\n const resolved = (refs as { id: string }[]).map((r) => findTopLevel(tasks, r.id));\n if (resolved.some((t) => !t)) { errors.push(`${label}: unknown task in merge list (already removed, merged, or split by an earlier op)`); break; }\n const toMerge = [...new Map(resolved.map((t) => [t!.id, t!])).values()].sort((a, b) => a.order - b.order);\n if (toMerge.length < 2) { errors.push(`${label}: merge needs at least two tasks`); break; }\n const locked = toMerge.map((t) => lockedTaskRefusal(t, 'merged')).find((refusal) => refusal !== null);\n if (locked) { errors.push(`${label}: ${locked}`); break; }\n const idSet = new Set(toMerge.map((t) => t.id));\n const unionDepsRaw = [...new Set(toMerge.flatMap((t) => t.dependencies))].filter((d) => !idSet.has(d));\n const { ids, bad } = resolveDeps(unionDepsRaw, i);\n if (bad.length) { errors.push(`${label}: unknown dependencies: ${bad.join(', ')}`); break; }\n const spec = op.merged ?? {};\n if (!spec.title) { errors.push(`${label}: merged task needs a title`); break; }\n // Read-only only when every merged task was: one that writes makes the merged task write.\n const writes = toMerge.find((t) => !isReadOnly(t, catalog));\n const stories = [...new Set(toMerge.flatMap((t) => t.userStoriesCovered ?? []))];\n const planned = plannedTask(spec, intake, {\n freshIds: true,\n newId,\n from: {\n readOnly: !writes,\n fields: {\n description: toMerge.map((t) => t.description).filter(Boolean).join('\\n\\n'),\n prompt: toMerge.map((t) => t.prompt).filter(Boolean).join('\\n\\n---\\n\\n') || undefined,\n type: toMerge.some((t) => t.type === 'user') ? 'user' : 'ai',\n assignedRunner: toMerge[0].assignedRunner,\n assignedModel: toMerge.find((t) => t.assignedModel)?.assignedModel,\n taskMode: (writes ?? toMerge[0]).taskMode,\n autonomy: toMerge.find((t) => t.autonomy)?.autonomy,\n sliceType: toMerge.find((t) => t.sliceType)?.sliceType,\n ops: inheritedOps(toMerge),\n skills: toMerge.flatMap((t) => t.skills ?? []),\n userStoriesCovered: stories.length ? stories : undefined,\n },\n },\n });\n const refused = refusalOf(planned);\n if (refused) { errors.push(`${label}: ${refused}`); break; }\n adjustments.push(...planned.adjustments);\n const built = resolveTree({ ...planned, task: { ...planned.task, dependencies: [] } }, i);\n if ('error' in built) { errors.push(`${label}: ${built.error}`); break; }\n const mergedTask: Task = { ...built.task, dependencies: ids };\n const mergedId = mergedTask.id;\n const firstId = toMerge[0].id;\n const result: Task[] = [];\n let inserted = false;\n for (const t of tasks) {\n if (idSet.has(t.id)) {\n if (!inserted && t.id === firstId) { result.push(mergedTask); inserted = true; }\n continue;\n }\n result.push({ ...t, dependencies: t.dependencies.map((d) => (idSet.has(d) ? mergedId : d)) });\n }\n if (!inserted) result.push(mergedTask);\n tasks = renumberTasks(result);\n if (op.handle) handleId.set(op.handle, mergedId);\n summary.push(`Merged ${toMerge.length} tasks into \"${spec.title}\"`);\n break;\n }\n case 'split': {\n const ref = resolveRef(op.taskId, currentTasks, tasks, handleOwner, handleId, i);\n if ('error' in ref) { errors.push(`${label}: ${ref.error}`); break; }\n const target = findTopLevel(tasks, ref.id);\n if (!target) { errors.push(`${label}: task \"${op.taskId}\" not found`); break; }\n const locked = lockedTaskRefusal(target, 'split');\n if (locked) { errors.push(`${label}: ${locked}`); break; }\n const parts = op.parts ?? [];\n if (parts.length < 2) { errors.push(`${label}: split needs at least two parts`); break; }\n const newTasks: Task[] = [];\n let prevId: string | undefined;\n let buildError = false;\n for (let p = 0; p < parts.length; p++) {\n const spec = parts[p];\n if (!spec || !spec.title) { errors.push(`${label}: split part ${p + 1} needs a title`); buildError = true; break; }\n // Part 0 inherits the original's (external) dependencies, resolved\n // against the current plan. Later parts chain onto the previous part\n // — a sibling id created in this same op, so it needs no resolution.\n let deps: string[];\n if (p === 0) {\n const { ids, bad } = resolveDeps(target.dependencies, i);\n if (bad.length) { errors.push(`${label}: split part 1 unknown dependencies: ${bad.join(', ')}`); buildError = true; break; }\n deps = ids;\n } else {\n deps = prevId ? [prevId] : [];\n }\n const planned = plannedTask(spec, intake, {\n freshIds: true,\n newId,\n from: {\n readOnly: isReadOnly(target, catalog),\n fields: {\n type: target.type,\n assignedRunner: target.assignedRunner,\n assignedModel: target.assignedModel,\n taskMode: target.taskMode,\n autonomy: target.autonomy,\n sliceType: target.sliceType,\n ops: inheritedOps([target]),\n skills: target.skills,\n userStoriesCovered: target.userStoriesCovered,\n },\n },\n });\n const refused = refusalOf(planned);\n if (refused) { errors.push(`${label}: split part ${p + 1}: ${refused}`); buildError = true; break; }\n adjustments.push(...planned.adjustments);\n const resolved = resolveTree({ ...planned, task: { ...planned.task, dependencies: [] } }, i);\n if ('error' in resolved) { errors.push(`${label}: split part ${p + 1}: ${resolved.error}`); buildError = true; break; }\n const nt: Task = { ...resolved.task, dependencies: deps };\n newTasks.push(nt);\n prevId = nt.id;\n }\n if (buildError) break;\n const tailId = newTasks[newTasks.length - 1].id;\n const result: Task[] = [];\n for (const t of tasks) {\n if (t.id === target.id) { result.push(...newTasks); continue; }\n result.push({ ...t, dependencies: t.dependencies.map((d) => (d === target.id ? tailId : d)) });\n }\n tasks = renumberTasks(result);\n if (op.handle) handleId.set(op.handle, tailId);\n summary.push(`Split \"${target.title}\" into ${newTasks.length} tasks`);\n break;\n }\n case 'rearm': {\n // Re-arming is the sanctioned exception to the planner lock — its whole\n // point is to touch a task the lock would otherwise refuse — so it\n // validates as a direct edit; well-formedness still applies.\n const prep = prepareEdit(op, i, label, 'direct', true);\n if ('error' in prep) { errors.push(prep.error); break; }\n const { target, changes, fields, check } = prep;\n tasks = updateTaskInPlan(tasks, target.id, { ...changes, status: 'pending', verdict: undefined, outputSummary: undefined, awaitingReason: undefined, resumeAt: undefined, skipReason: undefined });\n const clearedNote = check.clear?.length ? `; cleared ${check.clear.join(', ')}` : '';\n const changedNote = fields.length ? ` (${fields.join(', ')})` : '';\n summary.push(`Re-armed \"${target.title}\"${changedNote}${clearedNote}`);\n break;\n }\n default:\n errors.push(`${label}: unknown op \"${(op as { op: string }).op}\"`);\n }\n if (errors.length) break;\n lastLabel = label;\n // Invariants are judged on the final state, so a later op may complete an\n // earlier one; here they only record which op a breach belongs to.\n const now = new Set(checkPlanInvariants(tasks, runners, catalog?.runnerModes).map(breachKey));\n for (const key of brokenBy.keys()) if (!now.has(key)) brokenBy.delete(key);\n for (const key of now) if (!standing.has(key) && !brokenBy.has(key)) brokenBy.set(key, label);\n }\n\n if (!errors.length) {\n for (const e of checkPlanInvariants(tasks, runners, catalog?.runnerModes)) {\n const key = breachKey(e);\n if (!standing.has(key)) errors.push(`${brokenBy.get(key) ?? lastLabel}: ${e.message}`);\n }\n }\n\n // Display order is maintained, not demanded: whatever the batch produced,\n // the plan comes back with dependencies ahead of their dependents. The\n // planner never has to re-declare the whole order to move one task.\n if (!errors.length) {\n const repaired = repairOrder(tasks);\n if ('error' in repaired) {\n errors.push(repaired.error);\n } else {\n const moves = describeMoves(tasks, repaired.tasks);\n if (moves) summary.push(`Reordered to keep dependencies first: ${moves}`);\n tasks = renumberTasks(repaired.tasks);\n }\n }\n\n if (errors.length) return { ok: false, tasks: currentTasks, errors, summary: [] };\n // A later op may move or remove what an earlier one adjusted: only what still stands is reported.\n const landed = new Map(flattenTasks(tasks).map((t) => [t.id, t]));\n const told = new Set<string>();\n const standingAdjustments = adjustments.filter((a) => {\n const task = landed.get(a.taskId);\n const now = a.field === 'assignedModel' ? task?.assignedModel?.modelId : task?.assignedModel?.thinkingEffort;\n const key = `${a.taskId}\\u0000${a.field}`;\n if (task === undefined || (now ?? null) !== a.to || told.has(key)) return false;\n told.add(key);\n return true;\n });\n return { ok: true, tasks, errors: [], summary, handles: handleId, adjustments: standingAdjustments };\n}\n","import type { AwaitingReason } from '../models/Task';\n\n/**\n * What a row's status means to a reader, before any surface picks a word,\n * icon or colour for it. `quiet` is a running task whose runner has printed\n * nothing for a while — the status is still `in_progress`, so only the row,\n * never the store, tells the two apart.\n */\nexport type TaskStatusKind = 'todo' | 'running' | 'quiet' | 'awaiting' | 'blocked' | 'failed' | 'skipped' | 'done';\n\n/** A task with a runner live behind it. `in_progress` is the store's own status. */\nexport const isTaskRunning = (task: { status: string }): boolean =>\n task.status === 'in_progress' || task.status === 'running';\n\n/** Statuses of a task that has not started: what can still be started by hand, or flipped between change and ops (ADR-0020). */\nexport const NOT_STARTED: ReadonlySet<string> = new Set(['pending', 'approved', 'blocked']);\n\nexport function taskStatusKind(task: { status: string; idleSince?: string | null }): TaskStatusKind {\n switch (task.status) {\n case 'completed': return 'done';\n case 'failed': return 'failed';\n case 'skipped': return 'skipped';\n case 'blocked': return 'blocked';\n case 'awaiting_user': return 'awaiting';\n }\n if (!isTaskRunning(task)) return 'todo';\n return task.status === 'in_progress' && task.idleSince ? 'quiet' : 'running';\n}\n\nconst AWAITING_LABELS: Record<AwaitingReason, string> = {\n input: 'Waiting for your input',\n checkpoint: 'Checkpoint',\n conflict: 'Merge conflict',\n 'files-changed': 'Changed tracked files',\n 'usage-limit': 'Paused on a usage limit',\n};\n\n/** What an awaiting_user task waits on (ADR-0018, W1); null when no reason was saved. */\nexport function awaitingLabel(task: { status: string; awaitingReason?: AwaitingReason }): string | null {\n return task.status === 'awaiting_user' && task.awaitingReason ? AWAITING_LABELS[task.awaitingReason] : null;\n}\n\n/** \"Blocked by #1, #2.1\": the failed tasks a blocked task waits on, by reference (ADR-0034). */\nexport function blockedByLabel(refs: readonly string[]): string {\n return `Blocked by ${refs.join(', ')}`;\n}\n\n/** \"Skipped: no GPU on this host\", or \"Skipped\" when no reason was given. */\nexport function skippedLabel(reason: string | null): string {\n return reason ? `Skipped: ${reason}` : 'Skipped';\n}\n\n/**\n * A task added after the user approved the plan, which the scheduler leaves\n * for them (ADR-0035). Not a runner approval: nothing has started, so no\n * runner is asking anything.\n */\nexport const WAITS_FOR_APPROVAL_LABEL = 'Waits for your approval';\n\n/** Runner requests a task waits on (ADR-0018, A1); null when none do. */\nexport function approvalLabel(count: number | undefined): string | null {\n if (!count) return null;\n return count > 1 ? `Waiting for approval (${count})` : 'Waiting for approval';\n}\n\n/**\n * When a paused task resumes, as a reader's clock shows it: \"8:10pm\", or\n * \"Oct 14, 8:10pm\" when it is not today. Read in the local time zone of\n * whoever formats it.\n */\nexport function resumeTime(at: Date, now: Date = new Date()): string {\n const clock = at.toLocaleTimeString('en-US', { hour: 'numeric', minute: at.getMinutes() === 0 ? undefined : '2-digit', hour12: true })\n .replace(/[ \\u202f]([AP]M)$/i, (_m, meridiem: string) => meridiem.toLowerCase());\n if (at.toDateString() === now.toDateString()) return clock;\n return `${at.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}, ${clock}`;\n}\n\n/** \"Resumes at 8:10pm\" for a task paused on a usage limit that resumes on its own; null for any other. */\nexport function resumeLabel(task: { status: string; awaitingReason?: AwaitingReason; resumeAt?: string | null }, now: Date = new Date()): string | null {\n if (task.status !== 'awaiting_user' || task.awaitingReason !== 'usage-limit' || !task.resumeAt) return null;\n const at = new Date(task.resumeAt);\n return Number.isNaN(at.getTime()) ? null : `Resumes at ${resumeTime(at, now)}`;\n}\n","import { dependencyTargetErrors, findDependencyCycle } from './PlanTree';\nimport { v4 as uuidv4 } from 'uuid';\nimport { Task, RunnerId, TaskModelAssignment, DEFAULT_RUNNERS, createTask, flattenTasksWithParents, inheritedSkills, skillNames } from '../models/Task';\nimport { taggedReadOnlyMode, type RunnerModeInfo } from './ModeResolver';\nimport { resolveAssignment, type AssignmentAdjustment, type AssignmentCatalog } from './TaskAssignment';\n\n/** One reason a planned task was refused, pinned to the task and field it is about. */\nexport interface PlanTaskError {\n /** Absent when the envelope itself is wrong rather than one of its tasks. */\n taskId?: string;\n field: string;\n message: string;\n}\n\n/** What a planned task may be given: the runners it may run on and their modes. */\nexport interface IntakeCatalog {\n runners: readonly RunnerId[];\n /** Absent when no runner's modes are known: the mode is then guessed (ADR-0031). */\n runnerModes?: Partial<Record<RunnerId, readonly RunnerModeInfo[]>>;\n autonomousDefault?: boolean;\n /**\n * An edit's assignments are resolved against the catalog as it is planned,\n * and a model it names that the runner does not offer is refused; a\n * submitted plan's models are resolved as it lands instead (ADR-0003).\n */\n models?: AssignmentCatalog;\n}\n\n/** Where a planned task lands, which decides what it inherits. */\nexport interface Placement {\n /** The task it is a subtask of. */\n parent?: Pick<Task, 'title' | 'sliceType' | 'autonomy'> & { readOnly: boolean };\n /**\n * A task made from others — a merge, or a split part: what the planner\n * leaves out comes from these fields, and it stays read-only when they were.\n */\n from?: { fields: Partial<Task>; readOnly: boolean };\n /**\n * An edit's tasks get ids of their own, so a planner cannot name one after\n * a task already in the plan. A submitted plan keeps the planner's, which\n * its dependencies are written against; one it left out is made up.\n */\n freshIds?: boolean;\n /** Where a made-up id comes from: a new one each time, unless the caller keeps them. */\n newId?: () => string;\n}\n\nexport interface PlannedTask {\n task: Task;\n /** Rules the task, or one of its subtasks, breaks on its own. */\n errors: PlanTaskError[];\n /**\n * What the planner asked for that is not its to set — a mode, or read-only\n * on a manual task (ADR-0031). A whole plan lands without it; an edit is\n * refused.\n */\n ignored: PlanTaskError[];\n /** The planner's id for each task of the tree that was given a fresh one. */\n renamed: Map<string, string>;\n /** What the tree's assignments were adjusted to beyond what the planner wrote, for the planner to be told. */\n adjustments: AssignmentAdjustment[];\n}\n\n/** The planner names no mode (ADR-0031): it says read-only, and the mode follows. */\nexport const MODE_NOT_THE_PLANNERS = '\"taskMode\" is the user\\'s to choose: set \"readOnly\": true on a task that must not change files, and leave it out otherwise';\n\n/** A manual task runs in no mode, so it cannot be read-only. */\nexport const MANUAL_NOT_READ_ONLY = '\"readOnly\" is for AI tasks: a manual task runs in no mode';\n\n/** An ops task acts — runs commands — in the session's mode (ADR-0020); a read-only mode refuses that. */\nexport const OPS_NOT_READ_ONLY = '\"readOnly\" is not for an ops task: it runs commands, in the session\\'s mode, and a read-only mode refuses them';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction text(value: unknown): string | undefined {\n return typeof value === 'string' || typeof value === 'number' ? String(value) : undefined;\n}\n\n/**\n * Why a task may not be an ops task (ADR-0020), or null when it may: the flag\n * decides where the task runs, and a manual task runs nowhere, a subtask\n * where its parent does.\n */\nexport function opsPlacementRefusal(type: Task['type'], isSubtask: boolean): string | null {\n if (type !== 'ai') return 'is a manual task: only an AI task can be an ops task';\n if (isSubtask) return 'is a subtask, which runs with its parent: only a top-level task can be an ops task';\n return null;\n}\n\n/** How an error names a task, so the planner can find the object it wrote. */\nexport function taskWhere(title: string, parentTitle?: string): string {\n return parentTitle !== undefined ? `subtask \"${title}\" of \"${parentTitle}\"` : `Task \"${title}\"`;\n}\n\n/**\n * What each planned task asked to attach, as the planner wrote it. Kept beside\n * the task rather than on it: {@link skillNames} drops a name no skill could\n * have, and the plan's skill check still owes a warning for it. A copy of the\n * task (assignment coercion) does not carry it, so check what was planned.\n */\nconst skillsAsked = new WeakMap<Task, unknown[]>();\n\n/** The `skills` a planned task was submitted with, before normalization; undefined for a task not planned here. */\nexport function requestedSkills(task: Task): readonly unknown[] | undefined {\n return skillsAsked.get(task);\n}\n\n/** The model as a task stores it; a top-level `thinkingEffort` is the model's, as the effort has one home. */\nfunction modelOf(raw: Record<string, unknown>, from: TaskModelAssignment | undefined): TaskModelAssignment | undefined {\n const effort = text(raw.thinkingEffort);\n if (isRecord(raw.assignedModel)) {\n const m = raw.assignedModel;\n return {\n modelId: text(m.modelId) ?? '',\n modelLabel: text(m.modelLabel) ?? '',\n thinkingEffort: text(m.thinkingEffort) ?? effort,\n };\n }\n return from && effort !== undefined ? { ...from, thinkingEffort: effort } : from;\n}\n\n/**\n * Build a task from what a planner wrote, by whichever route it arrived: a\n * submitted plan, or an edit that adds, merges or splits. Every fallback a\n * planner's omission meets is here, so the routes cannot drift apart:\n *\n * - the runner is the one named, else the task's it is made from, else the\n * first one allowed — never a substitute for one named but unknown, which\n * {@link checkPlanInvariants} refuses;\n * - an AI task's prompt is its own, else its description, else its title, so\n * it is never unschedulable;\n * - the assignment — model, effort, and the mode decided from read-only or\n * not, never named (ADR-0031) — is the resolver's (`resolveAssignment`),\n * as it is for every writer: a model a merge or split carries is read as\n * what the task was made from, so a part moved to another runner gets that\n * runner's;\n * - an AI subtask with no slice classification takes its parent's: an `ai`\n * sub-step of an AFK slice is AFK. Not a blanket default, which would strip\n * a human gate the planner intended; a manual subtask must still say HITL.\n */\nexport function plannedTask(spec: unknown, catalog: IntakeCatalog, at: Placement = {}): PlannedTask {\n const raw = isRecord(spec) ? spec : {};\n const { parent, from, freshIds, newId = uuidv4 } = at;\n const base = from?.fields ?? {};\n const errors: PlanTaskError[] = [];\n const ignored: PlanTaskError[] = [];\n const renamed = new Map<string, string>();\n const adjustments: AssignmentAdjustment[] = [];\n\n const title = text(raw.title) ?? '';\n const where = taskWhere(title, parent?.title);\n const plannerId = text(raw.id);\n const id = freshIds || !plannerId ? newId() : plannerId;\n if (freshIds && plannerId) renamed.set(plannerId, id);\n\n const type: Task['type'] = raw.type === 'user' || raw.type === 'ai' ? raw.type : base.type ?? 'ai';\n const ai = type === 'ai';\n const assignedRunner = text(raw.assignedRunner) ?? base.assignedRunner ?? catalog.runners[0] ?? DEFAULT_RUNNERS[0];\n const description = text(raw.description) ?? base.description ?? title;\n\n // A manual task stores no ops flag, so this is the one place it can still be seen.\n if (raw.ops === true && !ai) errors.push({ taskId: id, field: 'ops', message: `${where} ${opsPlacementRefusal(type, !!parent)}` });\n if (raw.taskMode !== undefined) ignored.push({ taskId: id, field: 'taskMode', message: `${where}: ${MODE_NOT_THE_PLANNERS}` });\n if (!ai && raw.readOnly === true) ignored.push({ taskId: id, field: 'readOnly', message: `${where}: ${MANUAL_NOT_READ_ONLY}` });\n const ops = raw.ops !== undefined ? raw.ops === true : base.ops;\n if (ai && ops && raw.readOnly === true) ignored.push({ taskId: id, field: 'readOnly', message: `${where}: ${OPS_NOT_READ_ONLY}` });\n // A read-only task's subtasks run as tasks of their own, so they would\n // otherwise get write access the planner said the work must not have.\n const asked = typeof raw.readOnly === 'boolean' ? raw.readOnly : undefined;\n const readOnly = ai && !ops && (asked ?? from?.readOnly ?? parent?.readOnly ?? false);\n\n const assignedModel = ai ? modelOf(raw, base.assignedModel) : undefined;\n const slice = (value: unknown): 'AFK' | 'HITL' | undefined => (value === 'AFK' || value === 'HITL' ? value : undefined);\n // Explicit child values always win; inheritance only fills a gap, and only for `ai` tasks.\n const autonomy = ai ? slice(raw.autonomy) ?? base.autonomy ?? parent?.autonomy : undefined;\n const sliceType = slice(raw.sliceType) ?? base.sliceType ?? (ai ? parent?.sliceType : undefined);\n\n const subtasks: Task[] = [];\n if (Array.isArray(raw.subtasks)) {\n for (const s of raw.subtasks) {\n const child = plannedTask(s, catalog, { parent: { title, sliceType, autonomy, readOnly }, freshIds, newId });\n subtasks.push(child.task);\n errors.push(...child.errors);\n ignored.push(...child.ignored);\n adjustments.push(...child.adjustments);\n for (const [was, now] of child.renamed) renamed.set(was, now);\n }\n }\n\n const fields = {\n id,\n order: Number(raw.order ?? 0),\n title,\n description,\n type,\n dependencies: Array.isArray(raw.dependencies) ? raw.dependencies.map(String) : base.dependencies ?? [],\n prompt: text(raw.prompt) || base.prompt || (ai ? description || title || undefined : undefined),\n userSteps: Array.isArray(raw.userSteps)\n ? raw.userSteps.map((s) => (isRecord(s) ? s : {})).map((s) => ({ order: Number(s.order ?? 0), instruction: String(s.instruction ?? ''), completed: false }))\n : base.userSteps,\n subtasks,\n assignedModel,\n assignedRunner,\n autonomy,\n sliceType,\n userStoriesCovered: Array.isArray(raw.userStoriesCovered) ? raw.userStoriesCovered.map(String) : base.userStoriesCovered,\n ops,\n skills: from ? inheritedSkills(raw.skills, base.skills) : skillNames(raw.skills),\n };\n let taskMode = base.taskMode;\n let landedModel = assignedModel;\n if (ai && catalog.runners.includes(assignedRunner)) {\n const resolved = resolveAssignment({\n writer: catalog.models ? 'edit' : 'plan',\n task: { ...createTask(fields), taskMode },\n from: from ? { assignedRunner: base.assignedRunner ?? assignedRunner, assignedModel: base.assignedModel, taskMode: base.taskMode } : undefined,\n readOnly,\n catalog: { modelsByRunner: {}, ...catalog.models, runnerModes: catalog.runnerModes, autonomousDefault: catalog.autonomousDefault },\n });\n if (!resolved.ok) {\n // The planner names no mode: one it cannot have is about the read-only answer it gave (ADR-0031).\n errors.push({ taskId: id, field: resolved.field === 'taskMode' ? 'readOnly' : resolved.field, message: `${where}: ${resolved.error}` });\n } else {\n taskMode = resolved.task.taskMode;\n landedModel = resolved.task.assignedModel;\n adjustments.push(...resolved.adjustments);\n }\n }\n // With no runner modes to read, `plan` is the guess that keeps a read-only task from writing.\n if (taskMode === undefined && readOnly && !catalog.runnerModes) taskMode = 'plan';\n\n const task = createTask({ ...fields, assignedModel: landedModel, taskMode });\n if (Array.isArray(raw.skills)) skillsAsked.set(task, raw.skills);\n return { task, errors, ignored, renamed, adjustments };\n}\n\n/**\n * The rules a plan's tasks are held to together, subtasks included, whichever\n * route they arrived by and whoever wrote them, the planner or the user.\n * `runners` are the ones the writer may put a task on (`assignableRunners`),\n * any when undefined; with `runnerModes`, an ops task is held off its\n * runner's read-only mode.\n */\nexport function checkPlanInvariants(\n tasks: readonly Task[],\n runners: readonly RunnerId[] | undefined,\n runnerModes?: Partial<Record<RunnerId, readonly RunnerModeInfo[]>>,\n): PlanTaskError[] {\n const rows = flattenTasksWithParents(tasks);\n const errors: PlanTaskError[] = [];\n const seen = new Set<string>();\n for (const { task: t, parent } of rows) {\n const where = taskWhere(t.title, parent?.title);\n const fail = (field: string, message: string) => errors.push({ taskId: t.id, field, message });\n if (seen.has(t.id)) fail('id', `${where} has id \"${t.id}\", which another task in the plan has too: every task, subtasks included, needs an id of its own`);\n seen.add(t.id);\n if (t.autonomy === 'AFK' && t.userSteps && t.userSteps.length > 0) {\n fail('userSteps', `${where} has autonomy \"AFK\" but contains userSteps. AFK tasks must not have user touchpoints.`);\n }\n if (t.type === 'user' && t.sliceType && t.sliceType !== 'HITL') {\n fail('sliceType', `User ${where} has sliceType \"${t.sliceType}\". User tasks must have sliceType \"HITL\".`);\n }\n const opsRefused = t.ops ? opsPlacementRefusal(t.type, parent !== null) : null;\n if (opsRefused) fail('ops', `${where} ${opsRefused}`);\n if (t.ops && t.taskMode !== undefined && t.taskMode === taggedReadOnlyMode(runnerModes?.[t.assignedRunner])) {\n fail('taskMode', `${where} is an ops task, which runs commands, so it cannot run in its runner's read-only mode`);\n }\n if (runners && t.type !== 'user' && !runners.includes(t.assignedRunner)) {\n fail('assignedRunner', `${where} has invalid assignedRunner \"${t.assignedRunner}\". Expected one of: ${runners.join(', ')}`);\n }\n }\n for (const { task: t, parent } of rows) {\n // Self-dependencies are reported with the cycle below, including its full path.\n for (const error of dependencyTargetErrors(tasks, t.id, t.dependencies.filter((id) => id !== t.id))) {\n errors.push({ taskId: t.id, field: 'dependencies', message: `${taskWhere(t.title, parent?.title)}: ${error}` });\n }\n }\n const cycle = findCycle(rows.map((r) => r.task));\n // Pinned to a task on the cycle: a plan whose only fault is a rule a task\n // breaks is worth naming back to the planner, not re-asking for as JSON.\n if (cycle) errors.push({ taskId: cycle[0].id, field: 'dependencies', message: `Dependency cycle detected: ${[...cycle, cycle[0]].map((t) => `\"${t.title}\"`).join(' → ')}` });\n return errors;\n}\n\n/** The tasks on one dependency cycle, in dependency order, or null when there is none. A self-dependency is a cycle of one. */\nexport function findCycle(tasks: readonly Task[]): Task[] | null {\n return findDependencyCycle(tasks);\n}\n\n/** The title of a task on a dependency cycle, or null when there is none. */\nexport function detectCycle(tasks: readonly Task[]): string | null {\n return findCycle(tasks)?.[0].title ?? null;\n}\n","import type { DiscoveredModel, RunnerId } from '../models/Task';\n\n/**\n * The ids a runner may actually run: the user's allowlist with the ids that\n * provably belong to a *different* runner dropped. `undefined` means no\n * restriction.\n *\n * Model ids are scoped to the agent that lists them, so an OpenRouter slug\n * allowlisted for Claude Code does not limit it — it points it at something it\n * cannot spawn, and the plan only dies once a task is already running. But\n * \"this runner didn't list it\" is not enough to call an id wrong: discovery can\n * be stale or return no list at all. What settles it is\n * whether *another* runner listed the id. So:\n *\n * - listed for this runner → keep;\n * - listed for no runner → unknown, and the user said it explicitly, so keep it\n * and let the runner validate last (the same call `resolveAssignment` makes);\n * - listed only for other runners → provably not this runner's, so drop it.\n *\n * When that leaves nothing, the whole allowlist was about some other runner\n * (a settings file written before a surface scoped its picker to one). No\n * restriction is the only safe reading — the alternative is handing the planner\n * a list of models that cannot run.\n */\nexport function effectiveAllowlist(\n allowlist: string[] | undefined,\n runner: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>> | undefined,\n): string[] | undefined {\n if (!allowlist || allowlist.length === 0) return undefined;\n if (!modelsByRunner) return allowlist;\n\n const own = new Set((modelsByRunner[runner] ?? []).map((m) => m.modelId));\n const elsewhere = new Set<string>();\n for (const [other, models] of Object.entries(modelsByRunner)) {\n if (other === runner) continue;\n for (const m of models ?? []) elsewhere.add(m.modelId);\n }\n\n const kept = allowlist.filter((id) => own.has(id) || !elsewhere.has(id));\n return kept.length > 0 ? kept : undefined;\n}\n\nexport function filterModelsForPrompt(\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n perRunnerAllowlist: Partial<Record<RunnerId, string[]>>,\n): Partial<Record<RunnerId, DiscoveredModel[]>> {\n const result: Partial<Record<RunnerId, DiscoveredModel[]>> = {};\n for (const [runner, models] of Object.entries(modelsByRunner)) {\n if (!models) continue;\n const allowed = effectiveAllowlist(perRunnerAllowlist[runner], runner, modelsByRunner);\n if (!allowed) {\n result[runner] = models;\n continue;\n }\n const allowedSet = new Set(allowed);\n const intersection = models.filter((m) => allowedSet.has(m.modelId));\n // A set allowlist is a hard constraint: the planner must never see models\n // outside it. An allowed id no runner has listed is one discovery doesn't\n // cover, so synthesize an entry rather than leaking the full list.\n const covered = new Set(intersection.map((m) => m.modelId));\n const missing = allowed\n .filter((id) => !covered.has(id))\n .map((id) => ({ modelId: id, modelLabel: id.split('/').pop() || id, variants: [] }));\n result[runner] = [...intersection, ...missing];\n }\n return result;\n}\n\n/** Canonical low→high ordering of the well-known effort ladder. */\nconst EFFORT_LADDER = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'ultra'];\n/** Runner-specific spellings mapped onto the ladder. */\nconst EFFORT_ALIASES: Record<string, string> = { disabled: 'none', adaptive: 'medium' };\n\n/**\n * The one rule for an effort and a model: the effort a task keeps on a model,\n * whether it was written with it or carried from the model before. Kept where\n * the model offers it; otherwise mapped to the nearest rung the model\n * supports (so a Claude-style \"xhigh\" on a low/medium/high model becomes\n * \"high\"); undefined — the runner's own default — when no mapping exists or\n * the model offers no levels, which is how a model discovery does not list\n * reads (`variants` empty). Core's resolver and every surface's model picker\n * call it, so a model change lands on the same effort wherever it is made.\n */\nexport function clampThinkingEffort(\n effort: string | undefined,\n variants: { id: string }[],\n): string | undefined {\n if (!effort) return undefined;\n if (variants.length === 0) return undefined;\n const ids = new Set(variants.map((v) => v.id));\n if (ids.has(effort)) return effort;\n const canon = EFFORT_ALIASES[effort] ?? effort;\n if (ids.has(canon)) return canon;\n const idx = EFFORT_LADDER.indexOf(canon);\n if (idx < 0) return undefined;\n for (let d = 1; d < EFFORT_LADDER.length; d++) {\n const lower = EFFORT_LADDER[idx - d];\n if (lower && ids.has(lower)) return lower;\n const higher = EFFORT_LADDER[idx + d];\n if (higher && ids.has(higher)) return higher;\n }\n return undefined;\n}\n","import type { ResearchStepOutcome } from '../models/Task';\n\n/**\n * One-line human summary of a research tool call, shared by every surface that\n * renders live planner progress (VS Code webview, CLI, TUI). Kept in core so\n * the arg-shape heuristics (file path vs. pattern vs. shell command) live in\n * one place instead of being re-derived per surface — which also means a new\n * tool becomes readable in all three UIs by being handled here once.\n */\n\nfunction ellipsize(text: string, max: number): string {\n const oneLine = text.replace(/\\s+/g, ' ').trim();\n return oneLine.length > max ? `${oneLine.slice(0, max)}…` : oneLine;\n}\n\n/**\n * @param toolLabel The agent's own name for the tool, when a harness planner\n * produced the call (ADR-0009). It replaces the member name in the summary, so\n * the timeline says `Edit` rather than the catch-all `agent_tool` — and says\n * `WebFetch` rather than claiming a shell command ran.\n */\nexport function summarizeToolCall(tool: string, argsJson: string, toolLabel?: string): string {\n const display = toolLabel?.trim() || tool;\n if (tool === 'agent_tool') {\n // No Ordewell equivalent, so no arg shape to rely on: show the agent's name\n // plus whichever conventional field the call happens to carry.\n try {\n const args = JSON.parse(argsJson);\n const hint = args.path ?? args.file_path ?? args.filePath ?? args.pattern ?? args.query ?? args.url ?? args.command;\n if (hint) return `${display} ${ellipsize(String(hint), 50)}`;\n } catch {\n // fall through to the bare name\n }\n return display;\n }\n\n if (tool === 'spawn_research_agent') {\n try {\n const args = JSON.parse(argsJson);\n const prompt = typeof args.prompt === 'string' ? args.prompt : '';\n const oneLine = prompt.replace(/\\s+/g, ' ').trim();\n return `spawn: \"${oneLine.slice(0, 60)}${oneLine.length > 60 ? '…' : ''}\"`;\n } catch {\n return 'spawn_research_agent';\n }\n }\n\n try {\n const args = JSON.parse(argsJson);\n\n // Ordered by specificity: a tool's defining argument wins over the generic\n // `path`, which several of the newer tools also accept as a search root.\n if (tool === 'find_symbol' && args.symbol) {\n return `find_symbol ${args.symbol}${args.language ? ` [${args.language}]` : ''}`;\n }\n if (tool === 'web_search' && args.query) {\n return `web_search \"${ellipsize(String(args.query), 50)}\"`;\n }\n if (tool === 'fetch' && args.url) {\n return `fetch ${ellipsize(String(args.url), 60)}`;\n }\n // The pattern is what a glob is about; the generic `path` below is only its\n // search root, and reporting that read as \"glob src\" for every call.\n if (tool === 'glob' && args.pattern) {\n return `glob ${ellipsize(String(args.pattern), 50)}`;\n }\n if (tool === 'grep' && args.pattern) {\n const mode = args.output_mode && args.output_mode !== 'content' ? ` (${args.output_mode})` : '';\n const scope = args.include ? ` in ${args.include}` : '';\n return `grep ${ellipsize(String(args.pattern), 40)}${scope}${mode}`;\n }\n\n const path = args.filePath || args.file_path || args.path;\n if (path) {\n const basename = String(path).split('/').pop() || String(path);\n return `${display} ${basename}`;\n }\n if (args.pattern) {\n return `${display} ${args.pattern}`;\n }\n if (args.command) {\n return `bash: ${String(args.command).slice(0, 40)}`;\n }\n } catch {\n // fall through to the bare tool name below\n }\n return display;\n}\n\n/**\n * Classify a tool outcome from its result text and success flag, so a surface\n * can render a refused `rm` or a denied `npm test` distinctly from a\n * successful run without re-deriving the refusal signatures per surface. The\n * refusal/denial strings come from `commandPolicy.ts`, `BaseFileSystem.ts`,\n * `webReadPolicy.ts` and the research-subagent wrapper — keeping the matching\n * here means the signatures stay in one place alongside the human summary.\n */\nexport function classifyOutcome(success: boolean, output: string): ResearchStepOutcome {\n if (!success) {\n if (/^(Command|Fetch|Web search) refused:/.test(output) || /is not available\\. You are a read-only research subagent/.test(output)) return 'refused';\n if (/not approved/i.test(output) || /^Access denied:/.test(output) || /needs user approval/i.test(output)) return 'denied';\n return 'failure';\n }\n return 'success';\n}\n","import type { DiffStat, ToolHeadline } from './blocks';\n\n// eslint-disable-next-line no-control-regex\nconst ANSI_OR_CTRL_RE = /\\x1b\\[[0-9;?]*[A-Za-z]|\\x1b\\][^\\x07\\x1b]*(?:\\x07|\\x1b\\\\)?|\\x1b[()][AB012]|\\x1b[=>]|[\\x00-\\x08\\x0b-\\x1f\\x7f]/g;\n\n/**\n * How a command row names an Ordewell research tool. A harness planner's call\n * keeps the agent's own name instead (`toolLabel`, ADR-0009), so the row says\n * which tool actually ran.\n */\nconst DISPLAY_NAMES: Record<string, string> = {\n read_file: 'Read',\n read_files: 'Read',\n list_dir: 'List',\n glob: 'Glob',\n grep: 'Grep',\n find_symbol: 'Symbol',\n bash: 'Bash',\n fetch: 'Fetch',\n web_search: 'WebSearch',\n spawn_research_agent: 'Agent',\n};\n\n// Tried in order for a tool with no rule of its own: the field that names what\n// a call is about comes before the free text around it.\nconst HINT_FIELDS = ['file_path', 'filePath', 'path', 'url', 'pattern', 'query', 'command', 'description', 'prompt'] as const;\n\nfunction parseArgs(args: string): Record<string, unknown> | null {\n try {\n const parsed: unknown = JSON.parse(args);\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed as Record<string, unknown> : null;\n } catch {\n return null;\n }\n}\n\nfunction oneLine(text: string): string {\n return text.replace(/\\s+/g, ' ').trim();\n}\n\n// A command's later lines can change what it does (a heredoc body, a chained\n// step), so they are counted rather than folded into the first.\nfunction firstLineOf(command: string): string {\n const lines = command.trim().split(/\\r?\\n/);\n const more = lines.length - 1;\n return more > 0 ? `${lines[0]} … +${more} line${more === 1 ? '' : 's'}` : lines[0];\n}\n\nfunction text(value: unknown): string {\n return typeof value === 'string' ? value : '';\n}\n\nfunction searchArg(pattern: string, path: string, include = ''): string {\n return `${pattern}${path ? ` in ${path}` : ''}${include ? ` (${include})` : ''}`;\n}\n\nfunction hintArg(args: Record<string, unknown>): string {\n for (const field of HINT_FIELDS) {\n const value = text(args[field]);\n if (value) return field === 'command' ? firstLineOf(value) : oneLine(value);\n }\n const firstText = Object.values(args).find((v): v is string => typeof v === 'string' && v.trim() !== '');\n return firstText ? oneLine(firstText) : '';\n}\n\nfunction keyArgOf(tool: string, args: Record<string, unknown>): string {\n switch (tool) {\n case 'bash':\n return firstLineOf(text(args.command));\n case 'read_file':\n case 'list_dir':\n return text(args.path);\n case 'read_files':\n return Array.isArray(args.paths) ? args.paths.map(String).join(', ') : '';\n case 'glob':\n return searchArg(text(args.pattern), text(args.path));\n case 'grep':\n return searchArg(text(args.pattern), text(args.path), text(args.include));\n case 'find_symbol':\n return `${text(args.symbol)}${text(args.language) ? ` [${text(args.language)}]` : ''}`;\n case 'fetch':\n return text(args.url);\n case 'web_search':\n return oneLine(text(args.query));\n case 'spawn_research_agent':\n return oneLine(text(args.prompt));\n default:\n return hintArg(args);\n }\n}\n\n/**\n * The one-line head of a command row, shared by every surface: the tool's name\n * and the argument that says what the call is about.\n *\n * @param args The call's arguments as announced (JSON). Anything that is not a\n * JSON object is shown as it came, on one line.\n * @param toolLabel A harness planner's own name for the tool (ADR-0009).\n */\nexport function toolHeadline(tool: string, args: string, toolLabel?: string): ToolHeadline {\n const name = toolLabel?.trim() || DISPLAY_NAMES[tool] || tool;\n const parsed = parseArgs(args);\n return { name, keyArg: parsed ? keyArgOf(tool, parsed) : oneLine(args) };\n}\n\nexport interface OutputPreview {\n lines: string[];\n hiddenLineCount: number;\n}\n\n/** The lines of a tool's output as a reader sees them — what {@link outputPreview} shows and counts. */\nexport function outputLines(output: string): string[] {\n // Line endings first: CR is itself a control character the escape pass drops.\n const lines = output.replace(/\\r\\n?/g, '\\n').replace(ANSI_OR_CTRL_RE, '').split('\\n');\n while (lines.length > 0 && lines[lines.length - 1].trim() === '') lines.pop();\n return lines;\n}\n\n/** The head of a tool's output for a collapsed row, and how many lines it leaves out. */\nexport function outputPreview(output: string, maxLines: number): OutputPreview {\n const lines = outputLines(output);\n const shown = lines.slice(0, Math.max(0, maxLines));\n return { lines: shown, hiddenLineCount: lines.length - shown.length };\n}\n\n/**\n * The lines a diff adds and removes, or null when `output` is not one: every\n * line a hunk header, context, an addition or a removal, and at least one of\n * the last two.\n */\nexport function diffStat(output: string): DiffStat | null {\n const lines = outputLines(output);\n let added = 0;\n let removed = 0;\n for (const line of lines) {\n if (line.startsWith('+')) added += 1;\n else if (line.startsWith('-')) removed += 1;\n else if (!(line.startsWith('@@') || line.startsWith(' ') || line === '' || line.startsWith('\\\\'))) return null;\n }\n return added + removed > 0 ? { added, removed } : null;\n}\n\n/** `gap` stands between two hunks, for the lines a diff leaves out. */\nexport type DiffRowKind = 'added' | 'removed' | 'context' | 'gap';\n\nexport interface DiffRow {\n kind: DiffRowKind;\n /** The line in the file: the old file's for a removal, the new file's otherwise. */\n line?: number;\n text: string;\n}\n\nconst HUNK_RANGE = /^@@ -(\\d+)(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/;\n\n/** A diff as the rows a surface draws, numbered as an editor would number them. */\nexport function diffRows(output: string): DiffRow[] {\n const rows: DiffRow[] = [];\n let oldLine = 1;\n let newLine = 1;\n for (const line of outputLines(output)) {\n const range = HUNK_RANGE.exec(line);\n if (range) {\n if (rows.length > 0) rows.push({ kind: 'gap', text: '' });\n oldLine = Number(range[1]);\n newLine = Number(range[2]);\n } else if (line.startsWith('+')) {\n rows.push({ kind: 'added', line: newLine++, text: line.slice(1) });\n } else if (line.startsWith('-')) {\n rows.push({ kind: 'removed', line: oldLine++, text: line.slice(1) });\n } else if (!line.startsWith('\\\\')) {\n rows.push({ kind: 'context', line: newLine, text: line.slice(1) });\n oldLine += 1;\n newLine += 1;\n }\n }\n return rows;\n}\n\nfunction lines(count: number): string {\n return `${count} line${count === 1 ? '' : 's'}`;\n}\n\n/** \"Added 2 lines, removed 1 line\": the summary every surface puts on an edit's row. */\nexport function diffSummary({ added, removed }: DiffStat): string {\n if (!removed) return `Added ${lines(added)}`;\n if (!added) return `Removed ${lines(removed)}`;\n return `Added ${lines(added)}, removed ${lines(removed)}`;\n}\n","import type { ResearchToolType } from '../../models/Task';\n\n/**\n * Map a coding agent's own tool name onto Ordewell's research vocabulary\n * (ADR-0009, T5).\n *\n * A harness planner brings its own toolbox, and most of it overlaps ours: a\n * `Read` is a `read_file`, a `Grep` is a `grep`. Those map onto existing\n * members and render in every surface through the code path that is already\n * there. Everything else — `Edit`, `WebFetch`, `TodoWrite`, `Task`, whatever\n * ships next — becomes `agent_tool` carrying its real name.\n *\n * Nothing is relabelled as a tool it is not. Calling a web fetch a `bash` to\n * avoid adding a union member would put a lie in the timeline, which is the\n * point ADR-0008 spent its effort establishing.\n */\nconst KNOWN_TOOLS: Record<string, ResearchToolType> = {\n // Claude Code\n read: 'read_file',\n grep: 'grep',\n glob: 'glob',\n bash: 'bash',\n ls: 'list_dir',\n webfetch: 'fetch',\n websearch: 'web_search',\n // Codex — its sandboxed command tool is a shell by another name\n shell: 'bash',\n exec_command: 'bash',\n local_shell: 'bash',\n // OpenCode\n list: 'list_dir',\n fetch: 'fetch',\n // Ordewell's own research shell (ADR-0026), under every runner's name for it\n runcommand: 'bash',\n};\n\n/**\n * Claude Code and Codex call it `mcp__ordewell__<tool>`, OpenCode `ordewell_<tool>`.\n * Spelled out rather than built from `ORDEWELL_MCP_SERVER_NAME`: the webview\n * bundles this file, and `../mcp` brings the Node-only server with it.\n */\nconst ORDEWELL_TOOL_PREFIX = /^(mcp__ordewell__|ordewell_)/i;\n\n/**\n * The tools that write a file, by their normalized names: Claude Code's,\n * OpenCode's, and the change kinds a Codex row is named for. Their output is\n * a diff (see `fileDiff.ts`) when the runner reported one.\n */\nconst FILE_EDIT_TOOLS = new Set(['edit', 'write', 'multiedit', 'notebookedit', 'applypatch', 'patch', 'add', 'update', 'delete', 'filechange']);\n\nexport function isFileEditTool(name: string): boolean {\n return FILE_EDIT_TOOLS.has(name.trim().toLowerCase().replace(/[_-]/g, ''));\n}\n\nexport interface MappedTool {\n tool: ResearchToolType;\n /** The agent's own name, kept whenever it differs from the member it mapped to. */\n toolLabel?: string;\n}\n\n/**\n * Classify one agent tool name. Case- and separator-insensitive, because the\n * three agents disagree on `Read` vs `read` vs `read_file` for the same thing.\n */\nexport function mapAgentTool(name: string): MappedTool {\n const normalized = name.trim().replace(ORDEWELL_TOOL_PREFIX, '').toLowerCase().replace(/[_-]/g, '');\n const direct = KNOWN_TOOLS[normalized] ?? KNOWN_TOOLS[name.trim().toLowerCase()];\n if (direct) {\n // The label survives even on a mapped tool: `Read` and `read_file` render\n // the same way, but the transcript should still say which one ran.\n return { tool: direct, toolLabel: name };\n }\n return { tool: 'agent_tool', toolLabel: name };\n}\n\n/**\n * Normalize an agent's tool arguments into the shapes `summarizeToolCall`\n * already knows how to read, so a harness `Read` gets a one-line summary\n * instead of a bare tool name. Unknown keys are preserved — the raw args stay\n * visible under the surfaces' output chevron.\n */\nexport function normalizeAgentArgs(tool: ResearchToolType, args: Record<string, unknown>): Record<string, unknown> {\n const out = { ...args };\n const alias = (from: string, to: string) => {\n if (out[to] === undefined && out[from] !== undefined) out[to] = out[from];\n };\n if (tool === 'read_file' || tool === 'list_dir') {\n alias('filePath', 'path');\n alias('file_path', 'path');\n alias('target', 'path');\n }\n if (tool === 'bash') {\n alias('cmd', 'command');\n alias('script', 'command');\n // Codex hands the command over as an argv array; the summary wants a string.\n if (typeof out.command !== 'string' && Array.isArray(out.command)) {\n out.command = (out.command as unknown[]).join(' ');\n }\n }\n if (tool === 'fetch') alias('uri', 'url');\n if (tool === 'web_search') alias('q', 'query');\n return out;\n}\n","import type { ResearchStep, ResearchStepOutcome, SkillLoadNotice } from '../models/Task';\nimport type { UsageLine } from '../models/Usage';\nimport type { MessageBlock, MessageRole, PlanMarkerStatus, SkillLoadBlock, SubagentBlock, ToolBlock, ToolStatus, UsageBlock } from './blocks';\nimport { diffStat, outputLines, toolHeadline } from './format';\nimport { isFileEditTool } from '../services/harness/agentTools';\n\n/*\n * How the session's records — messages, research steps, subagents, transcript\n * markers, usage totals — read as blocks. Shared by the live view and the\n * reload, so the two cannot disagree about what a record shows.\n */\n\n/** A line that is done: nothing streams into it any more. */\nexport function settledMessage(id: string, role: MessageRole, text: string, turnId?: string): MessageBlock {\n return { type: 'message', id, role, text, streaming: false, ...(turnId ? { turnId } : {}) };\n}\n\n/** The user's message, marked with the skills it loaded when it loaded any, and when it was force sent. */\nexport function userMessage(id: string, text: string, skills: readonly SkillLoadNotice[], { turnId, forced }: { turnId?: string; forced?: boolean } = {}): MessageBlock {\n const block = settledMessage(id, 'user', text, turnId);\n return {\n ...block,\n ...(skills.length > 0 ? { skills: skills.map((s) => s.name) } : {}),\n ...(forced ? { forced: true } : {}),\n };\n}\n\n/** What a surface is told of a load: everything but the body, which only the planner is sent. */\nexport function skillLoadNotice({ invokedBy, name, source, path, attaches }: SkillLoadNotice): SkillLoadNotice {\n return { invokedBy, name, source, path, ...(attaches ? { attaches } : {}) };\n}\n\n/** `load_skill` as each harness names it: bare, `mcp__ordewell__load_skill`, `ordewell_load_skill`. */\nconst LOAD_SKILL_TOOL = /(?:^|_)load_skill$/;\n\n/**\n * A research step as a surface is sent it. A `load_skill` result is a skill's\n * body, which only the planner is sent; the session keeps it in the skill-load\n * entry, so the step need only say which skill loaded.\n */\nexport function surfaceStep(step: ResearchStep): ResearchStep {\n if (!step.success || !LOAD_SKILL_TOOL.test(step.toolLabel ?? step.tool)) return step;\n const name = loadedSkillName(step.args);\n return { ...step, result: name ? `Loaded skill ${name}.` : 'Loaded a skill.' };\n}\n\nfunction loadedSkillName(args: string): string | undefined {\n try {\n const parsed: unknown = JSON.parse(args);\n const name = typeof parsed === 'object' && parsed !== null && 'name' in parsed ? parsed.name : undefined;\n return typeof name === 'string' ? name : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function skillLoadBlock(id: string, { invokedBy, name, source, path, attaches }: SkillLoadNotice, turnId?: string): SkillLoadBlock {\n return { type: 'skill_load', id, invokedBy, name, source, path, ...(attaches ? { attaches } : {}), ...(turnId ? { turnId } : {}) };\n}\n\ntype SubagentFields = Omit<SubagentBlock, 'type' | 'id' | 'toolCallId' | 'model' | 'usage' | 'turnId'>\n & { toolCallId?: string; model?: string; usage?: SubagentBlock['usage']; turnId?: string };\n\nexport function subagentBlock(id: string, { toolCallId, model, usage, turnId, ...fields }: SubagentFields): SubagentBlock {\n return {\n type: 'subagent', id, ...fields,\n ...(toolCallId ? { toolCallId } : {}),\n ...(model ? { model } : {}),\n ...(usage ? { usage } : {}),\n ...(turnId ? { turnId } : {}),\n };\n}\n\nexport function usageBlock(id: string, { totals, bySubagent, byModel, model, contextFill }: UsageLine): UsageBlock {\n return { type: 'usage', id, totals, ...(byModel ? { byModel } : {}), ...(model ? { model } : {}), ...(bySubagent ? { bySubagent } : {}), ...(contextFill ? { contextFill } : {}) };\n}\n\nconst STATUS_OF_OUTCOME: Record<ResearchStepOutcome, ToolStatus> = {\n success: 'ok',\n failure: 'error',\n refused: 'denied',\n denied: 'denied',\n not_executed: 'interrupted',\n};\n\nexport function finishedTool(call: ToolBlock, output: string, outcome: ResearchStepOutcome): ToolBlock {\n const diff = outcome === 'success' && isFileEditTool(call.toolLabel ?? call.tool) ? diffStat(output) : null;\n return { ...call, status: STATUS_OF_OUTCOME[outcome], outcome, output, outputLineCount: outputLines(output).length, ...(diff ? { diff } : {}) };\n}\n\nexport function settledTool(call: ToolBlock, step: ResearchStep): ToolBlock {\n return finishedTool(call, step.result, step.outcome);\n}\n\nexport interface AnnouncedCall {\n tool: string;\n toolLabel?: string;\n args: string;\n toolCallId?: string;\n turnId?: string;\n}\n\nexport function pendingTool(id: string, { tool, toolLabel, args, toolCallId, turnId }: AnnouncedCall): ToolBlock {\n return {\n type: 'tool', id, tool, headline: toolHeadline(tool, args, toolLabel), args, status: 'pending', output: '', outputLineCount: 0,\n ...(toolCallId ? { toolCallId } : {}),\n ...(toolLabel ? { toolLabel } : {}),\n ...(turnId ? { turnId } : {}),\n };\n}\n\n/** The row of a call known only from its result — a reload, or a result whose call was never announced. */\nexport function toolFromStep(id: string, step: ResearchStep, turnId?: string): ToolBlock {\n return settledTool(pendingTool(id, { ...step, turnId }), step);\n}\n\n/**\n * What a plan marker says, read from the transcript entry `PlannerConversation`\n * writes for it (\"Plan generated with 2 tasks.\", \"Plan updated — now 1 task.\").\n * That entry is the only record of the marker a reload has, so the live view\n * reads the same text rather than counting tasks itself.\n */\nexport function planMarker(content: string): { status: Exclude<PlanMarkerStatus, 'building'>; taskCount?: number } {\n const count = /(\\d+) tasks?\\b/.exec(content);\n return { status: content.startsWith('Plan updated') ? 'updated' : 'generated', ...(count ? { taskCount: Number(count[1]) } : {}) };\n}\n","/** What the blocked rule reads of a task; structural, so a surface's own task shape answers it too. */\nexport interface BlockingSubject {\n id: string;\n status: string;\n dependencies: readonly string[];\n subtasks?: readonly BlockingSubject[];\n}\n\n/** Statuses of a task that has not started, the only ones a block holds back. */\nconst UNSTARTED: ReadonlySet<string> = new Set(['pending', 'approved']);\n\n/**\n * The blocked rule (ADR-0034): a task not started yet is blocked while a\n * dependency failed or is itself blocked. One already at work — force-started,\n * or waiting on the user — is not, and does not pass a block on. Each\n * blocked task maps to the failed tasks it waits on, in dependency order and\n * named once; an unblocked task is absent. Nothing is stored, so a retry that\n * passes is all it takes to lift a block.\n *\n * Takes the plan tree or a flat list; a subtask follows the same rule.\n */\nexport function blockingFailures(tasks: readonly BlockingSubject[]): Map<string, string[]> {\n const byId = new Map<string, BlockingSubject>();\n const index = (list: readonly BlockingSubject[]): void => {\n for (const t of list) {\n byId.set(t.id, t);\n index(t.subtasks ?? []);\n }\n };\n index(tasks);\n\n const memo = new Map<string, string[]>();\n const failuresOf = (id: string, visiting: Set<string>): string[] => {\n const known = memo.get(id);\n if (known) return known;\n const task = byId.get(id);\n // A dependency cycle the planner left has no failure at its root.\n if (!task || !UNSTARTED.has(task.status) || visiting.has(id)) return [];\n visiting.add(id);\n const failed = new Set<string>();\n for (const depId of task.dependencies) {\n const dep = byId.get(depId);\n // A skipped dependency releases its dependents: nobody waits for it.\n if (!dep || dep.status === 'completed' || dep.status === 'skipped') continue;\n if (dep.status === 'failed') failed.add(depId);\n else for (const root of failuresOf(depId, visiting)) failed.add(root);\n }\n visiting.delete(id);\n const result = [...failed];\n memo.set(id, result);\n return result;\n };\n\n const blocked = new Map<string, string[]>();\n for (const id of byId.keys()) {\n const failures = failuresOf(id, new Set());\n if (failures.length > 0) blocked.set(id, failures);\n }\n return blocked;\n}\n","import type { AwaitingReason, ConversationMessage, LegacyPlanState, PlanState, PendingPlanTurn, ReplyRun, ResearchStep, RunnerId, RunSettings, SkillLoadNotice, SubagentOutcome, Task, TaskSkillNotice, TaskSnapshot, Verdict } from '../models/Task';\nimport type { AttemptUsage, ModelUsage, PlanUsage, UsageTotals } from '../models/Usage';\nimport type { ExecutionRecord } from '../models/Execution';\nimport type { TaskLogEvent } from '../models/TaskLog';\nimport type { ApprovalKind } from '../interfaces/IApproval';\nimport type { ApprovalSource } from './ApprovalPolicy';\nimport type { AutoMergeTrigger } from './TaskOrchestrator';\nimport type { IsolationHandoff, IsolationMergeResult, TaskIsolation } from '../interfaces/IWorktreeIsolation';\nimport type { QueuedTaskMessage } from '../interfaces/IRunner';\nimport { canContinue } from './continuation';\nimport { skillLoadNotice, surfaceStep } from '../conversation/records';\nimport { blockingFailures } from './blocking';\n\nexport type SerializedTaskStatus = {\n id: string;\n status: Task['status'];\n verdict: { outcome: 'pass' | 'fail'; reason: string; checks: Verdict['checks'] } | null;\n /** Advisory silence timestamp from VerdictEngine — not part of task status semantics. */\n idleSince?: string | null;\n /** Absent unless the plan has an isolation run, so a shared-root plan's updates are unchanged. */\n isolation?: TaskIsolation;\n /** What an `awaiting_user` task waits on, when it was saved (ADR-0018, W1). */\n awaitingReason?: AwaitingReason;\n /** When a task paused on a usage limit resumes on its own (ISO time); absent when it waits for a manual retry. */\n resumeAt?: string;\n /** Why a `skipped` task was skipped; absent when no reason was given, and on any other status. */\n skipReason?: string;\n /** The whole question of the checkpoint the task waits at; absent when it waits at none. */\n checkpoint?: string;\n /** Messages waiting for a structured task's turn to end, oldest first; absent when there are none. */\n queued?: QueuedTaskMessage[];\n /** Set when the task can be continued in its saved runner session (ADR-0018, K1); the id itself stays in the daemon. */\n continuable?: true;\n /**\n * How many of a structured task's runner requests wait for an answer\n * (ADR-0018, A1) — \"waiting for approval\", which leaves `status` alone.\n * Absent when none do.\n */\n awaitingApproval?: number;\n /**\n * The ancestors an ops or user task waits on at its merge gate: their\n * work has landed but is not merged into the user's branch (ADR-0020).\n * Absent when it waits for no Merge all.\n */\n mergeGate?: string[];\n /** The ancestors, by title, a force start went past the merge gate of (ADR-0020). */\n forcedPastGate?: string[];\n /**\n * Added after the user approved the plan and not approved since, so the\n * scheduler leaves it for them (ADR-0035). Absent for any other task.\n */\n waitsForApproval?: true;\n attemptUsage?: AttemptUsage[];\n};\n\n/**\n * Landed work not yet in the user's branch. `paused` means the running plan\n * waits at a merge gate with no attempts active.\n */\nexport interface RunMergeView {\n waitingAtGate: boolean;\n paused: boolean;\n repos: IsolationHandoff['repos'];\n landed: IsolationHandoff['landed'];\n}\n\nexport type SerializedTask = {\n id: string;\n order: number;\n title: string;\n type: string;\n /** Without it a plan broadcast after a run reads as every task pending. */\n status: Task['status'];\n description: string;\n dependencies: string[];\n assignedRunner: RunnerId;\n assignedModel: Task['assignedModel'] | null;\n taskMode: string;\n prompt: string | null;\n subtasks: SerializedTask[];\n userSteps: Task['userSteps'];\n autonomy: Task['autonomy'];\n sliceType: Task['sliceType'];\n userStoriesCovered: Task['userStoriesCovered'];\n /** As on {@link SerializedTaskStatus}: only while the task is `awaiting_user`. */\n awaitingReason?: AwaitingReason;\n resumeAt?: string;\n /** As on {@link SerializedTaskStatus}: only while the task is `skipped`. */\n skipReason?: string;\n /** Set only on an ops task (ADR-0020). */\n ops?: true;\n /** Task skills attached by name; absent when none. */\n skills?: string[];\n /** Set only on a task an Act supervisor added (ADR-0029). */\n addedBy?: 'supervisor';\n attemptUsage?: AttemptUsage[];\n};\n\n/** Skill loads go out as notices: their bodies are for the planner, and stay in the session. */\nexport type SerializedConversationMessage = Omit<ConversationMessage, 'skill'> & { skill?: SkillLoadNotice };\nexport type SerializedPendingTurn = Omit<PendingPlanTurn, 'skills'> & { skills?: SkillLoadNotice[] };\n\n/**\n * A task as a surface is sent it: its attempt's skills are notices, whole in\n * the session only, and its runner session id stays there too — no surface shows it,\n * and only a continue reads the runner's own session id.\n */\nexport type SurfaceTask<T extends Task = Task> = Omit<T, 'attemptSkills' | 'subtasks' | 'runnerSessionId'> & {\n attemptSkills?: TaskSkillNotice[];\n subtasks: SurfaceTask[];\n};\n\n/** A plan as the daemon and the VS Code webview are sent it: the session's own state, minus every skill body. */\nexport type SurfacePlan = Omit<LegacyPlanState, 'tasks' | 'conversationHistory' | 'pendingTurns' | 'queuedMessages'> & {\n tasks: SurfaceTask[];\n conversationHistory?: SerializedConversationMessage[];\n pendingTurns?: SerializedPendingTurn[];\n};\n\n/** The phase-tagged shape of {@link SurfacePlan}. */\nexport type SurfacePlanState =\n | (Omit<Extract<PlanState, { phase: 'planning' }>, 'pendingTasks'> & { pendingTasks: SurfaceTask[] })\n | (Omit<Extract<PlanState, { phase: 'executing' }>, 'pendingTasks' | 'executionLog'> & { pendingTasks: SurfaceTask[]; executionLog: SurfaceTask<TaskSnapshot>[] });\n\nexport type SerializedPlan = {\n runSettings?: LegacyPlanState['runSettings'];\n /** What waits on the planner's usage limit, and when it goes, so a surface can say so and offer to cancel it. */\n plannerResend?: LegacyPlanState['plannerResend'];\n tasks: SerializedTask[];\n runners: RunnerId[];\n generatedAt: string;\n conversationHistory?: SerializedConversationMessage[];\n prdMarkdown?: string;\n};\n\n/** What a held edit does to a task once it lands. */\nexport type HeldEditMark = 'added' | 'changed' | 'removed';\n\n/**\n * The plan as the open planner turn's edit would leave it, in plan order with\n * the removed tasks where they were; flat, a subtask after its parent. `label`\n * is the task's `#2.1` reference; `mark` is absent for a task the edit leaves\n * alone. Proposed, not approved: the tasks need the user's go-ahead to run.\n */\nexport interface HeldEdit {\n turnId: string;\n tasks: Array<{ label: string; mark?: HeldEditMark; task: SerializedTask }>;\n}\n\n/** How a planner turn ended: the reply kind it settled on, a user stop, or a failure. */\nexport type PlannerTurnOutcome = 'message' | 'plan' | 'task_ops' | 'stopped' | 'error';\n\n/**\n * Everything a session tells its surfaces, over one broadcast seam.\n *\n * A planner turn (#47) streams between `planner_turn_started` and\n * `planner_turn_ended` with the same `turnId`; every turn-scoped message in\n * between carries it. The stream is provisional and the settled messages are\n * authoritative:\n * - `planner_message` settles the streamed text of each run it carries in that\n * run's segment, where it streamed — a surface drops what it accumulated\n * there and shows the run's text instead.\n * - A reply that is a JSON envelope (plan, taskOps, taskQuery) never arrives\n * as `planner_text_delta`; it streams as `plan_token`, the \"building plan\"\n * display.\n * - A subagent's own text never appears in the reply; its activity arrives\n * tagged with its `subagentId`.\n */\nexport type SessionMessage =\n /**\n * The plan, whole. `turnId` names the planner turn whose commit this\n * broadcast carries, so the turn's building plan becomes the marker; it is\n * absent on every other broadcast of the plan.\n */\n | { type: 'plan_generated'; plan: SerializedPlan; goal: string; runners: RunnerId[]; turnId?: string }\n /**\n * The settled reply of a planner turn, emitted by the session once the turn\n * is classified. `turnId` is absent for replies sent outside a streamed turn.\n * `supervisor`: the supervisor said it in a wake-up turn (ADR-0029).\n * `runs`: what the reply shows, run by run, each authoritative over its\n * segment's `planner_text_delta`s; `content` stays the whole reply. Without\n * runs (a note the conversation wrote, an older daemon) the message is\n * authoritative over the turn's final segment.\n */\n | { type: 'planner_message'; content: string; timestamp: string; turnId?: string; supervisor?: true; runs?: ReplyRun[] }\n /**\n * A planner turn began. Emitted once per turn by whoever runs the turn,\n * before any other message carrying its `turnId`. `prompt` is the user's\n * message, as typed, when the turn answers one; `skills` are what its\n * `/name` tokens loaded, absent when none did. `wakeUps` are the wake-up\n * digests the turn delivers, shown ahead of the prompt; `supervisor` marks a\n * wake-up turn, which no user message opened (ADR-0029). `forced`: the\n * prompt was force sent, and this turn replaces the one it stopped.\n */\n | { type: 'planner_turn_started'; turnId: string; prompt?: string; skills?: SkillLoadNotice[]; wakeUps?: string[]; supervisor?: true; forced?: true }\n | { type: 'planner_skill_loaded'; turnId: string; skill: SkillLoadNotice }\n /**\n * What the open planner turn's task edit would leave, sent whenever the\n * edit it holds changes (ADR-0029: it lands as the reply ends). `held` is\n * null once nothing is held: the edit landed, was refused as it landed, or\n * the turn ended without it. The plan itself is untouched until it lands.\n */\n | { type: 'plan_edit_held'; held: HeldEdit | null }\n /**\n * A planner turn is over; nothing more carries its `turnId`. Emitted exactly\n * once per `planner_turn_started`, stop and failure included, after the\n * turn's `planner_message` when it has one. `forceSent`: a force send\n * stopped it, and the forced turn follows — the user did not stop the\n * conversation, so a surface keeps the prompts it holds (ADR-0023, F2).\n */\n | { type: 'planner_turn_ended'; turnId: string; outcome: PlannerTurnOutcome; forceSent?: true }\n /**\n * Reply prose as it streams, appended in order within its segment. A segment\n * is one continuous run of model text; text before a tool call is its own\n * segment, and a later segment never rewrites an earlier one. Never carries\n * a JSON envelope or a subagent's text (see the union's invariants).\n */\n | { type: 'planner_text_delta'; turnId: string; segmentId: string; text: string }\n /**\n * Exposed reasoning as it streams, from the planner or — tagged with\n * `subagentId` — from one of its subagents. Never part of the reply. The one\n * thinking message for every backend: `segmentId` is set only where the\n * backend streams thinking in segments (the API loops; harness planners do\n * not), and `turnId` is absent for thinking outside a turn (one-shot plans).\n */\n | { type: 'planner_thinking_delta'; turnId?: string; segmentId?: string; subagentId?: string; text: string }\n /**\n * Text streamed for an attempt the turn discarded (a corrective retry) is\n * taken back: a surface removes it. With `segmentId`, only that segment;\n * without, all of the turn's text not yet settled by a `planner_message`.\n * A segment that streamed to the plan display (`plan_token`) takes the\n * turn's building plan with it.\n */\n | { type: 'planner_text_retracted'; turnId: string; segmentId?: string }\n /**\n * The planner's running usage for the session, subagents included, emitted\n * after a model call reports usage. `totals` already contains every\n * `bySubagent` entry. `contextFill` is the last planner prompt against the\n * model's window, omitted when the window is unknown. Cost appears only as\n * reported by a provider or runner (see `UsageRecord`).\n */\n | {\n type: 'planner_usage';\n byModel?: ModelUsage[];\n model?: string;\n turnId?: string;\n totals: UsageTotals;\n bySubagent?: Record<string, UsageTotals>;\n contextFill?: { usedTokens: number; windowTokens: number };\n }\n /**\n * A subagent began work on `brief`. Emitted by the planner backend that\n * spawned it (ADR-0005 research agents, or a harness planner's own), before\n * any message tagged with its `subagentId`.\n */\n | { type: 'subagent_started'; turnId?: string; subagentId: string; brief: string; model?: string }\n /**\n * A subagent is done; nothing more is tagged with its `subagentId`. Emitted\n * once per `subagent_started`. `digest` is what it handed back to the\n * planner; `usage` is its own share, already counted in `planner_usage`.\n */\n | { type: 'subagent_finished'; turnId?: string; subagentId: string; outcome: SubagentOutcome; digest: string; usage?: UsageTotals }\n | { type: 'status_update'; tasks: SerializedTaskStatus[]; runMerge?: RunMergeView; usage?: PlanUsage }\n | { type: 'review_needed'; tasks: SerializedTask[] }\n | { type: 'review_approved' }\n | { type: 'checkpoint'; taskId: string; taskTitle: string; summary: string }\n | { type: 'execution_complete'; summary: ExecutionSummary }\n | { type: 'execution_stopped' }\n // A call at the command seam (ADR-0029), with who made it: `text` is the\n // line the transcript keeps for it, so a reload shows what was shown live.\n | { type: 'execution_action'; record: ExecutionRecord; text: string }\n | { type: 'task_updated'; taskId: string; changes: Record<string, unknown> }\n | { type: 'task_started'; taskId: string; order: number; title: string; runner: RunnerId; modelId?: string }\n | { type: 'task_output'; taskId: string; text: string }\n /**\n * A structured task's log as it happens (ADR-0018, P1): the next events of\n * the task's attempt `attempt`, in order — the same ones appended to that\n * attempt's file, so a surface folding these and one replaying the file\n * draw the same blocks.\n */\n | { type: 'task_log'; taskId: string; attempt: number; events: TaskLogEvent[] }\n // A run did not start because tracked files are modified. It waits for the\n // user to stash (`continueWithStash`) or to run without isolation this once\n // (`continueWithoutIsolation`); nothing is spawned until then. `repos` names\n // the dirty repos of a group; a group of one names none.\n | { type: 'isolation_blocked'; reason: 'dirty'; repos?: string[]; message: string }\n // An isolated run settled: for each repo, the branch its work landed on and\n // the commit that branch forked from; and what landed, in plan order. Sent\n // before `execution_complete`, which surfaces treat as the end of the stream.\n // `deferredTo`: an Act supervisor handles it first; the unmarked handoff\n // that follows its wake-up turn, if the run is still unmerged, comes after.\n | { type: 'isolation_handoff'; repos: IsolationHandoff['repos']; landed: IsolationHandoff['landed']; deferredTo?: IsolationHandoff['deferredTo'] }\n // What \"Merge all\" did, for every surface watching rather than only the one\n // that asked: merged, blocked with each repo and why, or stopped part-way\n // with the repos that stay merged. `trigger`: Ordewell ran it by itself,\n // at a merge gate or at the run's end, with merge at gates automatically on.\n | { type: 'isolation_merge'; result: IsolationMergeResult; trigger?: AutoMergeTrigger }\n // The Session cleared the isolated run up and forgot it: a Merge all that\n // left nothing to hand over, or a discard. Sent after the `isolation_merge`\n // that caused it, and never for a merge that leaves the run going. The one\n // word on it: a surface folds this rather than guessing from a merge result.\n | { type: 'run_closed' }\n // Carries no content — see `ResearchProgress['liveness']`. Exists only so a\n // surface's idle watchdog sees the harness process working even during a\n // stretch that produces nothing visible.\n | { type: 'planner_liveness' }\n // `toolLabel` carries a harness planner's own name for the tool (ADR-0009) —\n // always set when `tool` is `agent_tool`, so no surface has to render the\n // catch-all member name at the user.\n | { type: 'research_step'; tool: string; toolLabel?: string; args: string; subagentId?: string; toolCallId?: string; turnId?: string }\n // The \"building plan\" display only: a JSON envelope as it streams, never\n // reply prose. `turnId` is absent for a one-shot plan, which has no turn.\n // `segmentId` names the segment the envelope streams in; a turn's next\n // envelope is a new segment, and the display starts over with it.\n | { type: 'plan_token'; token: string; turnId?: string; segmentId?: string }\n | { type: 'research_step_done'; step: ResearchStep; subagentId?: string; turnId?: string }\n // Planner research wants something outside its default envelope and is\n // blocked until a human answers. Broadcast rather than returned, because the\n // human may be on any surface (or several at once) and the request outlives\n // whichever HTTP call triggered it.\n | { type: 'approval_request'; id: string; kind: ApprovalKind; subject: string; scope: string; detail?: string; turnId?: string }\n | { type: 'approval_settled'; id: string; granted: boolean }\n // A decision reached with no round-trip prompt: pre-approved via config,\n // remembered from earlier in this session, or the operator's mode floor\n // (allow/deny skipping the human entirely). The interactive path above\n // already has full visibility via approval_request/approval_settled; this\n // is the one that previously had none — a model silently auto-running\n // `npm test` because the scope was already granted looked identical, from\n // every UI, to it never having been asked in the first place.\n | {\n type: 'approval_decided';\n kind: ApprovalKind;\n subject: string;\n scope: string;\n detail?: string;\n granted: boolean;\n source: Exclude<ApprovalSource, 'asked'>;\n };\n\n/**\n * A plan a surface read whole rather than off the message stream: a route's\n * answer, a loaded session. Folds into a {@link RunView} as a plan refresh.\n */\nexport type PlanSnapshot = { type: 'plan_snapshot'; plan: SurfacePlan | SurfacePlanState };\n\n/** What only the status stream says about a task; a plan refresh keeps these as they were. */\nexport type RunTaskStatus = Partial<Pick<\n SerializedTaskStatus,\n 'verdict' | 'idleSince' | 'isolation' | 'checkpoint' | 'queued' | 'continuable' | 'awaitingApproval' | 'mergeGate' | 'forcedPastGate' | 'waitsForApproval'\n>>;\n\n/** A task in the run view: the plan's fields, then the status stream's. */\nexport type RunTask = Omit<SerializedTask, 'subtasks'> & RunTaskStatus & { subtasks: RunTask[] };\n\n/**\n * A session's run as every surface draws it (the [run view](../../../../CONTEXT.md)):\n * folded from {@link SessionMessage}s and plan snapshots by `reduceRun`, or\n * taken whole from `Session.runSnapshot()` by a surface that joins late.\n */\nexport interface RunView {\n /** In plan order, subtasks nested under their parent. */\n tasks: RunTask[];\n runSettings?: RunSettings;\n runMerge: RunMergeView | null;\n usage?: PlanUsage;\n handoff: IsolationHandoff | null;\n mergeResult: IsolationMergeResult | null;\n /** The edit the open planner turn holds, as it would leave the plan; absent when it holds none. */\n heldEdit?: HeldEdit;\n}\n\nexport type RunInput = SessionMessage | PlanSnapshot;\n\n/**\n * A line a run wants the user to read — how it isolates, what it shares. Not a\n * {@link SessionMessage}: hosts that show notices as toasts already do, and\n * widening the union would break every exhaustive switch over it. A host with\n * no toast channel (the daemon) hands these to its clients by its own means.\n */\nexport type SessionNotice = { type: 'notice'; level: 'info' | 'warn' | 'error'; message: string };\n\nexport type SessionBroadcaster = (msg: SessionMessage) => void;\n\nexport function serializeTask(t: SurfaceTask): SerializedTask {\n return {\n id: t.id,\n order: t.order,\n title: t.title,\n type: t.type,\n status: t.status,\n description: t.description,\n dependencies: t.dependencies || [],\n assignedRunner: t.assignedRunner,\n assignedModel: t.assignedModel || null,\n taskMode: t.taskMode || 'build',\n prompt: t.prompt || null,\n subtasks: (t.subtasks || []).map(serializeTask),\n userSteps: t.userSteps || undefined,\n autonomy: t.autonomy || undefined,\n sliceType: t.sliceType || undefined,\n userStoriesCovered: t.userStoriesCovered || undefined,\n ...(t.status === 'awaiting_user' && t.awaitingReason ? { awaitingReason: t.awaitingReason } : {}),\n ...(t.status === 'awaiting_user' && t.awaitingReason === 'usage-limit' && t.resumeAt ? { resumeAt: t.resumeAt } : {}),\n ...(t.status === 'skipped' && t.skipReason ? { skipReason: t.skipReason } : {}),\n ...(t.ops ? { ops: true as const } : {}),\n ...(t.attemptUsage ? { attemptUsage: structuredClone(t.attemptUsage) } : {}),\n ...(t.skills?.length ? { skills: [...t.skills] } : {}),\n ...(t.addedBy ? { addedBy: t.addedBy } : {}),\n };\n}\n\nexport function serializeTaskStatus(\n t: Task,\n idleSince: string | null = null,\n isolation: TaskIsolation | null = null,\n queued: readonly QueuedTaskMessage[] = [],\n awaitingApproval = 0,\n mergeGate: readonly string[] = [],\n checkpoint = '',\n waitsForApproval = false,\n): SerializedTaskStatus {\n return {\n id: t.id,\n status: t.status,\n verdict: t.verdict\n ? { outcome: t.verdict.outcome, reason: t.verdict.reason, checks: t.verdict.checks || [] }\n : null,\n idleSince,\n ...(t.attemptUsage ? { attemptUsage: structuredClone(t.attemptUsage) } : {}),\n ...(isolation ? { isolation } : {}),\n ...(t.status === 'awaiting_user' && t.awaitingReason ? { awaitingReason: t.awaitingReason } : {}),\n ...(t.status === 'awaiting_user' && t.awaitingReason === 'usage-limit' && t.resumeAt ? { resumeAt: t.resumeAt } : {}),\n ...(t.status === 'awaiting_user' && t.awaitingReason === 'checkpoint' && checkpoint ? { checkpoint } : {}),\n ...(t.status === 'skipped' && t.skipReason ? { skipReason: t.skipReason } : {}),\n ...(queued.length > 0 ? { queued: queued.map((m) => ({ ...m })) } : {}),\n ...(canContinue(t) ? { continuable: true as const } : {}),\n ...(awaitingApproval > 0 ? { awaitingApproval } : {}),\n ...(mergeGate.length > 0 ? { mergeGate: [...mergeGate] } : {}),\n ...(t.forcedPastGate?.length ? { forcedPastGate: [...t.forcedPastGate] } : {}),\n ...(waitsForApproval ? { waitsForApproval: true as const } : {}),\n };\n}\n\nfunction surfaceConversation(history: LegacyPlanState['conversationHistory']): SerializedConversationMessage[] | undefined {\n return history?.map(({ skill, ...m }) => (skill ? { ...m, skill: skillLoadNotice(skill) } : m));\n}\n\nfunction surfacePendingTurns(pending: LegacyPlanState['pendingTurns']): SerializedPendingTurn[] | undefined {\n return pending?.map(({ skills, ...t }) => (skills ? { ...t, skills: skills.map(skillLoadNotice) } : t));\n}\n\nexport function surfaceTask<T extends Task>({ attemptSkills, subtasks, runnerSessionId: _runnerSessionId, ...task }: T): SurfaceTask<T> {\n return {\n ...task,\n ...(attemptSkills ? { attemptSkills: attemptSkills.map(({ name, source, path }): TaskSkillNotice => ({ name, source, path })) } : {}),\n subtasks: (subtasks ?? []).map(surfaceTask),\n };\n}\n\n/** The one place a plan's skill bodies come off before it leaves the session: every wire path that carries plan state goes through here. */\nexport function surfacePlan({ queuedMessages: _carriedOverAtLoad, ...plan }: LegacyPlanState): SurfacePlan {\n return {\n ...plan,\n tasks: plan.tasks.map(surfaceTask),\n conversationHistory: surfaceConversation(plan.conversationHistory),\n pendingTurns: surfacePendingTurns(plan.pendingTurns),\n researchLog: plan.researchLog?.map((e) => ('type' in e ? e : surfaceStep(e))),\n };\n}\n\nexport function surfacePlanState(state: PlanState): SurfacePlanState {\n return state.phase === 'planning'\n ? { ...state, pendingTasks: state.pendingTasks.map(surfaceTask) }\n : { ...state, pendingTasks: state.pendingTasks.map(surfaceTask), executionLog: state.executionLog.map(surfaceTask) };\n}\n\nexport function serializePlan(plan: LegacyPlanState): SerializedPlan {\n return {\n tasks: plan.tasks.map(serializeTask),\n runners: plan.runners,\n generatedAt: plan.generatedAt,\n runSettings: plan.runSettings,\n ...(plan.plannerResend ? { plannerResend: plan.plannerResend } : {}),\n conversationHistory: surfaceConversation(plan.conversationHistory),\n prdMarkdown: plan.prdMarkdown,\n };\n}\n\n/**\n * What a finished run did, task by task: `blocked` are those a failure kept\n * from starting (ADR-0034); `skipped` ended without a verdict and landed\n * nothing, so they are neither completed nor failed.\n */\nexport interface ExecutionSummary {\n total: number;\n completed: number;\n failed: number;\n blocked: number;\n skipped: number;\n}\n\nexport function executionSummary(tasks: readonly Task[]): ExecutionSummary {\n const blocked = blockingFailures(tasks);\n return {\n total: tasks.length,\n completed: tasks.filter((t) => t.status === 'completed').length,\n failed: tasks.filter((t) => t.status === 'failed').length,\n blocked: tasks.filter((t) => blocked.has(t.id)).length,\n skipped: tasks.filter((t) => t.status === 'skipped').length,\n };\n}\n\nexport const CHECKPOINT_TRUNCATE_LENGTH = 120;\n\n/** Truncate a checkpoint summary to a single line of at most CHECKPOINT_TRUNCATE_LENGTH chars. */\nexport function truncateCheckpointSummary(summary: string): string {\n // Take the first line only (checkpoint summaries often contain reasoning across lines)\n const firstLine = summary.split('\\n')[0].trim();\n if (firstLine.length <= CHECKPOINT_TRUNCATE_LENGTH) return firstLine;\n return firstLine.slice(0, CHECKPOINT_TRUNCATE_LENGTH - 1) + '…';\n}\n","/**\n * Pure, no-imports helper so a browser surface can format a conflict's files\n * without pulling `isolationRecord` — and its `path` import — into a webview\n * bundle. Kept out of `isolationRecord.ts` for exactly that reason.\n */\nexport function capConflictFiles(files: string[], max = 5): string {\n return files.length <= max ? files.join(', ') : `${files.slice(0, max).join(', ')}, +${files.length - max} more`;\n}\n","import type { SupervisorLevel } from '../models/Execution';\nimport type { GlobalRunSettings } from './SettingsService';\n\n/** How every surface words the run settings (ADR-0030), so they all say the same thing. */\n\nexport const SUPERVISOR_LEVEL_LABEL: Record<SupervisorLevel, string> = { off: 'Off', watch: 'Watch', act: 'Act' };\n\nconst plural = (n: number, one: string, many: string): string => `${n} ${n === 1 ? one : many}`;\nconst onOff = (value: boolean): string => (value ? 'on' : 'off');\n\nexport const supervisorSummary = (run: GlobalRunSettings): string =>\n `Supervisor: ${SUPERVISOR_LEVEL_LABEL[run.supervisorLevel]}, ${plural(run.supervisorRetryLimit, 'retry', 'retries')} per task, ${plural(run.wakeUpReadBudget, 'read', 'reads')} per wake-up`;\nexport const automergeSummary = (run: GlobalRunSettings): string => `Merge automatically (gates, end of run): ${onOff(run.mergeAtGatesAutomatically)}`;\nexport const autorunSummary = (run: GlobalRunSettings): string => `Autorun: ${onOff(run.autorun)}`;\n\nexport const ACT_RISK = 'Tasks it adds run too, ops tasks included, which can act on real systems unattended.';\nexport const AUTORUN_RISK = 'Plans start without review, ops tasks included, which can act on real systems unattended. In Full, the planner may also start tasks it adds later.';\n\n/** `on`/`off` as a switch's value; null for anything else. */\nexport function parseSwitch(arg: string): boolean | null {\n return arg === 'on' ? true : arg === 'off' ? false : null;\n}\n\n/** A whole number at least `min`, as typed; null for anything else. */\nexport function parseCount(arg: string | undefined, min: number): number | null {\n if (arg === undefined || !/^\\d+$/.test(arg)) return null;\n const n = Number(arg);\n return n >= min ? n : null;\n}\n","/**\n * What one model call consumed, as its provider or runner reported it. Shared\n * by the planner's usage line (#49) and per-attempt task usage (#26): a record\n * says nothing about who asked for the call, so either can hold a list of them.\n *\n * Every measure is optional because backends report different subsets. An\n * absent field means \"not reported\" — never zero — so a total can tell the two\n * apart.\n */\nexport interface UsageRecord {\n /** The provider or runner id that reported the call — `openai`, `claude-code`, … */\n source: string;\n model?: string;\n /** A session breakdown can name a model without identifying the current context. */\n aggregate?: true;\n inputTokens?: number;\n outputTokens?: number;\n /** The share of `inputTokens` served from the provider's prompt cache. */\n cachedInputTokens?: number;\n /**\n * Filled only from a provider's or runner's own report, never from a price\n * table or an estimate: prices go stale, and a subscription runner has no\n * per-token price at all. No report means no cost, not a guessed one.\n */\n reportedCost?: { amount: number; currency: string };\n /**\n * The model's context window: as the runner or provider reported it, or,\n * when it reported none, from that runner's or provider's own model listing\n * (`ContextWindowFill`). Never from a table kept in Ordewell.\n */\n contextWindow?: number;\n /** Set when a subagent made the call; its usage still counts toward the total. */\n subagentId?: string;\n}\n\n/**\n * A running sum of {@link UsageRecord}s. A measure stays absent until some\n * record reports it. Cost is kept per currency: two runners may bill in\n * different ones, and there is no honest exchange rate to fold them together.\n */\nexport interface UsageTotals {\n inputTokens?: number;\n outputTokens?: number;\n cachedInputTokens?: number;\n reportedCost?: Record<string, number>;\n}\n\n/**\n * The input side of a call whose provider reports its prompt in parts — the\n * uncached tail, with cache reads and cache writes beside it rather than inside\n * it (Anthropic, and OpenCode after it). The prompt the model saw is all three;\n * only the reads were served from cache, since a write is billed as fresh\n * input. A part left unreported adds nothing, and with no part reported there\n * is no measure at all.\n */\nexport function partedPromptUsage(parts: { uncached?: number; cacheRead?: number; cacheWrite?: number }): Pick<UsageRecord, 'inputTokens' | 'cachedInputTokens'> {\n const reported = [parts.uncached, parts.cacheRead, parts.cacheWrite].filter((n): n is number => n !== undefined);\n return {\n ...(reported.length > 0 ? { inputTokens: reported.reduce((a, b) => a + b, 0) } : {}),\n ...(parts.cacheRead !== undefined ? { cachedInputTokens: parts.cacheRead } : {}),\n };\n}\n\nconst TOKEN_FIELDS = ['inputTokens', 'outputTokens', 'cachedInputTokens'] as const;\n\nexport function addUsage(totals: UsageTotals, record: UsageRecord): UsageTotals {\n const next: UsageTotals = { ...totals };\n for (const field of TOKEN_FIELDS) {\n const reported = record[field];\n if (reported !== undefined) next[field] = (totals[field] ?? 0) + reported;\n }\n if (record.reportedCost) {\n const { amount, currency } = record.reportedCost;\n next.reportedCost = { ...totals.reportedCost, [currency]: (totals.reportedCost?.[currency] ?? 0) + amount };\n }\n return next;\n}\n\n/**\n * What the planner has consumed over a session (#49). `totals` includes every\n * `bySubagent` entry. `lastPromptTokens` and `contextWindow` track the\n * planner's own calls only — a subagent runs its own model, whose window says\n * nothing about the planner's.\n */\nexport interface PlannerUsage {\n totals: UsageTotals;\n bySubagent?: Record<string, UsageTotals>;\n byModel?: ModelUsage[];\n source?: string;\n model?: string;\n lastPromptTokens?: number;\n contextWindow?: number;\n}\n\nexport function addPlannerUsage(usage: PlannerUsage, record: UsageRecord): PlannerUsage {\n const next: PlannerUsage = { ...usage, totals: addUsage(usage.totals, record), byModel: addModelUsage(usage.byModel ?? [], record) };\n if (record.subagentId) {\n next.bySubagent = { ...usage.bySubagent, [record.subagentId]: addUsage(usage.bySubagent?.[record.subagentId] ?? {}, record) };\n return next;\n }\n if (!record.aggregate) {\n if (record.source !== usage.source || record.model !== usage.model) {\n delete next.lastPromptTokens;\n delete next.contextWindow;\n }\n next.source = record.source;\n next.model = record.model;\n }\n if (record.inputTokens !== undefined) next.lastPromptTokens = record.inputTokens;\n // A reported window of 0 means \"not known\", not \"no room\": keep it out so the\n // fill is omitted rather than shown against a guessed zero.\n if (record.contextWindow !== undefined) next.contextWindow = record.contextWindow > 0 ? record.contextWindow : undefined;\n return next;\n}\n\n/** Whether any measure was reported: a token line of nothing but blanks says nothing. */\nexport function isMeasured(totals: UsageTotals): boolean {\n return totals.inputTokens !== undefined || totals.outputTokens !== undefined || totals.cachedInputTokens !== undefined\n || Object.keys(totals.reportedCost ?? {}).length > 0;\n}\n\n/** What the token line shows of a ledger — live from its broadcast, or reloaded from the saved one. */\nexport interface UsageLine {\n byModel?: ModelUsage[];\n model?: string;\n totals: UsageTotals;\n bySubagent?: Record<string, UsageTotals>;\n contextFill?: { usedTokens: number; windowTokens: number };\n}\n\nexport function usageLine(usage: PlannerUsage): UsageLine {\n const contextFill = plannerContextFill(usage);\n return {\n totals: usage.totals,\n ...(usage.byModel ? { byModel: usage.byModel } : {}),\n ...(usage.model ? { model: usage.model } : {}),\n ...(usage.bySubagent ? { bySubagent: usage.bySubagent } : {}),\n ...(contextFill ? { contextFill } : {}),\n };\n}\n\n/**\n * The last planner prompt against its window, or undefined while either is\n * unknown. `usedTokens` is the prompt total as reported, cached tokens\n * included: a cached token still occupies the window, so subtracting the\n * cached share would understate how full the context is. A window of 0 is\n * treated as unknown — never guessed.\n */\nexport function plannerContextFill(usage: PlannerUsage): { usedTokens: number; windowTokens: number } | undefined {\n if (usage.lastPromptTokens === undefined || usage.contextWindow === undefined || usage.contextWindow <= 0) return undefined;\n return { usedTokens: usage.lastPromptTokens, windowTokens: usage.contextWindow };\n}\n\nexport interface ModelUsage {\n source: string;\n model?: string;\n totals: UsageTotals;\n}\n\nexport function addModelUsage(models: readonly ModelUsage[], record: UsageRecord): ModelUsage[] {\n const index = models.findIndex((m) => m.source === record.source && m.model === record.model);\n if (index < 0) return [...models, { source: record.source, ...(record.model ? { model: record.model } : {}), totals: addUsage({}, record) }];\n return models.map((m, i) => i === index ? { ...m, totals: addUsage(m.totals, record) } : m);\n}\n\n/**\n * What Ordewell has counted of a runner's own session that reports its cost\n * as a running total: that total and each model's share, in USD, as of its\n * last report. A resume of that session counts its first report's growth\n * over this; with no count kept for it, that report only sets the baseline.\n */\nexport interface RunnerSessionCost {\n sessionId: string;\n usd: number;\n modelUsd: Record<string, number>;\n}\n\nexport interface AttemptUsage extends PlannerUsage {\n attempt: number;\n runner: string;\n /** The runner session this attempt ran in, as its runner reported it: what a later Continue of it resumes. */\n sessionId?: string;\n startedAt: string;\n endedAt?: string;\n wallTimeMs: number;\n /** What was counted of its runner session's running cost as it ended: a continue of that session counts on from it. */\n runnerSessionCost?: RunnerSessionCost;\n}\n\nexport function startAttemptUsage(attempt: number, runner: string, startedAt: string): AttemptUsage {\n return { attempt, runner, startedAt, wallTimeMs: 0, totals: {}, byModel: [] };\n}\n\nexport function addAttemptUsage(usage: AttemptUsage, record: UsageRecord, now: string): AttemptUsage {\n const folded = addPlannerUsage(usage, record);\n return { ...usage, ...folded, lastPromptTokens: folded.lastPromptTokens, contextWindow: folded.contextWindow, wallTimeMs: Math.max(0, Date.parse(now) - Date.parse(usage.startedAt)) };\n}\n\nexport function endAttemptUsage(usage: AttemptUsage, now: string, runnerSessionCost?: RunnerSessionCost, sessionId?: string): AttemptUsage {\n return {\n ...usage,\n endedAt: now,\n wallTimeMs: Math.max(0, Date.parse(now) - Date.parse(usage.startedAt)),\n ...(sessionId ? { sessionId } : {}),\n ...(runnerSessionCost ? { runnerSessionCost } : {}),\n };\n}\n\n/** The count a continue of `sessionId` starts from: the one its latest attempt in that session ended with. */\nexport function countedSessionCost(attempts: readonly AttemptUsage[] | undefined, sessionId: string): RunnerSessionCost | undefined {\n return [...attempts ?? []].reverse().find((usage) => usage.runnerSessionCost?.sessionId === sessionId)?.runnerSessionCost;\n}\n\n/**\n * The model a continue's session last ran on and the window it was measured\n * against: the latest earlier attempt of that same runner session that\n * reported one. An attempt that measured nothing is skipped — a continuation\n * does not undo what its session was last measured against — and a window is\n * never borrowed from another session: a fresh attempt starts one.\n */\nexport function resumedSessionWindow(attempts: readonly AttemptUsage[] | undefined, runner: string, attempt: number, sessionId: string): Pick<PlannerUsage, 'source' | 'model' | 'contextWindow'> | undefined {\n const last = [...attempts ?? []].reverse().find((usage) => usage.attempt !== attempt && usage.runner === runner && usage.sessionId === sessionId && usage.contextWindow !== undefined);\n return last ? { source: last.source, model: last.model, contextWindow: last.contextWindow } : undefined;\n}\n\nexport interface PlanUsage {\n totals: UsageTotals;\n byModel: ModelUsage[];\n wallTimeMs: number;\n attempts: number;\n}\n\nexport function addUsageTotals(totals: UsageTotals, addition: UsageTotals): UsageTotals {\n let next = addUsage(totals, { source: '', inputTokens: addition.inputTokens, outputTokens: addition.outputTokens, cachedInputTokens: addition.cachedInputTokens });\n for (const [currency, amount] of Object.entries(addition.reportedCost ?? {})) next = addUsage(next, { source: '', reportedCost: { currency, amount } });\n return next;\n}\n\ninterface UsageTask { attemptUsage?: readonly AttemptUsage[]; subtasks?: readonly UsageTask[] }\n\nexport function planUsage(tasks: readonly UsageTask[]): PlanUsage {\n const result: PlanUsage = { totals: {}, byModel: [], wallTimeMs: 0, attempts: 0 };\n for (const task of tasks) {\n const child = planUsage(task.subtasks ?? []);\n result.totals = addUsageTotals(result.totals, child.totals);\n result.wallTimeMs += child.wallTimeMs;\n result.attempts += child.attempts;\n const models = [...child.byModel];\n for (const usage of task.attemptUsage ?? []) {\n result.totals = addUsageTotals(result.totals, usage.totals);\n result.wallTimeMs += usage.wallTimeMs;\n result.attempts++;\n models.push(...usage.byModel ?? []);\n }\n for (const model of models) {\n const existing = result.byModel.find((m) => m.source === model.source && m.model === model.model);\n if (existing) existing.totals = addUsageTotals(existing.totals, model.totals);\n else result.byModel.push({ ...model, totals: addUsageTotals({}, model.totals) });\n }\n }\n return result;\n}\n\n/**\n * What one task spent across every attempt and every model it ran on, so a\n * stop, a model change and a continue never makes the earlier spend vanish. The\n * context meter is the exception: it reads the latest attempt, because only the\n * current model's window says how full the next prompt is.\n */\nexport interface TaskUsageSummary {\n totals: UsageTotals;\n attempts: number;\n contextFill?: { usedTokens: number; windowTokens: number };\n}\n\nexport function taskUsageSummary(task: Pick<UsageTask, 'attemptUsage'>): TaskUsageSummary {\n const attempts = task.attemptUsage ?? [];\n const latest = attempts.at(-1);\n const contextFill = latest ? plannerContextFill(latest) : undefined;\n return {\n totals: attempts.reduce((sum, attempt) => addUsageTotals(sum, attempt.totals), {} as UsageTotals),\n attempts: attempts.length,\n ...(contextFill ? { contextFill } : {}),\n };\n}\n","import type { UsageLine } from '../models/Usage';\nimport type { DisplayBlock, SubagentBlock, SubagentChild, SubagentStatus } from './blocks';\nimport { subagentBlock, usageBlock } from './records';\n\n/*\n * The block-list operations both reducers are built from — the planner\n * conversation (`reduce.ts`) and a structured task's log (`taskLog.ts`) — so\n * a subagent, a streaming run of text or the usage line behaves the same in\n * either view.\n */\n\n/** What every view over display blocks holds; each view adds its own state beside it. */\nexport interface BlockList {\n readonly blocks: readonly DisplayBlock[];\n readonly nextId: number;\n}\n\n/** The top level of the view (`null`), or the index of the subagent whose children are meant. */\nexport type Lane = number | null;\n\nexport function findLastIndex<T>(items: readonly T[], match: (item: T) => boolean): number {\n for (let i = items.length - 1; i >= 0; i--) if (match(items[i])) return i;\n return -1;\n}\n\nexport function replaceAt<T>(items: readonly T[], index: number, item: T): T[] {\n const next = items.slice();\n next[index] = item;\n return next;\n}\n\n// The usage line always sits last, so everything else lands above it.\nfunction insertTop(blocks: readonly DisplayBlock[], block: DisplayBlock): DisplayBlock[] {\n const last = blocks[blocks.length - 1];\n return last?.type === 'usage' ? [...blocks.slice(0, -1), block, last] : [...blocks, block];\n}\n\nexport function append<V extends BlockList>(view: V, make: (id: string) => DisplayBlock): V {\n return { ...view, blocks: insertTop(view.blocks, make(`b${view.nextId}`)), nextId: view.nextId + 1 };\n}\n\nexport function subagentAt(view: BlockList, lane: number): SubagentBlock {\n const block = view.blocks[lane];\n if (block.type !== 'subagent') throw new Error(`block ${lane} is not a subagent`);\n return block;\n}\n\nexport function laneBlocks(view: BlockList, lane: Lane): readonly DisplayBlock[] {\n return lane === null ? view.blocks : subagentAt(view, lane).children;\n}\n\nfunction setChildren<V extends BlockList>(view: V, lane: number, children: readonly SubagentChild[]): V {\n return { ...view, blocks: replaceAt(view.blocks, lane, { ...subagentAt(view, lane), children }) };\n}\n\nexport function laneReplace<V extends BlockList>(view: V, lane: Lane, index: number, block: SubagentChild): V {\n if (lane === null) return { ...view, blocks: replaceAt(view.blocks, index, block) };\n return setChildren(view, lane, replaceAt(subagentAt(view, lane).children, index, block));\n}\n\nexport function laneAppend<V extends BlockList>(view: V, lane: Lane, make: (id: string) => SubagentChild): V {\n if (lane === null) return append(view, make);\n const children = [...subagentAt(view, lane).children, make(`b${view.nextId}`)];\n return { ...setChildren(view, lane, children), nextId: view.nextId + 1 };\n}\n\nfunction isStreaming(block: DisplayBlock): boolean {\n return (block.type === 'message' || block.type === 'thinking') && block.streaming;\n}\n\nexport function sealed<B extends DisplayBlock>(block: B): B {\n return isStreaming(block) ? { ...block, streaming: false } : block;\n}\n\n/**\n * Output landed at `keep` in the lane, so nothing else there is still\n * streaming: one lane has one voice at a time, and a block left marked as\n * streaming would keep its cursor after its text had moved on.\n */\nexport function sealLane<V extends BlockList>(view: V, lane: Lane, keep: number): V {\n const blocks = laneBlocks(view, lane);\n if (!blocks.some((b, i) => i !== keep && isStreaming(b))) return view;\n if (lane === null) return { ...view, blocks: view.blocks.map((b, i) => (i === keep ? b : sealed(b))) };\n return setChildren(view, lane, subagentAt(view, lane).children.map((b, i) => (i === keep ? b : sealed(b))));\n}\n\n/** Append output to the lane, which then speaks through it alone. */\nexport function appendOutput<V extends BlockList>(view: V, lane: Lane, make: (id: string) => SubagentChild): V {\n const next = laneAppend(view, lane, make);\n return sealLane(next, lane, findLastIndex(laneBlocks(next, lane), (b) => b.type !== 'usage'));\n}\n\n/**\n * The subagent's block, created on first sighting: its activity can arrive\n * before (or without) its start. The call that spawns it becomes the block,\n * keeping the call's id and position — the call and the subagent are one\n * thing on screen.\n */\nexport function subagentLane<V extends BlockList>(view: V, subagentId: string, turnId?: string): [V, number] {\n const existing = findLastIndex(view.blocks, (b) => b.type === 'subagent' && b.subagentId === subagentId);\n if (existing >= 0) return [view, existing];\n const spawn = findLastIndex(view.blocks, (b) => b.type === 'tool' && (b.spawns === subagentId || b.toolCallId === subagentId));\n const call = view.blocks[spawn];\n if (call?.type === 'tool') {\n const block = subagentBlock(call.id, {\n subagentId, brief: call.headline.keyArg, status: 'running', children: [], digest: '', toolCallId: call.toolCallId, turnId: call.turnId,\n });\n return [{ ...view, blocks: replaceAt(view.blocks, spawn, block) }, spawn];\n }\n const next = append(view, (id) => subagentBlock(id, { subagentId, brief: '', status: 'running', children: [], digest: '', turnId }));\n return [next, findLastIndex(next.blocks, (b) => b.type === 'subagent' && b.subagentId === subagentId)];\n}\n\nexport function updateSubagent<V extends BlockList>(view: V, subagentId: string, turnId: string | undefined, update: (block: SubagentBlock) => SubagentBlock): V {\n const [next, lane] = subagentLane(view, subagentId, turnId);\n return { ...next, blocks: replaceAt(next.blocks, lane, update(subagentAt(next, lane))) };\n}\n\n/** The lane a subagent's activity lands in: its own block's children, or the top level. */\nexport function laneOf<V extends BlockList>(view: V, subagentId: string | undefined, turnId?: string): [V, Lane] {\n return subagentId ? subagentLane(view, subagentId, turnId) : [view, null];\n}\n\nexport function think<V extends BlockList>(view: V, text: string, turnId?: string, segmentId?: string, subagentId?: string): V {\n const [placed, lane] = laneOf(view, subagentId, turnId);\n const blocks = laneBlocks(placed, lane);\n const lastIndex = findLastIndex(blocks, (b) => b.type !== 'usage');\n const last = blocks[lastIndex];\n if (last?.type === 'thinking' && last.streaming && last.segmentId === segmentId) {\n return laneReplace(placed, lane, lastIndex, { ...last, text: last.text + text });\n }\n return appendOutput(placed, lane, (id) => ({\n type: 'thinking', id, text, streaming: true,\n ...(turnId ? { turnId } : {}),\n ...(segmentId ? { segmentId } : {}),\n ...(subagentId ? { subagentId } : {}),\n }));\n}\n\n/** The one usage line, replaced in place or added as the last block. */\nexport function setUsageLine<V extends BlockList>(view: V, line: UsageLine): V {\n const last = view.blocks[view.blocks.length - 1];\n const block = usageBlock(last?.type === 'usage' ? last.id : `b${view.nextId}`, line);\n if (last?.type === 'usage') return { ...view, blocks: replaceAt(view.blocks, view.blocks.length - 1, block) };\n return { ...view, blocks: [...view.blocks, block], nextId: view.nextId + 1 };\n}\n\nfunction closeBlock<B extends DisplayBlock>(block: B, interrupted: boolean): B {\n return interrupted && block.type === 'tool' && block.status === 'pending' ? { ...block, status: 'interrupted' } : sealed(block);\n}\n\nfunction closeSubagent(block: SubagentBlock, cut: SubagentStatus | null): SubagentBlock {\n const children = block.children.map((c) => closeBlock(c, cut !== null));\n const status = cut && block.status === 'running' ? cut : block.status;\n return status === block.status && children.every((c, i) => c === block.children[i]) ? block : { ...block, status, children };\n}\n\n/**\n * A turn is over, so whatever it left open is closed: streaming stops, and\n * when the turn was cut short (`cut`), its unanswered calls and running\n * subagents say so.\n */\nexport function closeOpenBlocks<V extends BlockList>(view: V, cut: SubagentStatus | null): V {\n const blocks = view.blocks.map((b) => (b.type === 'subagent' ? closeSubagent(b, cut) : closeBlock(b, cut !== null)));\n return blocks.every((b, i) => b === view.blocks[i]) ? view : { ...view, blocks };\n}\n","import type { ReplyRun, ResearchStep } from '../models/Task';\nimport type { SerializedPendingTurn, SessionMessage } from '../services/SessionMessage';\nimport { isMeasured } from '../models/Usage';\nimport type { DisplayBlock, MessageBlock, MessageRole, PlanBlock, ToolBlock } from './blocks';\nimport { pendingTool, planMarker, settledMessage, settledTool, skillLoadBlock, toolFromStep, userMessage } from './records';\nimport {\n append, appendOutput, closeOpenBlocks, findLastIndex, laneBlocks, laneOf, laneAppend, laneReplace, replaceAt, sealLane, sealed, setUsageLine,\n think, updateSubagent, type BlockList,\n} from './lanes';\n\n/**\n * A line a surface adds to the conversation itself rather than receiving from\n * the session: the user's prompt as it is sent, a notice, an error.\n */\nexport interface LocalEntry {\n type: 'local_entry';\n role: 'user' | 'system' | 'error';\n text: string;\n}\n\nexport type ConversationInput = SessionMessage | LocalEntry;\n\nexport interface ConversationView extends BlockList {\n /**\n * The newest transcript entry the view accounts for. Plan markers and system\n * notes reach a surface only inside the transcript a `plan_generated`\n * carries, so entries after this one are what is new in it.\n */\n readonly transcriptAt?: string;\n /** Reloaded arrivals, keyed by pending turn id until the live turn or transcript accounts for them. */\n readonly pendingInputs?: readonly { input: SerializedPendingTurn; blockIds: readonly string[] }[];\n}\n\nexport const EMPTY_CONVERSATION: ConversationView = { blocks: [], nextId: 1 };\n\ntype Message<T extends SessionMessage['type']> = Extract<SessionMessage, { type: T }>;\n\nfunction isUnsettledSegment(block: DisplayBlock, turnId: string): block is MessageBlock & { segmentId: string } {\n return block.type === 'message' && block.turnId === turnId && block.segmentId !== undefined;\n}\n\nfunction isBuildingPlan(block: DisplayBlock, turnId: string | undefined): block is PlanBlock {\n return block.type === 'plan' && block.status === 'building' && block.turnId === turnId;\n}\n\n/**\n * Where the turn's final segment is, if its text streamed: the turn's latest\n * block, when that is streamed text. Anything the turn did after a segment —\n * a tool call, a plan envelope — means a later segment follows it, and a later\n * segment never rewrites an earlier one. `pastPlan` looks past the turn's plan\n * block, for a plan that settled after its own text.\n */\nfunction finalSegmentIndex(blocks: readonly DisplayBlock[], turnId: string, pastPlan = false): number {\n for (let i = blocks.length - 1; i >= 0; i--) {\n const block = blocks[i];\n if (block.type === 'usage' || block.type === 'thinking' || block.type === 'approval' || (pastPlan && block.type === 'plan')) continue;\n // A task log's own blocks; a planner turn never has one.\n if (block.type === 'command' || block.type === 'compaction' || block.type === 'runner_loaded') continue;\n if (block.turnId !== turnId) continue;\n return isUnsettledSegment(block, turnId) ? i : -1;\n }\n return -1;\n}\n\nfunction openTurn(view: ConversationView, { turnId, prompt = '', skills = [], wakeUps = [], forced }: Message<'planner_turn_started'>): ConversationView {\n const adopted = takePendingInputs(view, prompt, wakeUps, turnId);\n view = adopted.view;\n wakeUps = wakeUps.slice(adopted.wakeUps);\n if (wakeUps.length === 0) return adopted.prompt || (prompt === '' && adopted.wakeUps > 0) ? view : promptLine(view, turnId, prompt, skills, forced);\n // A wake-up turn has no message; otherwise the run updates go ahead of the\n // message they were delivered with, where the transcript keeps them.\n const said = prompt === '' || adopted.prompt ? view : promptLine(view, turnId, prompt, skills, forced);\n const at = prompt === '' ? said.blocks.length : findLastIndex(said.blocks, (b) => b.type === 'message' && b.role === 'user' && b.turnId === turnId);\n const updates = wakeUps.map((text, n) => settledMessage(`b${said.nextId + n}`, 'wake_up', text, turnId));\n return { ...said, blocks: [...said.blocks.slice(0, at), ...updates, ...said.blocks.slice(at)], nextId: said.nextId + updates.length };\n}\n\nfunction takePendingInputs(view: ConversationView, prompt: string | undefined, wakeUps: readonly string[], turnId?: string): { view: ConversationView; prompt: boolean; wakeUps: number } {\n const pending = view.pendingInputs ?? [];\n const users = pending.filter(({ input }) => input.source === 'user');\n const updates = pending.filter(({ input }) => input.source === 'supervisor');\n const taken = new Set<string>();\n let matchedPrompt = false;\n // PlanTurns joins a batch's user messages, but reload draws each arrival.\n for (let n = 1; prompt !== undefined && n <= users.length; n++) {\n if (users.slice(0, n).map(({ input }) => input.text).join('\\n\\n') !== prompt) continue;\n for (const { input } of users.slice(0, n)) taken.add(input.id);\n matchedPrompt = true;\n break;\n }\n let matchedUpdates = 0;\n while (matchedUpdates < wakeUps.length && updates[matchedUpdates]?.input.text === wakeUps[matchedUpdates]) {\n taken.add(updates[matchedUpdates++].input.id);\n }\n if (taken.size === 0) return { view, prompt: false, wakeUps: 0 };\n const blockIds = new Set(pending.filter(({ input }) => taken.has(input.id)).flatMap(({ blockIds }) => blockIds));\n return {\n view: {\n ...view,\n blocks: turnId === undefined ? view.blocks : view.blocks.map((block) => blockIds.has(block.id) ? { ...block, turnId } : block),\n pendingInputs: pending.filter(({ input }) => !taken.has(input.id)),\n },\n prompt: matchedPrompt,\n wakeUps: matchedUpdates,\n };\n}\n\nfunction promptLine(view: ConversationView, turnId: string, prompt: string, skills: NonNullable<Message<'planner_turn_started'>['skills']>, forced?: boolean): ConversationView {\n // A surface shows its user's prompt the moment it is sent; the turn that\n // answers it adopts that line rather than repeating it.\n const i = findLastIndex(view.blocks, (b) => b.type === 'message' && b.role === 'user');\n const sent = view.blocks[i];\n const adopted = sent?.type === 'message' && sent.turnId === undefined && sent.text === prompt;\n const said: ConversationView = adopted\n ? { ...view, blocks: replaceAt(view.blocks, i, userMessage(sent.id, prompt, skills, { turnId, forced })) }\n : append(view, (id) => userMessage(id, prompt, skills, { turnId, forced }));\n if (skills.length === 0) return said;\n // Directly under the message that loaded them, wherever that line sits.\n const at = adopted ? i + 1 : findLastIndex(said.blocks, (b) => b.type === 'message' && b.role === 'user') + 1;\n const loads = skills.map((skill, n) => skillLoadBlock(`b${said.nextId + n}`, skill, turnId));\n return { ...said, blocks: [...said.blocks.slice(0, at), ...loads, ...said.blocks.slice(at)], nextId: said.nextId + loads.length };\n}\n\nfunction streamText(view: ConversationView, { turnId, segmentId, text }: Message<'planner_text_delta'>): ConversationView {\n const i = findLastIndex(view.blocks, (b) => isUnsettledSegment(b, turnId) && b.segmentId === segmentId);\n const segment = view.blocks[i];\n if (segment?.type === 'message') {\n return sealLane(laneReplace(view, null, i, { ...segment, text: segment.text + text, streaming: true }), null, i);\n }\n return appendOutput(view, null, (id) => ({ type: 'message', id, role: 'planner', text, streaming: true, turnId, segmentId }));\n}\n\n/**\n * Drop the turn's plan display while it is still building: whatever streamed\n * there did not become a plan — a task-ops or task-query envelope, or, from a\n * daemon older than turns, the reply's prose.\n */\nfunction dropBuildingPlan(view: ConversationView, turnId: string | undefined, segmentId?: string): ConversationView {\n const blocks = view.blocks.filter((b) => !(isBuildingPlan(b, turnId) && (segmentId === undefined || b.segmentId === segmentId)));\n return blocks.length === view.blocks.length ? view : { ...view, blocks };\n}\n\nfunction settleReply(view: ConversationView, { content, turnId, supervisor, runs }: Message<'planner_message'>): ConversationView {\n const role = supervisor ? 'supervisor' : 'planner';\n if (runs) return settleRuns(view, runs, role, turnId);\n if (turnId !== undefined) {\n const i = finalSegmentIndex(view.blocks, turnId);\n if (i >= 0) {\n return dropBuildingPlan({ ...view, blocks: replaceAt(view.blocks, i, settledMessage(view.blocks[i].id, role, content, turnId)) }, turnId);\n }\n }\n return append(dropBuildingPlan(view, turnId), (id) => settledMessage(id, role, content, turnId));\n}\n\n/**\n * Settle a reply run by run (ADR-0017 A1): each run's text takes its segment's\n * place, wherever in the turn it streamed, and only a run that never streamed\n * goes last. A segment of the turn the reply no longer contains did not\n * become part of it. Without a turn id (a reply a surface backfilled from the\n * transcript) the turn is the one the runs' segments streamed in.\n */\nfunction settleRuns(view: ConversationView, runs: readonly ReplyRun[], role: MessageRole, turnId: string | undefined): ConversationView {\n const settled = new Map<number, ReplyRun>();\n let turn = turnId;\n for (const run of runs) {\n const i = view.blocks.findIndex((b) => b.type === 'message' && b.segmentId === run.segmentId && b.turnId !== undefined && (turnId === undefined || b.turnId === turnId));\n const segment = view.blocks[i];\n if (segment?.type !== 'message') continue;\n settled.set(i, run);\n turn ??= segment.turnId;\n }\n const contained = new Set(runs.map((run) => run.segmentId));\n const blocks = view.blocks.flatMap((block, i) => {\n const run = settled.get(i);\n if (run) return [settledMessage(block.id, role, run.text, turn)];\n return turn !== undefined && isUnsettledSegment(block, turn) && !contained.has(block.segmentId) ? [] : [block];\n });\n const streamed = new Set(settled.values());\n return runs\n .filter((run) => !streamed.has(run))\n .reduce((next, run) => append(next, (id) => settledMessage(id, role, run.text, turn)), dropBuildingPlan({ ...view, blocks }, turn));\n}\n\n// A retracted envelope takes the turn's plan display with it, or its retry\n// would build on the botched JSON and the partial-plan rows read both.\nfunction retractText(view: ConversationView, { turnId, segmentId }: Message<'planner_text_retracted'>): ConversationView {\n const blocks = view.blocks.filter((b) => !(isUnsettledSegment(b, turnId) && (segmentId === undefined || b.segmentId === segmentId)));\n return dropBuildingPlan(blocks.length === view.blocks.length ? view : { ...view, blocks }, turnId, segmentId);\n}\n\nfunction startSubagent(view: ConversationView, { subagentId, brief, model, turnId }: Message<'subagent_started'>): ConversationView {\n return updateSubagent(view, subagentId, turnId, (block) => ({ ...block, ...(brief ? { brief } : {}), ...(model ? { model } : {}) }));\n}\n\nfunction finishSubagent(view: ConversationView, { subagentId, outcome, digest, usage, turnId }: Message<'subagent_finished'>): ConversationView {\n return updateSubagent(view, subagentId, turnId, (block) => ({\n ...block, status: outcome, digest, children: block.children.map(sealed), ...(usage ? { usage } : {}),\n }));\n}\n\nfunction announceTool(view: ConversationView, call: Message<'research_step'>): ConversationView {\n // A spawn call names the subagent it starts; any other call tagged with a\n // subagent is that subagent's own.\n const spawns = call.tool === 'spawn_research_agent' ? call.subagentId : undefined;\n const [placed, lane] = laneOf(view, spawns ? undefined : call.subagentId, call.turnId);\n return appendOutput(placed, lane, (id) => ({ ...pendingTool(id, call), ...(spawns ? { spawns } : {}) }));\n}\n\n// By the call's id: results of a parallel round return in any order, and a\n// name match would put one call's output on another's row (ADR-0008). The\n// name scan survives only for calls that announced no id.\nfunction isPendingCallOf(block: DisplayBlock, step: ResearchStep): block is ToolBlock {\n if (block.type !== 'tool' || block.status !== 'pending') return false;\n return step.toolCallId ? block.toolCallId === step.toolCallId : block.toolCallId === undefined && block.tool === step.tool;\n}\n\nfunction settleTool(view: ConversationView, { step, turnId }: Message<'research_step_done'>): ConversationView {\n const [placed, lane] = laneOf(view, step.subagentId, turnId);\n const blocks = laneBlocks(placed, lane);\n const i = findLastIndex(blocks, (b) => isPendingCallOf(b, step));\n const pending = blocks[i];\n if (pending?.type === 'tool') return laneReplace(placed, lane, i, settledTool(pending, step));\n // The call that spawned a subagent is shown by the subagent's block, and\n // only the subagent's own finish settles it: a backgrounded agent's call\n // returns at launch, long before the work ends.\n if (lane === null && step.toolCallId && blocks.some((b) => b.type === 'subagent' && b.toolCallId === step.toolCallId)) return view;\n return laneAppend(placed, lane, (id) => toolFromStep(id, step, turnId));\n}\n\n/**\n * The building display shows one envelope: the segment streaming now. A turn's\n * later envelope (a plan after a read it asked for) starts it over, below\n * whatever the turn did in between, rather than running on from the last one.\n */\nfunction streamPlan(view: ConversationView, { token, turnId, segmentId }: Message<'plan_token'>): ConversationView {\n const i = findLastIndex(view.blocks, (b) => isBuildingPlan(b, turnId));\n const building = view.blocks[i];\n if (building?.type === 'plan' && building.segmentId === segmentId) {\n return { ...view, blocks: replaceAt(view.blocks, i, { ...building, text: building.text + token }) };\n }\n return append(dropBuildingPlan(view, turnId), (id) => ({\n type: 'plan', id, status: 'building', text: token, ...(turnId ? { turnId } : {}), ...(segmentId ? { segmentId } : {}),\n }));\n}\n\n/** A plan landed: the building display of the turn that committed it becomes its marker. */\nfunction markPlan(view: ConversationView, content: string, turnId: string | undefined): ConversationView {\n const marker = planMarker(content);\n const i = findLastIndex(view.blocks, (b) => isBuildingPlan(b, turnId));\n const building = view.blocks[i];\n if (building?.type === 'plan') {\n const settled: PlanBlock = { type: 'plan', id: building.id, ...marker, text: '', ...(building.turnId ? { turnId: building.turnId } : {}) };\n return { ...view, blocks: replaceAt(view.blocks, i, settled) };\n }\n return append(view, (id) => ({ type: 'plan', id, text: '', ...marker }));\n}\n\nfunction requestApproval(view: ConversationView, { id: approvalId, kind, subject, scope, detail, turnId }: Message<'approval_request'>): ConversationView {\n return append(view, (id) => ({\n type: 'approval', id, approvalId, kind, subject, scope, status: 'pending',\n ...(detail ? { detail } : {}),\n ...(turnId ? { turnId } : {}),\n }));\n}\n\nfunction settleApproval(view: ConversationView, { id, granted }: Message<'approval_settled'>): ConversationView {\n const i = findLastIndex(view.blocks, (b) => b.type === 'approval' && b.approvalId === id);\n const request = view.blocks[i];\n if (request?.type !== 'approval') return view;\n return { ...view, blocks: replaceAt(view.blocks, i, { ...request, status: granted ? 'granted' : 'denied', decidedBy: 'asked' }) };\n}\n\nfunction decideApproval(view: ConversationView, { kind, subject, scope, detail, granted, source }: Message<'approval_decided'>): ConversationView {\n return append(view, (id) => ({\n type: 'approval', id, kind, subject, scope, status: granted ? 'granted' : 'denied', decidedBy: source,\n ...(detail ? { detail } : {}),\n }));\n}\n\nfunction reportUsage(view: ConversationView, message: Message<'planner_usage'>): ConversationView {\n return isMeasured(message.totals) ? setUsageLine(view, message) : view;\n}\n\n/**\n * Nothing carries the turn's id after this, so whatever it left open is closed:\n * streaming stops, and on a stop or failure its unanswered calls and running\n * subagents say they were cut short. A plan reply that streamed as text (a\n * prose preamble decides a segment's route) gives way to its plan block, as a\n * settled message would have replaced it.\n */\nfunction endTurn(view: ConversationView, { turnId, outcome }: Message<'planner_turn_ended'>): ConversationView {\n let next = dropBuildingPlan(view, turnId);\n const planText = outcome === 'plan' ? finalSegmentIndex(next.blocks, turnId, true) : -1;\n if (planText >= 0) next = { ...next, blocks: next.blocks.filter((_, i) => i !== planText) };\n return closeOpenBlocks(next, outcome === 'stopped' ? 'stopped' : outcome === 'error' ? 'failed' : null);\n}\n\n// The summary is announced as a planner message before the transcript it now\n// heads arrives; the transcript records it as a notice, and so does the view.\nfunction markCompaction(view: ConversationView, summary: string): ConversationView {\n const i = findLastIndex(view.blocks, (b) => b.type === 'message' && b.role === 'planner' && b.turnId === undefined && b.text === summary);\n const announced = view.blocks[i];\n if (announced?.type === 'message') return { ...view, blocks: replaceAt(view.blocks, i, { ...announced, role: 'system' }) };\n return append(view, (id) => settledMessage(id, 'system', summary));\n}\n\nfunction syncTranscript(view: ConversationView, { plan, turnId }: Message<'plan_generated'>): ConversationView {\n const history = plan.conversationHistory ?? [];\n // Only the newest marker can be the committing turn's; older ones a surface\n // is only now catching up on belong to turns long over.\n const committed = findLastIndex(history, (e) => e.kind === 'plan_generated');\n let next = view;\n let latest = view.transcriptAt;\n for (const [i, entry] of history.entries()) {\n const isNew = view.transcriptAt === undefined || entry.timestamp > view.transcriptAt;\n if (isNew && entry.role === 'user' && !entry.kind) next = takePendingInputs(next, entry.content, []).view;\n if (isNew && entry.kind === 'wake_up') next = takePendingInputs(next, undefined, [entry.content]).view;\n if (isNew && entry.kind === 'plan_generated') next = markPlan(next, entry.content, i === committed ? turnId : undefined);\n if (isNew && entry.kind === 'system') next = append(next, (id) => settledMessage(id, 'system', entry.content));\n if (isNew && entry.kind === 'error') next = append(next, (id) => settledMessage(id, 'error', entry.content));\n if (isNew && entry.kind === 'compaction') next = markCompaction(next, entry.content);\n if (latest === undefined || entry.timestamp > latest) latest = entry.timestamp;\n }\n return next === view && latest === view.transcriptAt ? view : { ...next, transcriptAt: latest };\n}\n\n/**\n * Bring the view's approval cards in line with the planner's requests the\n * session says are still waiting — for a surface that was not listening the\n * whole time: one that reconnected, reloaded, or just attached. A pending card\n * the session no longer has was answered or expired meanwhile; this surface\n * never heard how, so the card goes rather than guessing an answer. A waiting\n * request with no card gets one, answerable as the live one would have been.\n */\nexport function reconcileApprovals(view: ConversationView, waiting: readonly Message<'approval_request'>[]): ConversationView {\n const ids = new Set(waiting.map((request) => request.id));\n const answered = (block: DisplayBlock): boolean =>\n block.type === 'approval' && block.status === 'pending' && block.approvalId !== undefined && !ids.has(block.approvalId);\n const kept = view.blocks.some(answered) ? { ...view, blocks: view.blocks.filter((block) => !answered(block)) } : view;\n const carded = new Set(kept.blocks.flatMap((block) => (block.type === 'approval' && block.approvalId ? [block.approvalId] : [])));\n return waiting.filter((request) => !carded.has(request.id)).reduce(requestApproval, kept);\n}\n\n/**\n * Fold one input into the view. Pure and incremental: blocks the input does\n * not touch keep their identity, and an input that changes nothing returns\n * `view` itself — surfaces memoize their drawing on that, and text deltas\n * arrive quickly.\n */\nexport function reduceConversation(view: ConversationView, input: ConversationInput): ConversationView {\n switch (input.type) {\n case 'local_entry':\n return append(view, (id) => settledMessage(id, input.role, input.text));\n case 'planner_turn_started':\n return input.prompt === undefined ? view : openTurn(view, input);\n case 'planner_skill_loaded':\n return append(sealLane(view, null, -1), (id) => skillLoadBlock(id, input.skill, input.turnId));\n case 'planner_text_delta':\n return streamText(view, input);\n case 'planner_message':\n return settleReply(view, input);\n case 'planner_text_retracted':\n return retractText(view, input);\n case 'planner_thinking_delta':\n return think(view, input.text, input.turnId, input.segmentId, input.subagentId);\n case 'research_step':\n return announceTool(view, input);\n case 'research_step_done':\n return settleTool(view, input);\n case 'subagent_started':\n return startSubagent(view, input);\n case 'subagent_finished':\n return finishSubagent(view, input);\n case 'plan_token':\n return streamPlan(view, input);\n case 'plan_generated':\n return syncTranscript(view, input);\n case 'planner_turn_ended':\n return endTurn(view, input);\n case 'approval_request':\n return requestApproval(view, input);\n case 'approval_settled':\n return settleApproval(view, input);\n case 'approval_decided':\n return decideApproval(view, input);\n case 'execution_action':\n return append(view, (id) => settledMessage(id, 'system', input.text));\n case 'planner_usage':\n return reportUsage(view, input);\n default:\n return view;\n }\n}\n","import type { ResearchLogEntry, ResearchStep, SkillLoadNotice, SubagentLogEntry } from '../models/Task';\nimport type { SerializedConversationMessage, SerializedPendingTurn } from '../services/SessionMessage';\nimport { isMeasured, usageLine, type PlannerUsage } from '../models/Usage';\nimport type { DisplayBlock, MessageRole } from './blocks';\nimport { planMarker, settledMessage, skillLoadBlock, skillLoadNotice, subagentBlock, toolFromStep, usageBlock, userMessage } from './records';\nimport type { ConversationView } from './reduce';\n\n/** One top-level block before it has an id, and where it falls in time. */\ninterface Placed {\n at: string;\n /** Breaks a tie in `at`: a user's message, then the research it caused, then what the turn settled on. */\n rank: number;\n build: (nextId: () => string) => DisplayBlock;\n}\n\nconst USER = 0;\nconst RESEARCH = 1;\nconst SETTLED = 2;\n\n/** `loaded`: the skills the entries after a user's message say it loaded. */\nfunction fromEntry(entry: SerializedConversationMessage, loaded: readonly SkillLoadNotice[] = []): Placed['build'] {\n if (entry.kind === 'plan_generated') return (id) => ({ type: 'plan', id: id(), text: '', ...planMarker(entry.content) });\n if (entry.kind === 'skill_load' && entry.skill) {\n const { skill } = entry;\n return (id) => skillLoadBlock(id(), skillLoadNotice(skill));\n }\n if (entry.role === 'user' && !entry.kind) return (id) => userMessage(id(), entry.content, loaded.map(skillLoadNotice), { forced: entry.forced });\n return (id) => settledMessage(id(), roleOf(entry), entry.content);\n}\n\nfunction roleOf(entry: SerializedConversationMessage): MessageRole {\n switch (entry.kind) {\n case 'system': case 'compaction': case 'execution': return 'system';\n case 'wake_up': return 'wake_up';\n case 'supervisor': return 'supervisor';\n case 'error': return 'error';\n default: return entry.role === 'user' ? 'user' : 'planner';\n }\n}\n\nfunction loadsAfter(entries: readonly SerializedConversationMessage[], index: number): SkillLoadNotice[] {\n const loads: SkillLoadNotice[] = [];\n for (let i = index + 1; i < entries.length && entries[i].kind === 'skill_load'; i++) {\n const { skill } = entries[i];\n if (skill?.invokedBy === 'user') loads.push(skill);\n }\n return loads;\n}\n\n// A skill load ranks with the message that caused it: same time, same rank,\n// and the stable sort keeps it right under the message. A run update is a\n// turn's input too, ahead of the research it caused.\nfunction rankOf(entry: SerializedConversationMessage): number {\n return entry.role === 'user' && (!entry.kind || entry.kind === 'skill_load' || entry.kind === 'wake_up') ? USER : SETTLED;\n}\n\nfunction spawnBrief(step: ResearchStep): string | undefined {\n try {\n const args: unknown = JSON.parse(step.args);\n const prompt = args && typeof args === 'object' ? (args as Record<string, unknown>).prompt : undefined;\n return typeof prompt === 'string' ? prompt.trim() : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Which subagent a planner step started, if it did. The log keeps no link: a\n * harness planner's subagent takes its call's id, and an ADR-0005 research\n * agent is briefed with its spawn call's prompt, trimmed.\n */\nfunction spawnedBy(step: ResearchStep, unclaimed: SubagentLogEntry[]): SubagentLogEntry | undefined {\n const byId = unclaimed.find((e) => e.subagentId === step.toolCallId);\n if (byId) return byId;\n if (step.tool !== 'spawn_research_agent') return undefined;\n const brief = spawnBrief(step);\n return brief === undefined ? undefined : unclaimed.find((e) => e.brief === brief);\n}\n\nfunction research(log: readonly ResearchLogEntry[]): Placed[] {\n const subagents = log.filter((e): e is SubagentLogEntry => 'type' in e && e.type === 'subagent');\n const ownSubagent = new Set(subagents.map((e) => e.subagentId));\n const unclaimed = [...subagents];\n const spawnCall = new Map<string, string | undefined>();\n const placed: Placed[] = [];\n\n for (const entry of log) {\n if ('type' in entry) {\n if (entry.type === 'system') placed.push({ at: entry.timestamp, rank: RESEARCH, build: (id) => settledMessage(id(), 'system', entry.content) });\n continue;\n }\n if (entry.subagentId && ownSubagent.has(entry.subagentId)) continue;\n const spawned = spawnedBy(entry, unclaimed);\n if (spawned) {\n unclaimed.splice(unclaimed.indexOf(spawned), 1);\n spawnCall.set(spawned.subagentId, entry.toolCallId);\n continue;\n }\n placed.push({ at: entry.timestamp, rank: RESEARCH, build: (id) => toolFromStep(id(), entry) });\n }\n\n // A subagent stands where it started, which is where its spawn call was\n // announced; the call's own record is written only once the subagent is done.\n for (const entry of subagents) {\n const toolCallId = spawnCall.get(entry.subagentId);\n const steps = log.filter((e): e is ResearchStep => !('type' in e) && e.subagentId === entry.subagentId);\n placed.push({\n at: entry.timestamp,\n rank: RESEARCH,\n build: (id) => subagentBlock(id(), {\n subagentId: entry.subagentId, brief: entry.brief, status: entry.outcome, digest: entry.digest,\n children: steps.map((step) => toolFromStep(id(), step)),\n toolCallId, model: entry.model, usage: entry.usage,\n }),\n });\n }\n return placed;\n}\n\n/**\n * The view a saved session reopens with: what its transcript and research log\n * kept, in the order it happened — messages, each reply run by run where it\n * began, notices and the compaction summary, plan markers, tool calls with\n * each subagent's calls nested under it, and the token line. Reasoning and\n * streamed text that never settled were never saved, so a reload has none.\n *\n * The research log interleaves with the transcript by time. Entries older than\n * a compaction's first kept message went with the turns it condensed.\n * Pending inputs follow the landed records in arrival order; they are not\n * transcript entries until their turn lands.\n */\nexport function fromTranscript(\n conversationHistory: readonly SerializedConversationMessage[] | undefined,\n researchLog: readonly ResearchLogEntry[] | undefined,\n plannerUsage?: PlannerUsage,\n pendingTurns: readonly SerializedPendingTurn[] = [],\n): ConversationView {\n const history = conversationHistory ?? [];\n const compacted = history[0]?.kind === 'compaction' ? history[0] : undefined;\n const kept = compacted ? history.slice(1) : history;\n const cutoff = compacted ? (kept[0]?.timestamp ?? compacted.timestamp) : '';\n\n const placed: Placed[] = [\n ...kept.flatMap((entry, i): Placed[] => (entry.runs\n // ADR-0017 A1: each run of a reply where it streamed, among the research.\n ? entry.runs.map((run) => ({ at: run.startedAt, rank: SETTLED, build: (id) => settledMessage(id(), roleOf(entry), run.text) }))\n : [{ at: entry.timestamp, rank: rankOf(entry), build: fromEntry(entry, loadsAfter(kept, i)) }])),\n ...research(researchLog ?? []).filter((item) => item.at >= cutoff),\n ];\n placed.sort((a, b) => (a.at < b.at ? -1 : a.at > b.at ? 1 : a.rank - b.rank));\n // The summary stands where the condensed turns were, ahead of everything kept.\n if (compacted) placed.unshift({ at: '', rank: SETTLED, build: fromEntry(compacted) });\n\n let nextId = 1;\n const id = () => `b${nextId++}`;\n const blocks = placed.map((item) => item.build(id));\n const pendingInputs: NonNullable<ConversationView['pendingInputs']>[number][] = [];\n\n for (const input of pendingTurns) {\n const start = blocks.length;\n if (input.source === 'supervisor') {\n blocks.push(settledMessage(id(), 'wake_up', input.text));\n } else {\n const skills = (input.skills ?? []).map(skillLoadNotice);\n blocks.push(userMessage(id(), input.text, skills, { forced: input.forced }));\n blocks.push(...skills.map((skill) => skillLoadBlock(id(), skill)));\n }\n pendingInputs.push({ input: { ...input, skills: input.skills?.map(skillLoadNotice) }, blockIds: blocks.slice(start).map((block) => block.id) });\n }\n\n if (plannerUsage && isMeasured(plannerUsage.totals)) blocks.push(usageBlock(id(), usageLine(plannerUsage)));\n\n const transcriptAt = history.reduce<string | undefined>((latest, e) => (latest === undefined || e.timestamp > latest ? e.timestamp : latest), undefined);\n return { blocks, nextId, ...(transcriptAt ? { transcriptAt } : {}), ...(pendingInputs.length > 0 ? { pendingInputs } : {}) };\n}\n","/**\n * Whether two messages say the same thing. Claude Code words a usage limit\n * alike in its assistant message and in the `result` of the failed turn, but\n * for whitespace and a final period.\n */\nexport function sameMessage(a: string, b: string): boolean {\n const bare = (value: string) => value.trim().replace(/\\.+$/, '').trimEnd();\n return bare(a) !== '' && bare(a) === bare(b);\n}\n","import type { QueuedTaskMessage, StructuredTurnEnd, TaskMessageFrom } from '../interfaces/IRunner';\nimport type { ApprovalDecision } from '../interfaces/IApproval';\nimport type { TaskLogEvent } from '../models/TaskLog';\nimport { addPlannerUsage, isMeasured, usageLine, type PlannerUsage } from '../models/Usage';\nimport { sameMessage } from '../utils/sameMessage';\nimport { mapAgentTool, normalizeAgentArgs } from '../services/harness/agentTools';\nimport type { ApprovalBlock, CommandStatus, DisplayBlock, MessageBlock, SubagentChild, SubagentStatus, ThinkingDisplayBlock } from './blocks';\nimport { toolHeadline } from './format';\nimport {\n append, appendOutput, replaceAt, closeOpenBlocks, findLastIndex, laneAppend, laneBlocks, laneOf, laneReplace, setUsageLine, updateSubagent, sealed, sealLane,\n type BlockList, type Lane,\n} from './lanes';\nimport { finishedTool, pendingTool, settledMessage } from './records';\n\n/**\n * What a surface draws for one attempt of a structured task (ADR-0018, O1b):\n * the same display blocks as the planner conversation, built from the task's\n * {@link TaskLogEvent}s. No planner turn ids — a task's turns are its own,\n * one at a time.\n */\nexport interface TaskLogView extends BlockList {\n /** Messages not yet delivered, oldest first; `handedOver` marks the ones the runner already has. */\n readonly queued: readonly QueuedTaskMessage[];\n /** A turn is running. */\n readonly working: boolean;\n /** How the last turn ended; absent before the first one does. */\n readonly lastTurnEnd?: StructuredTurnEnd;\n /** What the runner reported over the attempt, subagents included. */\n readonly usage?: PlannerUsage;\n /**\n * The block each stream of deltas writes into — a run of text by its id,\n * thinking by whose it is — so the stream's authoritative copy replaces it\n * instead of repeating it below.\n */\n readonly streams: Readonly<Record<string, string>>;\n /** The turn's latest agent text block, which a failure that repeats it takes the place of. */\n readonly latestText?: string;\n}\n\nexport const EMPTY_TASK_LOG: TaskLogView = { blocks: [], nextId: 1, queued: [], working: false, streams: {} };\n\ntype Event<T extends TaskLogEvent['type']> = Extract<TaskLogEvent, { type: T }>;\n\n/** A log saved before runs of text carried an id streams every run through one key. */\nconst textStream = (runId: string | undefined) => (runId === undefined ? 'text' : `text:${runId}`);\nconst thinkingStream = (subagentId: string | undefined) => `thinking:${subagentId ?? ''}`;\n\nfunction withoutStream(view: TaskLogView, key: string): TaskLogView {\n if (!(key in view.streams)) return view;\n return { ...view, streams: Object.fromEntries(Object.entries(view.streams).filter(([k]) => k !== key)) };\n}\n\n// A later run of a turn in a log saved before runs carried an id opens with\n// the paragraph break that joined it; as a block of its own it needs none.\nfunction blockText(text: string): string {\n return text.replace(/^\\n+/, '');\n}\n\ntype Streamed = MessageBlock | ThinkingDisplayBlock;\n\n/** The lane's streaming block for `key`, while it is still the lane's latest output and still streaming. */\nfunction openStream(view: TaskLogView, lane: Lane, key: string): number {\n const id = view.streams[key];\n if (id === undefined) return -1;\n const blocks = laneBlocks(view, lane);\n const i = findLastIndex(blocks, (b) => b.type !== 'usage');\n const block = blocks[i];\n return block?.id === id && (block.type === 'message' || block.type === 'thinking') && block.streaming ? i : -1;\n}\n\n/** The lane's block for `key`, wherever it now sits. */\nfunction streamBlock(view: TaskLogView, lane: Lane, key: string): number {\n const id = view.streams[key];\n return id === undefined ? -1 : findLastIndex(laneBlocks(view, lane), (b) => b.id === id);\n}\n\n/**\n * One delta of `key`, into its block: the one it has wherever that sits when\n * `anywhere`, else only while that is still the lane's latest output.\n * Otherwise it opens a block of its own.\n */\nfunction streamDelta(view: TaskLogView, lane: Lane, key: string, text: string, make: (id: string, text: string) => Streamed, anywhere = false): TaskLogView {\n const i = anywhere ? streamBlock(view, lane, key) : openStream(view, lane, key);\n const open = laneBlocks(view, lane)[i];\n if (open?.type === 'message' || open?.type === 'thinking') return laneReplace(view, lane, i, { ...open, text: open.text + text });\n const next = appendOutput(view, lane, (id) => make(id, blockText(text)));\n return { ...next, streams: { ...next.streams, [key]: `b${view.nextId}` } };\n}\n\n/**\n * A run's authoritative copy: it replaces the text its deltas built, wherever\n * that block now sits in the lane, and is added whole when nothing streamed.\n */\nfunction streamWhole(view: TaskLogView, lane: Lane, key: string, text: string, make: (id: string) => SubagentChild): TaskLogView {\n const i = streamBlock(view, lane, key);\n const streamed = laneBlocks(view, lane)[i];\n const next = withoutStream(view, key);\n if (streamed?.type === 'message' || streamed?.type === 'thinking') {\n return laneReplace(next, lane, i, { ...streamed, text: blockText(text), streaming: false });\n }\n return appendOutput(next, lane, make);\n}\n\n/** The turn's latest text block is the one a run opened last; a run settling elsewhere leaves it be. */\nfunction openedText(view: TaskLogView, next: TaskLogView): TaskLogView {\n return next.nextId > view.nextId ? { ...next, latestText: `b${view.nextId}` } : next;\n}\n\nfunction agentText(view: TaskLogView, { runId, text }: Event<'text'>): TaskLogView {\n return openedText(view, streamWhole(view, null, textStream(runId), text, (id) => settledMessage(id, 'agent', blockText(text))));\n}\n\n/**\n * A run with an id streams into its own block wherever that now sits, so a\n * note or another run landing in the middle of it splits nothing. A log saved\n * without ids has one stream for every run, which streams into the latest\n * output only.\n */\nfunction agentTextDelta(view: TaskLogView, { runId, text }: Event<'text_delta'>): TaskLogView {\n const make = (id: string, t: string): Streamed => ({ type: 'message', id, role: 'agent', text: t, streaming: true });\n return openedText(view, streamDelta(view, null, textStream(runId), text, make, runId !== undefined));\n}\n\n/**\n * Claude Code says a usage limit twice — as an assistant message and as the\n * `result` of the failed turn. The log keeps both; the view shows the failure\n * alone when the turn's latest agent text only repeats it. Text before that\n * block is a real reply, and text that merely mentions the failure is not a\n * repeat.\n */\nfunction failTurn(view: TaskLogView, message: string): TaskLogView {\n const repeated = view.blocks.find((b) => b.id === view.latestText);\n const settled = repeated?.type === 'message' && repeated.role === 'agent' && sameMessage(repeated.text, message)\n ? {\n ...view,\n blocks: view.blocks.filter((b) => b !== repeated),\n streams: Object.fromEntries(Object.entries(view.streams).filter(([, id]) => id !== repeated.id)),\n }\n : view;\n return appendOutput({ ...settled, latestText: undefined }, null, (id) => settledMessage(id, 'error', message));\n}\n\nfunction thinkingBlock(id: string, text: string, streaming: boolean, subagentId: string | undefined): ThinkingDisplayBlock {\n return { type: 'thinking', id, text, streaming, ...(subagentId ? { subagentId } : {}) };\n}\n\nfunction thinkingDelta(view: TaskLogView, { text, subagentId }: Event<'thinking_delta'>): TaskLogView {\n const [placed, lane] = laneOf(view, subagentId);\n return streamDelta(placed, lane, thinkingStream(subagentId), text, (id, t) => thinkingBlock(id, t, true, subagentId));\n}\n\nfunction thinkingWhole(view: TaskLogView, { text, subagentId }: Event<'thinking'>): TaskLogView {\n const [placed, lane] = laneOf(view, subagentId);\n return streamWhole(placed, lane, thinkingStream(subagentId), text, (id) => thinkingBlock(id, blockText(text), false, subagentId));\n}\n\nfunction announceTool(view: TaskLogView, { id: toolCallId, name, args, subagentId }: Event<'tool_call'>): TaskLogView {\n const { tool, toolLabel } = mapAgentTool(name);\n const [placed, lane] = laneOf(view, subagentId);\n return appendOutput(placed, lane, (id) => {\n const call = pendingTool(id, { tool, toolLabel, args, toolCallId });\n const parsed = parseArgs(args);\n // Headline from the normalized arguments, as the harness planner's rows\n // are, so a `Read` or a Codex argv reads the same in both views.\n return parsed ? { ...call, headline: toolHeadline(tool, JSON.stringify(normalizeAgentArgs(tool, parsed)), toolLabel) } : call;\n });\n}\n\nfunction parseArgs(args: string): Record<string, unknown> | null {\n try {\n const parsed: unknown = JSON.parse(args);\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed as Record<string, unknown> : null;\n } catch {\n return null;\n }\n}\n\nfunction settleTool(view: TaskLogView, { id: toolCallId, output, success, subagentId }: Event<'tool_result'>): TaskLogView {\n const [placed, lane] = laneOf(view, subagentId);\n const blocks = laneBlocks(placed, lane);\n const i = findLastIndex(blocks, (b) => b.type === 'tool' && b.status === 'pending' && b.toolCallId === toolCallId);\n const pending = blocks[i];\n const outcome = success ? 'success' : 'failure';\n if (pending?.type === 'tool') return laneReplace(placed, lane, i, finishedTool(pending, output, outcome));\n // The call that spawned a subagent is shown by the subagent's block, and\n // only the subagent's own finish settles it: a backgrounded agent's call\n // returns at launch, long before the work ends.\n if (lane === null && blocks.some((b) => b.type === 'subagent' && b.toolCallId === toolCallId)) return view;\n return laneAppend(placed, lane, (id) => finishedTool(pendingTool(id, { tool: 'agent_tool', toolLabel: 'Tool', args: '', toolCallId }), output, outcome));\n}\n\nfunction startSubagent(view: TaskLogView, { subagentId, brief, model }: Event<'subagent_started'>): TaskLogView {\n return updateSubagent(view, subagentId, undefined, (block) => ({ ...block, ...(brief ? { brief } : {}), ...(model ? { model } : {}) }));\n}\n\nfunction finishSubagent(view: TaskLogView, { subagentId, outcome, digest }: Event<'subagent_finished'>): TaskLogView {\n const usage = view.usage?.bySubagent?.[subagentId];\n const next = updateSubagent(view, subagentId, undefined, (block) => ({\n ...block, status: outcome, digest, children: block.children.map(sealed), ...(usage ? { usage } : {}),\n }));\n return withoutStream(next, thinkingStream(subagentId));\n}\n\nfunction reportUsage(view: TaskLogView, { record }: Event<'usage'>): TaskLogView {\n const usage = addPlannerUsage(view.usage ?? { totals: {} }, record);\n const next = { ...view, usage };\n return isMeasured(usage.totals) ? setUsageLine(next, usageLine(usage)) : next;\n}\n\n/** A runner's tool request, read the way its call's row reads: `Bash(npm test)`. */\nexport function runnerToolSubject(tool: string, args: string): string {\n const { tool: mapped, toolLabel } = mapAgentTool(tool);\n const parsed = parseArgs(args);\n const headline = toolHeadline(mapped, parsed ? JSON.stringify(normalizeAgentArgs(mapped, parsed)) : args, toolLabel);\n return headline.keyArg ? `${headline.name}(${headline.keyArg})` : headline.name;\n}\n\nfunction requestApproval(view: TaskLogView, { approvalId, tool, args, allowForTask, toolCallId, decided }: Event<'approval_requested'>): TaskLogView {\n if (view.blocks.some((b) => b.type === 'approval' && b.approvalId === approvalId)) return view;\n return append(view, (id) => {\n const block: ApprovalBlock = {\n type: 'approval', id, approvalId, kind: 'runner_tool',\n subject: runnerToolSubject(tool, args),\n scope: tool,\n status: 'pending',\n ...(allowForTask ? { allowForTask } : {}),\n ...(toolCallId ? { toolCallId } : {}),\n };\n // Already answered at the source (an Ordewell tool, an auto-approving\n // mode): shown settled rather than as something still waiting on a person.\n return decided ? answered(block, decided) : block;\n });\n}\n\nfunction settleApproval(view: TaskLogView, approvalId: string, settle: (block: ApprovalBlock) => ApprovalBlock): TaskLogView {\n const i = findLastIndex(view.blocks, (b) => b.type === 'approval' && b.approvalId === approvalId);\n const block = view.blocks[i];\n if (block?.type !== 'approval' || block.status !== 'pending') return view;\n return { ...view, blocks: replaceAt(view.blocks, i, settle(block)) };\n}\n\nfunction answered(block: ApprovalBlock, decision: ApprovalDecision['decision'], note?: string): ApprovalBlock {\n return {\n ...block,\n status: decision === 'deny' ? 'denied' : 'granted',\n decidedBy: 'asked',\n ...(decision === 'allowForTask' ? { forTask: true } : {}),\n ...(note ? { note } : {}),\n };\n}\n\nfunction decideApproval(view: TaskLogView, { approvalId, decision, note }: Event<'approval_decided'>): TaskLogView {\n return settleApproval(view, approvalId, (block) => answered(block, decision, note));\n}\n\nfunction startTurn(view: TaskLogView, { message, messageId, from, forced }: Event<'turn_start'>): TaskLogView {\n const queued = messageId ? view.queued.filter((m) => m.id !== messageId) : view.queued;\n const working = { ...view, queued, working: true, latestText: undefined };\n // A turn the runner opened itself has no user message to show.\n return message ? append(working, (id) => ({ ...sentMessage(id, message, from), ...(forced ? { forced: true } : {}) })) : working;\n}\n\n/** A message to the runner, drawn as the user's unless Ordewell sent it (ADR-0018, W1). */\nfunction sentMessage(id: string, text: string, from: TaskMessageFrom | undefined): MessageBlock {\n return from === 'ordewell' ? settledMessage(id, 'system', `Ordewell: ${text}`) : settledMessage(id, 'user', text);\n}\n\n/** A runner command opens its turn as a message would, shown as the command it runs (#66). */\nfunction startCommand(view: TaskLogView, { name, args, messageId }: Event<'command'>): TaskLogView {\n const queued = messageId ? view.queued.filter((m) => m.id !== messageId) : view.queued;\n return append({ ...view, queued, working: true, latestText: undefined }, (id) => ({\n type: 'command', id, name, ...(args ? { args } : {}), status: 'running', output: '',\n }));\n}\n\nfunction runningCommand(view: TaskLogView): number {\n return findLastIndex(view.blocks, (b) => b.type === 'command' && b.status === 'running');\n}\n\nfunction commandOutput(view: TaskLogView, { text }: Event<'command_output'>): TaskLogView {\n const i = runningCommand(view);\n const block = view.blocks[i];\n if (block?.type !== 'command') return append(view, (id) => settledMessage(id, 'system', text));\n return { ...view, blocks: replaceAt(view.blocks, i, { ...block, output: block.output ? `${block.output}\\n${text}` : text }) };\n}\n\nfunction modelSwitchNotice({ from, to, plan, kept }: Event<'model_switched'>): string {\n if (!plan) return `Model changed in the runner: ${from.label ?? from.model} → ${to.label ?? to.model}${kept ? ` (${kept})` : ''}`;\n const planned = plan.model ? `${plan.model.label ?? plan.model.model}${plan.effort ? `, ${plan.effort}` : ''}` : undefined;\n if (!kept) return `Model changed in the runner: ${from.label ?? from.model} → ${to.label ?? to.model}; the plan now says ${planned ?? to.label ?? to.model}`;\n return `The runner now answers on ${to.label ?? to.model}; ${planned ? `the plan still says ${planned}` : 'the plan names no model'} (${kept})`;\n}\n\n/** Among the turn's steps, as a tool call is: what streamed before it is settled. */\nfunction appendStep(view: TaskLogView, make: (id: string) => DisplayBlock): TaskLogView {\n const next = append(view, make);\n return sealLane(next, null, findLastIndex(next.blocks, (b) => b.type !== 'usage'));\n}\n\nconst CUT: Record<StructuredTurnEnd, SubagentStatus | null> = { completed: null, interrupted: 'stopped', failed: 'failed' };\nconst COMMAND_END: Record<StructuredTurnEnd, CommandStatus> = { completed: 'done', interrupted: 'stopped', failed: 'failed' };\n\nfunction endTurn(view: TaskLogView, { reason }: Event<'turn_end'>): TaskLogView {\n const i = runningCommand(view);\n const command = view.blocks[i];\n const settled = command?.type === 'command' ? { ...view, blocks: replaceAt(view.blocks, i, { ...command, status: COMMAND_END[reason] }) } : view;\n const closed = closeOpenBlocks({ ...settled, working: false, lastTurnEnd: reason, streams: {}, latestText: undefined }, CUT[reason]);\n return reason === 'interrupted' ? append(closed, (id) => settledMessage(id, 'system', 'Interrupted.')) : closed;\n}\n\nfunction queueMessage(view: TaskLogView, { messageId, text, forced, from }: Event<'message_queued'>): TaskLogView {\n const listed = view.queued.find((m) => m.id === messageId);\n const sender = from ? { from } : {};\n if (forced) {\n // The session's own order (ADR-0023, F2): behind earlier forced messages, ahead of the rest.\n // Forcing one the runner already has moves it without taking it back.\n const rest = view.queued.filter((m) => m !== listed);\n const at = rest.findIndex((m) => !m.forced);\n const placed = at < 0 ? rest.length : at;\n const handedOver = listed?.handedOver ? { handedOver: true } : {};\n return { ...view, queued: [...rest.slice(0, placed), { id: messageId, text, forced: true, ...handedOver, ...sender }, ...rest.slice(placed)] };\n }\n if (!listed) return { ...view, queued: [...view.queued, { id: messageId, text, ...sender }] };\n if (!listed.handedOver) return view;\n return { ...view, queued: view.queued.map((m) => (m === listed ? { id: m.id, text: m.text, ...(m.forced ? { forced: true } : {}), ...sender } : m)) };\n}\n\nfunction handOver(view: TaskLogView, { messageId }: Event<'message_handed_over'>): TaskLogView {\n const listed = view.queued.find((m) => m.id === messageId);\n if (!listed || listed.handedOver) return view;\n return { ...view, queued: view.queued.map((m) => (m === listed ? { ...m, handedOver: true } : m)) };\n}\n\n/** The message joins the transcript where the runner read it, between the steps around it. */\nfunction deliverMidTurn(view: TaskLogView, event: Event<'message_delivered'>): TaskLogView {\n return appendOutput(unqueueMessage(view, event), null, (id) => sentMessage(id, event.text, event.from));\n}\n\nfunction unqueueMessage(view: TaskLogView, { messageId }: { messageId: string }): TaskLogView {\n const queued = view.queued.filter((m) => m.id !== messageId);\n return queued.length === view.queued.length ? view : { ...view, queued };\n}\n\nfunction endCall<B extends SubagentChild>(block: B): B {\n return block.type === 'tool' && block.status === 'pending' ? finishedTool(block, '', 'not_executed') as B : block;\n}\n\n/** Whatever the runner left without a result ended with it. */\nfunction endOpenCalls(view: TaskLogView): TaskLogView {\n let changed = false;\n const blocks = view.blocks.map((block) => {\n const ended = block.type === 'subagent'\n ? (block.children.some((c) => c.type === 'tool' && c.status === 'pending') ? { ...block, children: block.children.map(endCall) } : block)\n : block.type === 'tool' ? endCall(block)\n : block.type === 'command' && block.status === 'running' ? { ...block, status: 'stopped' as const } : block;\n if (ended !== block) changed = true;\n return ended;\n });\n return changed ? { ...view, blocks } : view;\n}\n\n/**\n * Fold one task-log event into the view. Pure and incremental, like\n * `reduceConversation`: an event that changes nothing returns `view` itself,\n * and an event of a type this build does not know is skipped — a log written\n * by a newer Ordewell still reads.\n */\nexport function reduceTaskLog(view: TaskLogView, event: TaskLogEvent): TaskLogView {\n switch (event.type) {\n case 'task_skills': return append(view, (id) => settledMessage(id, 'system', `Skills: ${event.skills.map((s) => `${s.name} (${s.path})`).join(', ')}`));\n case 'turn_start': return startTurn(view, event);\n case 'command': return startCommand(view, event);\n case 'command_output': return commandOutput(view, event);\n case 'model_switched': return append(view, (id) => settledMessage(id, 'system', modelSwitchNotice(event)));\n case 'compaction': return appendStep(view, (id) => ({\n type: 'compaction', id, trigger: event.trigger,\n ...(event.preTokens !== undefined ? { preTokens: event.preTokens } : {}), ...(event.postTokens !== undefined ? { postTokens: event.postTokens } : {}),\n }));\n case 'runner_loaded': return append(view, (id) => ({ type: 'runner_loaded', id, commands: event.commands, mcpServers: event.mcpServers }));\n case 'turn_end': return endTurn(view, event);\n case 'text_delta': return agentTextDelta(view, event);\n case 'text': return agentText(view, event);\n case 'thinking_delta': return thinkingDelta(view, event);\n case 'thinking': return thinkingWhole(view, event);\n case 'tool_call': return announceTool(view, event);\n case 'tool_result': return settleTool(view, event);\n case 'subagent_started': return startSubagent(view, event);\n case 'subagent_finished': return finishSubagent(view, event);\n case 'usage': return reportUsage(view, event);\n case 'message_queued': return queueMessage(view, event);\n case 'message_removed': return unqueueMessage(view, event);\n case 'message_handed_over': return handOver(view, event);\n case 'message_delivered': return deliverMidTurn(view, event);\n case 'message_undelivered': return append(unqueueMessage(view, event), (id) => settledMessage(id, 'system', `${event.text} · not delivered`));\n case 'error': return failTurn(view, event.message);\n case 'approval_requested': return requestApproval(view, event);\n case 'approval_decided': return decideApproval(view, event);\n case 'approval_withdrawn': return settleApproval(view, event.approvalId, (block) => ({ ...block, status: 'withdrawn' }));\n case 'runner_ended': return closeOpenBlocks({ ...endOpenCalls(view), working: false, streams: {}, latestText: undefined }, 'stopped');\n default: return view;\n }\n}\n\n/** A whole attempt's events, folded from the start — what a reload shows. */\nexport function replayTaskLog(events: readonly TaskLogEvent[], from: TaskLogView = EMPTY_TASK_LOG): TaskLogView {\n return events.reduce(reduceTaskLog, from);\n}\n","/**\n * Prompts the user sent while a planner turn was in flight, waiting to be the\n * next turn's input. The hold is a plain immutable list, oldest first, so a\n * pure reducer can keep it in state and a host can keep it in a field — and\n * either can draw it as is.\n */\nexport type PromptHold = readonly string[];\n\nexport const EMPTY_HOLD: PromptHold = [];\n\n/** One prompt taken out of the hold, and what is left behind. */\nexport interface TakenPrompt {\n text: string;\n rest: PromptHold;\n}\n\nexport function holdPrompt(hold: PromptHold, text: string): PromptHold {\n return [...hold, text];\n}\n\n/** The prompt a settled turn sends next: the oldest, so they go in the order typed. */\nexport function drainNext(hold: PromptHold): TakenPrompt | undefined {\n const [text, ...rest] = hold;\n return text === undefined ? undefined : { text, rest };\n}\n\n/**\n * Takes back the newest prompt — the one the user most likely just regretted —\n * while the older ones stay queued behind the turn.\n */\nexport function unsendLatest(hold: PromptHold): TakenPrompt | undefined {\n if (hold.length === 0) return undefined;\n return { text: hold[hold.length - 1], rest: hold.slice(0, -1) };\n}\n\n/**\n * Takes one prompt out by position — a \"Send now\" on that held row — leaving\n * every other prompt in the order it was typed.\n */\nexport function takeAt(hold: PromptHold, index: number): TakenPrompt | undefined {\n if (index < 0 || index >= hold.length) return undefined;\n return { text: hold[index], rest: [...hold.slice(0, index), ...hold.slice(index + 1)] };\n}\n\n/**\n * A stopped turn takes its queue with it: the prompts were written against a\n * turn that no longer exists, so they come back as one draft to edit and\n * resend rather than firing off after the stop.\n */\nexport function unsendAll(hold: PromptHold): TakenPrompt | undefined {\n if (hold.length === 0) return undefined;\n return { text: hold.join('\\n'), rest: EMPTY_HOLD };\n}\n\n/** Where an unsent prompt lands in the drafting input: above what is being typed, never replacing it. */\nexport function aheadOfDraft(text: string, draft: string): string {\n return draft ? `${text}\\n${draft}` : text;\n}\n","import type { SessionMessage } from '../services/SessionMessage';\nimport { reduceConversation, type ConversationInput, type ConversationView } from './reduce';\n\n/**\n * The planner turn a surface has open, and the one its user stopped. Kept\n * beside the view rather than in it: the view is what a turn drew, this is\n * whether the surface still wants to hear from it.\n */\nexport interface TurnGate {\n readonly open: string | null;\n readonly stopped: string | null;\n}\n\nexport const NO_TURN: TurnGate = { open: null, stopped: null };\n\nexport interface GatedConversation {\n view: ConversationView;\n gate: TurnGate;\n}\n\n/** What a turn streams — everything a stop cuts off. Usage, approvals and transcript markers are facts and still land. */\nconst TURN_STREAM = new Set<SessionMessage['type']>([\n 'planner_text_delta', 'planner_thinking_delta', 'planner_text_retracted', 'planner_message', 'plan_token',\n 'research_step', 'research_step_done', 'subagent_started', 'subagent_finished', 'planner_turn_ended',\n 'planner_skill_loaded',\n]);\n\n// A message with no turn id while a stop stands can only be the stopped\n// turn's: a new turn announces itself first, and that lifts the stop.\nfunction cutOff(gate: TurnGate, input: ConversationInput): boolean {\n if (gate.stopped === null || !TURN_STREAM.has(input.type as SessionMessage['type'])) return false;\n const turnId = 'turnId' in input ? input.turnId : undefined;\n return turnId === undefined || turnId === gate.stopped;\n}\n\nfunction withGate(live: GatedConversation, gate: TurnGate): GatedConversation {\n return gate.open === live.gate.open && gate.stopped === live.gate.stopped ? live : { ...live, gate };\n}\n\n/**\n * One input into the view, the stop rule applied: a turn the user stopped is\n * over on screen, and whatever it streams until the backend notices is\n * dropped. An input that changes nothing hands back the same view and gate.\n */\nexport function followTurn(view: ConversationView, gate: TurnGate, input: ConversationInput): GatedConversation {\n const live = { view, gate };\n if (input.type === 'planner_turn_started') {\n return withGate({ view: reduceConversation(view, input), gate }, { open: input.turnId, stopped: null });\n }\n if (cutOff(gate, input)) {\n return input.type === 'planner_turn_ended' ? withGate(live, { ...gate, stopped: null }) : live;\n }\n const next = { view: reduceConversation(view, input), gate };\n return input.type === 'planner_turn_ended' && input.turnId === gate.open ? withGate(next, { ...gate, open: null }) : next;\n}\n\n/**\n * The user stopped the planner. The turn ends on screen now rather than when\n * the backend notices the abort, so the surface is free at once and the\n * turn's late output never lands. Nothing changes when no turn is open.\n */\nexport function stopTurn(view: ConversationView, gate: TurnGate): GatedConversation {\n if (gate.open === null) return { view, gate };\n return {\n view: reduceConversation(view, { type: 'planner_turn_ended', turnId: gate.open, outcome: 'stopped' }),\n gate: { open: null, stopped: gate.open },\n };\n}\n","import type { DisplayBlock } from './blocks';\n\n/**\n * Whether the conversation holds anything the collapsed view hides — thinking,\n * a command row's arguments and output, a subagent's children and digest,\n * what a task's runner loaded. The\n * detail toggle is the only expansion control (ADR-0017, X1), so a surface\n * offers it only when it would do something.\n */\nexport function hasHiddenDetail(blocks: readonly DisplayBlock[]): boolean {\n return blocks.some((b) => b.type === 'thinking' || b.type === 'tool' || b.type === 'subagent' || b.type === 'runner_loaded');\n}\n","/** The conversation line for a task starting, worded the same on every surface. */\nexport function taskStartedNotice(title: string, runner?: string): string {\n return runner ? `Started \"${title}\" · ${runner}` : `Started \"${title}\"`;\n}\n","import MarkdownIt from 'markdown-it';\n\n/*\n * The one Markdown parser every surface draws a model's text from. The text\n * can be steered by what the model read, so what it may turn into — no raw\n * HTML, no image, no link but a web one — is settled here, where no surface\n * can loosen it.\n */\n\n// `breaks`: a chat reply's single newline is a line break, as it reads in the\n// raw text the model wrote, not a space as in a CommonMark document.\nconst md = new MarkdownIt({ html: false, linkify: true, breaks: true });\n\n// Only a URL written with its scheme is linked. Fuzzy matching would turn file\n// names into links (.md, .rs, .py and .sh are all country domains).\nmd.linkify.set({ fuzzyLink: false, fuzzyEmail: false });\n\n// Every link passes here, linkify's and autolinks' included. An allowlist, not\n// markdown-it's javascript/vbscript/file/data denylist: a vscode: or command:\n// URI would act inside the editor, and a relative URL resolves against the\n// webview's own origin.\nmd.validateLink = (url) => /^https?:/i.test(url);\n\n// A remote image would make the webview fetch a URL the model chose. It is\n// replaced in the tokens rather than at render time, so no surface gets one.\nmd.core.ruler.after('linkify', 'image_as_text', (state) => {\n for (const block of state.tokens) {\n if (!block.children) continue;\n block.children = block.children.map((token) => {\n if (token.type !== 'image') return token;\n const text = new state.Token('text', '', 0);\n text.content = token.content || (token.attrGet('src') ?? '');\n return text;\n });\n }\n});\n\nmd.renderer.rules.link_open = (tokens, idx, options, _env, self) => {\n tokens[idx].attrSet('target', '_blank');\n tokens[idx].attrSet('rel', 'noopener');\n return self.renderToken(tokens, idx, options);\n};\n\n// A table made its own scroll container is still fitted to its parent's width,\n// squashing every column; a box around it scrolls and the table keeps its own.\nmd.renderer.rules.table_open = (tokens, idx, options, _env, self) => `<div class=\"md-table\">${self.renderToken(tokens, idx, options)}`;\nmd.renderer.rules.table_close = () => '</table></div>\\n';\n\n/**\n * One markdown-it token, as far as a surface reads it. Declared here rather\n * than re-exporting markdown-it's class so a surface depends on core alone.\n */\nexport interface MarkdownToken {\n readonly type: string;\n readonly tag: string;\n readonly nesting: 1 | 0 | -1;\n readonly level: number;\n readonly content: string;\n readonly markup: string;\n readonly info: string;\n readonly block: boolean;\n readonly hidden: boolean;\n readonly map: readonly [number, number] | null;\n readonly attrs: readonly (readonly [string, string])[] | null;\n readonly children: readonly MarkdownToken[] | null;\n}\n\n/** The parsed blocks of a model's text, for a surface that paints them itself (the TUI). */\nexport function markdownTokens(text: string): readonly MarkdownToken[] {\n return md.parse(text, {});\n}\n\n/** A model's text as HTML, safe to set as a webview element's innerHTML. */\nexport function markdownHtml(text: string): string {\n return md.render(text);\n}\n","import type { StreamStamp } from '../daemonContract';\nimport type { TaskLogEvent } from '../models/TaskLog';\nimport { EMPTY_TASK_LOG, reduceTaskLog, replayTaskLog, type TaskLogView } from './taskLog';\n\nexport interface TaskLogBatch {\n attempt: number;\n events: TaskLogEvent[];\n position?: StreamStamp;\n}\n\n/** A saved attempt and the live batches that follow it (ADR-0018 P1). */\nexport interface TaskLogFollow {\n view: TaskLogView;\n attempts: number[];\n attempt: number;\n pending: TaskLogBatch[];\n loaded: boolean;\n followLatest: boolean;\n /** The outstanding pick; an older attempt read cannot replace it. */\n loadingAttempt?: number;\n /** The saved read's cutoff, also rejecting socket copies delivered after the read. */\n position?: StreamStamp;\n}\n\nexport type TaskLogFollowInput =\n | { type: 'opened' }\n | ({ type: 'loaded'; attempts?: number[]; abandoned?: boolean } & TaskLogBatch)\n | ({ type: 'live' } & TaskLogBatch)\n | { type: 'picked'; attempt: number };\n\nexport const EMPTY_TASK_LOG_FOLLOW: TaskLogFollow = {\n view: EMPTY_TASK_LOG, attempts: [], attempt: 0, pending: [], loaded: false, followLatest: true,\n};\n\nfunction covered(position: StreamStamp | undefined, batch: TaskLogBatch): boolean {\n return !!position && !!batch.position && position.stream === batch.position.stream && batch.position.seq <= position.seq;\n}\n\nfunction live(state: TaskLogFollow, batch: TaskLogBatch): TaskLogFollow {\n if (batch.attempt <= 0 || batch.attempt < state.attempt) return state;\n const attempts = state.attempts.includes(batch.attempt) ? state.attempts : [...state.attempts, batch.attempt].sort((a, b) => a - b);\n if (batch.attempt > state.attempt) {\n if (!state.followLatest) return attempts === state.attempts ? state : { ...state, attempts };\n return { ...state, attempts, attempt: batch.attempt, position: undefined, view: batch.events.reduce(reduceTaskLog, EMPTY_TASK_LOG) };\n }\n if (covered(state.position, batch)) return state;\n return { ...state, attempts, view: batch.events.reduce(reduceTaskLog, state.view) };\n}\n\n/** Join by stream position, never by event content or socket arrival time. */\nexport function followTaskLog(state: TaskLogFollow, input: TaskLogFollowInput): TaskLogFollow {\n switch (input.type) {\n case 'opened': return EMPTY_TASK_LOG_FOLLOW;\n case 'picked': return { ...state, loaded: false, loadingAttempt: input.attempt, followLatest: input.attempt === state.attempts.at(-1) };\n case 'live':\n return state.loaded ? live(state, input) : { ...state, pending: [...state.pending, input] };\n case 'loaded': {\n if (state.loaded) return state;\n if (!input.abandoned && state.loadingAttempt !== undefined && input.attempt !== state.loadingAttempt) return state;\n const attempts = [...new Set([...(input.attempts ?? state.attempts), ...state.pending.map((batch) => batch.attempt)])].filter((attempt) => attempt > 0).sort((a, b) => a - b);\n let next: TaskLogFollow = {\n ...state, attempts, loaded: true, pending: [], loadingAttempt: undefined,\n ...(input.abandoned ? {} : { attempt: input.attempt, view: replayTaskLog(input.events), position: input.position }),\n };\n for (const batch of state.pending) {\n // A read of one attempt does not account for another attempt's file.\n if (!input.abandoned && batch.attempt === input.attempt) {\n if (covered(input.position, batch)) continue;\n // An older daemon supplies no position; preserve its replay behaviour.\n if (!input.position && !batch.position) continue;\n }\n next = live(next, batch);\n }\n return next;\n }\n }\n}\n","import { NOT_STARTED } from './status';\n\n/**\n * What a user can do to one task from its row. For a task paused on a usage\n * limit, `resume-now` resumes it in its saved session once the user says the\n * limit has reset, and `cancel-resume` keeps it from resuming on its own.\n */\nexport type TaskRowAction = 'cancel' | 'resume-now' | 'cancel-resume' | 'skip' | 'force-start' | 'complete' | 'uncomplete';\n\n/** A subtask runs with its parent, so its row offers a different set than a top-level task's. */\nexport type TaskRowPlacement = 'task' | 'subtask';\n\ninterface ActionSubject {\n status: string;\n type: 'ai' | 'user';\n awaitingReason?: string;\n resumeAt?: string | null;\n /** Its last attempt left a runner session to continue (ADR-0018, K1). */\n continuable?: boolean;\n}\n\ntype Rule = readonly [TaskRowAction, (task: ActionSubject) => boolean];\n\nconst UNSTARTED_AI = (t: ActionSubject): boolean => t.type === 'ai' && NOT_STARTED.has(t.status);\nconst QUEUED = (t: ActionSubject): boolean => t.status === 'pending' || t.status === 'approved';\nconst PAUSED = (t: ActionSubject): boolean => t.status === 'awaiting_user' && t.awaitingReason === 'usage-limit';\nconst RESUMES = (t: ActionSubject): boolean => PAUSED(t) && !!t.resumeAt;\nconst RESUMABLE = (t: ActionSubject): boolean => PAUSED(t) && t.continuable === true;\n/** Work that holds up what depends on it until someone acts: Skip lets the run go on without it. */\nconst HOLDS_UP = (t: ActionSubject): boolean => t.status === 'failed' || t.status === 'blocked' || t.status === 'awaiting_user';\n\n// Order is the order a surface lays the actions out in.\nconst TASK_RULES: readonly Rule[] = [\n ['cancel', (t) => t.status === 'in_progress'],\n ['resume-now', RESUMABLE],\n ['cancel-resume', RESUMES],\n ['skip', HOLDS_UP],\n ['force-start', UNSTARTED_AI],\n // A manual task has no runner to report it done, so it can always be marked;\n // a skipped one's kept work can still be vouched for.\n ['complete', (t) => t.status === 'awaiting_user' || t.status === 'skipped' || t.type === 'user'],\n ['uncomplete', (t) => t.status === 'completed'],\n];\n\nconst SUBTASK_RULES: readonly Rule[] = [\n ['cancel', (t) => t.status === 'in_progress'],\n ['resume-now', RESUMABLE],\n ['cancel-resume', RESUMES],\n ['complete', (t) => t.status === 'in_progress' && t.type === 'ai'],\n ['force-start', (t) => t.type === 'ai' && QUEUED(t)],\n ['skip', (t) => QUEUED(t) || t.status === 'failed'],\n ['complete', (t) => t.status === 'awaiting_user' || t.status === 'skipped'],\n ['uncomplete', (t) => t.status === 'completed'],\n];\n\n/** The actions a task's row offers while a plan runs, in the order they are laid out. */\nexport function taskRowActions(task: ActionSubject, placement: TaskRowPlacement = 'task'): TaskRowAction[] {\n const rules = placement === 'subtask' ? SUBTASK_RULES : TASK_RULES;\n return rules.filter(([, applies]) => applies(task)).map(([action]) => action);\n}\n\n/**\n * One toggle in both directions: a done task is taken back, anything else is\n * marked done. A second control for the reverse is one nobody remembers.\n */\nexport function markAction(task: { status: string }): 'complete' | 'uncomplete' {\n return task.status === 'completed' ? 'uncomplete' : 'complete';\n}\n\n/**\n * The mark an action asks the session for, or null when it is not a mark.\n * Skip is not one: it ends the task without vouching for its work, which\n * only Mark complete does.\n */\nexport function markRequestFor(action: string): 'complete' | 'uncomplete' | null {\n if (action === 'complete') return 'complete';\n if (action === 'uncomplete') return 'uncomplete';\n return null;\n}\n\n/** Change versus ops can still be flipped (ADR-0020): an AI task that has not started. */\nexport function opsEditable(task: ActionSubject): boolean {\n return UNSTARTED_AI(task);\n}\n","import type { AwaitingReason, DiscoveredModel, RunnerId } from '../models/Task';\nimport { effectiveAllowlist } from './ModelAllowlistResolver';\n\n/**\n * What the user allows the plan to be built from right now: the enabled\n * runners and each runner's model allowlist. Structural, so a surface that\n * only holds the two lists can ask without a session.\n */\nexport interface AssignmentScope {\n enabledRunners: readonly string[];\n allowlist: Readonly<Record<string, readonly string[] | undefined>>;\n /**\n * The models discovery has found per runner, where the holder has them. An\n * allowlist is read against them exactly as the planner's catalog reads it\n * (ids only another runner lists limit nothing), so a flag never says a\n * model is off a list the planner sees as no limit.\n */\n models?: Readonly<Partial<Record<RunnerId, readonly DiscoveredModel[]>>>;\n}\n\n/** The part of a task an assignment is read from. */\nexport interface AssignedTask {\n type: string;\n status: string;\n assignedRunner: string;\n assignedModel?: { modelId: string; modelLabel?: string };\n}\n\nexport type AssignmentIssue =\n | { kind: 'runner-off'; runner: string }\n | { kind: 'model-off-list'; runner: string; modelId: string; modelLabel: string };\n\n/** A finished task has nothing left to run, so where it ran is history, not a choice to revisit. */\nconst OVER = new Set(['completed', 'skipped']);\n\n/**\n * Whether a task sits outside the scope it is read against. This only names\n * the mismatch: such a task still runs (ADR-0003, P1) — the allowlist and the\n * enabled runners shape what is planned, not what is started — and the user or\n * the planner may move it. A runner that is off settles the matter before its\n * model is looked at.\n */\nexport function assignmentIssue(task: AssignedTask, scope: AssignmentScope): AssignmentIssue | null {\n if (task.type !== 'ai' || OVER.has(task.status)) return null;\n if (!scope.enabledRunners.includes(task.assignedRunner)) return { kind: 'runner-off', runner: task.assignedRunner };\n const model = task.assignedModel;\n const allowed = effectiveAllowlist(scope.allowlist[task.assignedRunner] as string[] | undefined, task.assignedRunner, scope.models as Partial<Record<RunnerId, DiscoveredModel[]>> | undefined);\n if (model && allowed && !allowed.includes(model.modelId)) {\n return { kind: 'model-off-list', runner: task.assignedRunner, modelId: model.modelId, modelLabel: model.modelLabel || model.modelId };\n }\n return null;\n}\n\nexport function assignmentIssueText(issue: AssignmentIssue): string {\n return issue.kind === 'runner-off' ? `${issue.runner} is switched off` : `${issue.modelLabel} is not in the allowlist`;\n}\n\n/** Where a flagged task stands, which decides what its assignment means. */\nexport interface AssignmentStanding {\n status?: string;\n awaitingReason?: AwaitingReason;\n resumeAt?: string | null;\n}\n\n/**\n * What happens to a flagged task as assigned, which depends on where it stands:\n * a failed one only runs again if retried, and a pause whose attempt ended (a\n * usage limit, work that did not land) has nothing running, whatever its\n * status says. The planner's note and every surface's flag read this one text.\n */\nexport function assignmentConsequence({ status, awaitingReason, resumeAt }: AssignmentStanding): string {\n if (status === 'failed') return 'failed; a retry would run it there unless moved';\n if (status === 'awaiting_user' && awaitingReason === 'usage-limit') {\n return resumeAt ? 'paused on a usage limit; resumes there at the reset unless moved' : 'paused on a usage limit; a retry would run it there unless moved';\n }\n if (status === 'awaiting_user' && (awaitingReason === 'conflict' || awaitingReason === 'files-changed')) return 'waiting for the user; what runs next runs there unless moved';\n if (status === 'in_progress' || status === 'awaiting_user') return 'already running as assigned';\n return 'runs as assigned unless moved';\n}\n","import { taskUsageSummary, type AttemptUsage, type TaskUsageSummary } from '../models/Usage';\nimport type { AwaitingReason } from '../models/Task';\nimport type { TaskIsolationState } from '../interfaces/IWorktreeIsolation';\nimport { taskOrderLabel, taskRefOf } from '../services/TaskRefs';\nimport { capConflictFiles } from '../services/conflictFiles';\nimport { blockingFailures, type BlockingSubject } from '../services/blocking';\nimport { assignmentConsequence, assignmentIssue, assignmentIssueText, type AssignmentScope } from '../services/AssignmentScope';\nimport { approvalLabel, awaitingLabel, isTaskRunning, NOT_STARTED, resumeLabel, taskStatusKind, WAITS_FOR_APPROVAL_LABEL, type TaskStatusKind } from './status';\nimport { markAction, opsEditable, taskRowActions, type TaskRowAction, type TaskRowPlacement } from './actions';\n\n/**\n * A task as both surfaces hold it, with the live state each tracks beside it\n * (silence, approvals, isolation, the merge gate). Structural, because the TUI\n * projects tasks into its own shape.\n */\nexport interface TaskRowSubject {\n id: string;\n order: number;\n type: 'ai' | 'user';\n status: string;\n dependencies: readonly string[];\n taskMode?: string;\n ops?: boolean;\n idleSince?: string | null;\n awaitingReason?: AwaitingReason;\n skipReason?: string;\n /** When a task paused on a usage limit resumes on its own (ISO time). */\n resumeAt?: string | null;\n /** Its last attempt left a runner session to continue (ADR-0018, K1). */\n continuable?: boolean;\n awaitingApproval?: number;\n /** Added after the user approved the plan, and not approved since (ADR-0035). */\n waitsForApproval?: boolean;\n isolation?: TaskRowIsolation | null;\n mergeGate?: readonly string[];\n forcedPastGate?: readonly string[];\n attemptUsage?: readonly AttemptUsage[];\n assignedRunner?: string;\n assignedModel?: { modelId: string; modelLabel?: string };\n}\n\nexport interface TaskRowIsolation {\n state: TaskIsolationState;\n repos?: string[];\n conflictRepo?: string;\n conflictFiles?: string[];\n repair?: { attempt: number; limit: number };\n repairedFiles?: string[];\n}\n\n/**\n * The plan a row labels its references against: the tree, so a subtask's\n * dependency reads dotted (\"#2.1\") rather than by its parent-scoped order.\n * With statuses and dependencies it also tells which tasks a failure blocks.\n */\ninterface PlanRefTask {\n id: string;\n order: number;\n title: string;\n status?: string;\n dependencies?: readonly string[];\n subtasks?: readonly PlanRefTask[];\n}\n\nexport interface TaskRowContext {\n /** Set for a subtask: it is labelled by its dotted order. */\n parent?: { order: number } | null;\n /** Which action set the row offers; a row with a parent is a subtask's unless told otherwise. */\n placement?: TaskRowPlacement;\n /** The plan tree a dependency, gate or block is labelled against; one it does not hold is shown by id. */\n tasks?: readonly PlanRefTask[];\n /** The modes the task's runner declares; autonomy is a tag on one of them (ADR-0001). */\n modes?: readonly { id: string; autonomous?: boolean }[];\n /** What a resume time is read against; the clock when absent. */\n now?: Date;\n /** The enabled runners and allowlist an assignment is read against; without it no assignment is flagged. */\n runnerScope?: AssignmentScope;\n}\n\n/** Whether the row stands for an AI task, a manual one, or an ops task (ADR-0020). */\nexport type TaskRowKind = 'ai' | 'user' | 'ops';\n\n/** The task's whole spend (see `taskUsageSummary`); `attempt` is the latest one, 0 before any reported. */\nexport interface TaskRowUsage extends Pick<TaskUsageSummary, 'totals' | 'contextFill'> {\n attempt: number;\n}\n\nexport interface TaskRowView {\n usage: TaskRowUsage | null;\n /** \"2\", or \"2.1\" for a subtask. */\n orderLabel: string;\n kind: TaskRowKind;\n status: TaskStatusKind;\n /** A runner is live behind it — `quiet` included. */\n running: boolean;\n /** What an awaiting task waits on, in sentence case; null when nothing was saved. */\n awaiting: string | null;\n /** \"Resumes at 8:10pm\" while a task paused on a usage limit resumes on its own; null otherwise. */\n resumes: string | null;\n /** Runner requests waiting on the user, in sentence case; null when none do. */\n approvals: string | null;\n /** That it waits for the user's approval to start, in sentence case; null once it started, or when it needs none. */\n waitsForApproval: string | null;\n /** Why the task's runner or model is one the user has since moved away from, in sentence case; null when it is not. The task still runs. */\n assignmentFlag: string | null;\n /** What the flag means for this task as it stands (a failed one runs again only if retried); set exactly when `assignmentFlag` is. */\n assignmentConsequence: string | null;\n /** The task's mode is tagged autonomous: it runs without permission prompts. */\n autonomous: boolean;\n /** The repos its isolated work changed, by path; empty for a group of one. */\n repos: string[];\n /** Integration stopped on a conflict: the one isolation state that needs the user. */\n conflict: { repo: string | null; files: string | null } | null;\n /** A conflict repair in flight (ADR-0015) — progress, not a blocker. */\n repairing: { files: string | null; attempt: { attempt: number; limit: number } | null } | null;\n /** The files a conflict repair was started for; `landed` once the task is integrated. */\n repaired: { files: string; landed: boolean } | null;\n /** The ancestors, by reference, whose work is not merged into the user's branch yet. */\n mergeGate: string[] | null;\n /** The failed tasks, by reference, a task not started waits on through its dependencies (ADR-0034); null when none. */\n blockedBy: string[] | null;\n /** Why a skipped task was skipped, as whoever skipped it put it; null for any other, or one skipped without a reason. */\n skipReason: string | null;\n /** An ops task changed tracked files in the user's checkout and nothing was committed. */\n opsChangedFiles: boolean;\n /** The ancestors, by title, a force start went past the merge gate of. */\n forcedPastGate: readonly string[] | null;\n /** The task's dependencies, by reference. */\n dependencies: string[];\n /** What the row offers while a plan runs. */\n actions: TaskRowAction[];\n /** The one mark its toggle sets. */\n mark: 'complete' | 'uncomplete';\n opsEditable: boolean;\n}\n\nconst refsOf = (ids: readonly string[], tasks: readonly PlanRefTask[] | undefined): string[] =>\n ids.map((id) => (tasks?.length ? taskRefOf(tasks, id) ?? id : id));\n\n/** A lone repository at the workspace root is not named: a group of one reads as it did before repo groups. */\nconst namedRepo = (repo: string | undefined): string | null => (repo && repo !== '.' ? repo : null);\n\n/** The repos a task changed, for a row that names them; none for a group of one. */\nexport const namedRepos = (repos: readonly string[] | undefined): string[] => (repos ?? []).filter((r) => r !== '.');\n\nconst filesOf = (files: string[] | undefined): string | null => (files?.length ? capConflictFiles(files) : null);\n\nconst asBlocking = (tasks: readonly PlanRefTask[]): BlockingSubject[] =>\n tasks.map((t) => ({ id: t.id, status: t.status ?? '', dependencies: t.dependencies ?? [], subtasks: asBlocking(t.subtasks ?? []) }));\n\n/** What blocks a task not started, read off the plan tree; empty without one that carries statuses. */\nfunction blockedBy(task: TaskRowSubject, tasks: readonly PlanRefTask[] | undefined): string[] {\n if (!tasks?.length || !NOT_STARTED.has(task.status)) return [];\n return blockingFailures(asBlocking(tasks)).get(task.id) ?? [];\n}\n\nfunction flagOf(task: TaskRowSubject, scope: AssignmentScope | undefined): Pick<TaskRowView, 'assignmentFlag' | 'assignmentConsequence'> {\n const issue = scope && task.assignedRunner !== undefined ? assignmentIssue({ ...task, assignedRunner: task.assignedRunner }, scope) : null;\n return issue\n ? { assignmentFlag: assignmentIssueText(issue), assignmentConsequence: assignmentConsequence(task) }\n : { assignmentFlag: null, assignmentConsequence: null };\n}\n\n/**\n * Everything a plan row says about one task, decided once: each surface picks\n * its own words, glyphs and casing for these facts, and derives none of them.\n */\nexport function taskRowView(task: TaskRowSubject, context: TaskRowContext = {}): TaskRowView {\n const parent = context.parent ?? undefined;\n const isolation = task.isolation && task.isolation.state !== 'none' ? task.isolation : null;\n const spend = taskUsageSummary(task);\n const latestAttempt = task.attemptUsage?.at(-1);\n const blocked = blockedBy(task, context.tasks);\n return {\n usage: latestAttempt ? { totals: spend.totals, ...(spend.contextFill ? { contextFill: spend.contextFill } : {}), attempt: latestAttempt.attempt } : task.type === 'ai' && ['completed', 'failed', 'in_progress', 'awaiting_user'].includes(task.status) ? { totals: {}, attempt: 0 } : null,\n orderLabel: taskOrderLabel(task, parent),\n kind: task.type === 'user' ? 'user' : task.ops ? 'ops' : 'ai',\n status: blocked.length > 0 ? 'blocked' : taskStatusKind(task),\n running: isTaskRunning(task),\n awaiting: awaitingLabel(task),\n resumes: resumeLabel(task, context.now),\n approvals: approvalLabel(task.awaitingApproval),\n waitsForApproval: task.waitsForApproval && NOT_STARTED.has(task.status) ? WAITS_FOR_APPROVAL_LABEL : null,\n ...flagOf(task, context.runnerScope),\n autonomous: task.type === 'ai' && context.modes?.find((m) => m.id === task.taskMode)?.autonomous === true,\n repos: namedRepos(isolation?.repos),\n conflict: isolation?.state === 'conflict'\n ? { repo: namedRepo(isolation.conflictRepo), files: filesOf(isolation.conflictFiles) }\n : null,\n repairing: isolation?.state === 'repairing'\n ? { files: filesOf(isolation.conflictFiles), attempt: isolation.repair ?? null }\n : null,\n repaired: isolation?.repairedFiles?.length\n ? { files: capConflictFiles(isolation.repairedFiles), landed: isolation.state === 'integrated' }\n : null,\n mergeGate: task.mergeGate?.length ? refsOf(task.mergeGate, context.tasks) : null,\n blockedBy: blocked.length > 0 ? refsOf(blocked, context.tasks) : null,\n skipReason: task.status === 'skipped' ? task.skipReason ?? null : null,\n opsChangedFiles: task.status === 'awaiting_user' && task.awaitingReason === 'files-changed',\n forcedPastGate: task.forcedPastGate?.length ? task.forcedPastGate : null,\n dependencies: refsOf(task.dependencies, context.tasks),\n // A block read off the plan offers what a stored one does: Skip among them.\n actions: taskRowActions(blocked.length > 0 ? { ...task, status: 'blocked' } : task, context.placement ?? (parent ? 'subtask' : 'task')),\n mark: markAction(task),\n opsEditable: opsEditable(task),\n };\n}\n","import { titledTaskRef, titledTaskRefOf } from '../services/TaskRefs';\n\ninterface Named {\n id: string;\n order: number;\n title: string;\n subtasks?: readonly Named[];\n}\n\n/** Each id as \"#N title\", subtasks dotted, by the plan's tree; one it no longer holds stays a bare id. */\nexport function titledRefs(ids: readonly string[], tasks: readonly Named[]): string[] {\n return ids.map((id) => titledTaskRefOf(tasks, id) ?? id);\n}\n\n/**\n * What removing a task does to the tasks that depend on it, or null when none\n * do. Named rather than counted: the removal rewrites their dependency lists,\n * and a bare \"Remove task?\" would hide that.\n */\nexport function dependentsNotice(dependents: readonly { id?: string; order: number; title: string }[], tasks: readonly Named[] = []): string | null {\n if (dependents.length === 0) return null;\n const subject = dependents.length === 1 ? '1 task depends' : `${dependents.length} tasks depend`;\n return `${subject} on it and will lose that dependency: ${dependents.map((t) => (t.id ? titledTaskRefOf(tasks, t.id) : undefined) ?? titledTaskRef(t)).join(', ')}.`;\n}\n\n/**\n * What a start past a merge gate is asked with (ADR-0020): the work the task\n * would act without, named. `subject` is how the asking surface refers to the\n * task — \"It\" under a title that already names it.\n */\nexport function pastGateConfirmation(unmerged: readonly string[], subject = 'This task'): string {\n return `${subject} waits for Merge all: the work of ${unmerged.join(', ')} is not merged into your branch yet, so it would act without it. Starting it now is kept on the task.`;\n}\n\nexport interface NewTaskFields {\n title: string;\n description: string;\n prompt: string;\n type: 'ai';\n}\n\n/**\n * What a hand-added task starts as: an AI task whose description is its title\n * and whose prompt, unless one was typed, is too. Null for a title with nothing\n * in it, rather than a nameless task. Assignments are left for the session to\n * derive from the runner's catalog.\n */\nexport function newTaskFields(title: string, prompt?: string): NewTaskFields | null {\n const name = title.trim();\n if (!name) return null;\n return { title: name, description: name, prompt: prompt?.trim() ? prompt : name, type: 'ai' };\n}\n","import { serializeTask, type RunInput, type RunTask, type RunTaskStatus, type RunView, type SerializedTask, type SerializedTaskStatus, type SurfacePlan, type SurfacePlanState, type SurfaceTask } from './SessionMessage';\nimport type { IsolationHandoff } from '../interfaces/IWorktreeIsolation';\nimport { rejoinPlanTree } from '../models/Task';\nimport { walkPlan } from './PlanTree';\n\nexport const EMPTY_RUN: RunView = { tasks: [], runMerge: null, handoff: null, mergeResult: null };\n\ntype PlanFields = Omit<RunTask, keyof RunTaskStatus>;\n\n/**\n * The one decision of which task fields are status-only: what is named here\n * no plan carries, so only a status update changes it and a plan refresh\n * keeps it. Everything else is the plan's.\n */\nfunction split({ verdict, idleSince, isolation, checkpoint, queued, continuable, awaitingApproval, mergeGate, forcedPastGate, waitsForApproval, ...plan }: RunTask): { plan: PlanFields; status: RunTaskStatus } {\n return { plan, status: { verdict, idleSince, isolation, checkpoint, queued, continuable, awaitingApproval, mergeGate, forcedPastGate, waitsForApproval } };\n}\n\n/**\n * The plan's tasks over what the view already holds: plan fields from the\n * plan, absent meaning none; status-only fields as the stream last said.\n */\nfunction refresh(previous: readonly RunTask[], tasks: readonly SerializedTask[]): RunTask[] {\n const held = new Map([...walkPlan(previous)].map(({ task }) => [task.id, task]));\n const fold = ({ subtasks, ...task }: SerializedTask): RunTask => {\n const was = held.get(task.id);\n const { checkpoint, ...status } = was ? split(was).status : {};\n // The question is answered once the plan says the task no longer waits at it.\n const waits = task.status === 'awaiting_user' && task.awaitingReason === 'checkpoint';\n return { ...task, ...status, ...(waits && checkpoint ? { checkpoint } : {}), subtasks: subtasks.map(fold) };\n };\n return tasks.map(fold);\n}\n\n/** A plan carries the task's wait and usage too, but a status update is the newer word on them. */\nfunction withStatus({ awaitingReason: _reason, resumeAt: _resumeAt, skipReason: _skipped, attemptUsage: _usage, ...plan }: PlanFields, { id: _id, ...status }: SerializedTaskStatus): Omit<RunTask, 'subtasks'> {\n return { ...plan, ...status };\n}\n\n/** A status update says everything about a task's status: what it leaves out, the task no longer has. */\nfunction applyStatus(tasks: readonly RunTask[], updates: ReadonlyMap<string, SerializedTaskStatus>): RunTask[] {\n return tasks.map((task) => {\n const subtasks = applyStatus(task.subtasks, updates);\n const update = updates.get(task.id);\n return update ? { ...withStatus(split(task).plan, update), subtasks } : { ...task, subtasks };\n });\n}\n\n/** `tasks` itself when `change` leaves the task named alone, or no task has that id. */\nfunction changeTask(tasks: RunTask[], taskId: string, change: (task: RunTask) => RunTask): RunTask[] {\n let changed = false;\n const next = tasks.map((task) => {\n const updated = task.id === taskId ? change(task) : task;\n const subtasks = changeTask(updated.subtasks, taskId, change);\n if (updated === task && subtasks === task.subtasks) return task;\n changed = true;\n return { ...updated, subtasks };\n });\n return changed ? next : tasks;\n}\n\nconst PATCHABLE: ReadonlySet<string> = new Set<keyof PlanFields>([\n 'order', 'title', 'type', 'status', 'description', 'dependencies', 'assignedRunner', 'assignedModel', 'taskMode', 'prompt',\n 'userSteps', 'autonomy', 'sliceType', 'userStoriesCovered', 'awaitingReason', 'resumeAt', 'skipReason', 'ops', 'skills', 'addedBy', 'attemptUsage',\n]);\n\nfunction patchTask(task: RunTask, changes: Record<string, unknown>): RunTask {\n const fields = Object.entries(changes).filter(([key]) => PATCHABLE.has(key));\n if (fields.length === 0) return task;\n // The patch is the `Partial<Task>` PlanEditor applied; past the filter, only plan fields remain.\n return { ...task, ...(Object.fromEntries(fields) as Partial<PlanFields>) };\n}\n\nfunction startTask(task: RunTask): RunTask {\n return task.status === 'in_progress' ? task : running(task);\n}\n\nfunction running({ awaitingReason: _reason, resumeAt: _resumeAt, skipReason: _skipped, checkpoint: _checkpoint, ...task }: RunTask): RunTask {\n return { ...task, status: 'in_progress' };\n}\n\nfunction withoutIsolation(tasks: readonly RunTask[]): RunTask[] {\n return tasks.map(({ isolation: _isolation, ...task }) => ({ ...task, subtasks: withoutIsolation(task.subtasks) }));\n}\n\nfunction handoffOf({ type: _type, ...handoff }: Extract<RunInput, { type: 'isolation_handoff' }>): IsolationHandoff {\n return handoff;\n}\n\n/**\n * A saved plan keeps finished tasks in its execution log and the rest pending;\n * rejoined, the log wins for a task in both, being what actually happened.\n */\nfunction planTasks(plan: SurfacePlan | SurfacePlanState): SurfaceTask[] {\n if ('tasks' in plan) return plan.tasks;\n return rejoinPlanTree<SurfaceTask>(plan.pendingTasks, plan.phase === 'executing' ? plan.executionLog : []);\n}\n\nexport function reduceRun(view: RunView, input: RunInput): RunView {\n switch (input.type) {\n case 'plan_generated':\n return { ...view, tasks: refresh(view.tasks, input.plan.tasks), runSettings: input.plan.runSettings };\n case 'plan_snapshot':\n return {\n ...view,\n tasks: refresh(view.tasks, planTasks(input.plan).map(serializeTask)),\n // A saved plan's phase-tagged form has no run settings to say.\n runSettings: 'tasks' in input.plan ? input.plan.runSettings : view.runSettings,\n };\n case 'status_update':\n return {\n ...view,\n tasks: applyStatus(view.tasks, new Map(input.tasks.map((t) => [t.id, t]))),\n runMerge: input.runMerge ?? null,\n usage: input.usage,\n };\n case 'task_started':\n case 'task_updated': {\n const tasks = changeTask(view.tasks, input.taskId, (task) => (input.type === 'task_started' ? startTask(task) : patchTask(task, input.changes)));\n return tasks === view.tasks ? view : { ...view, tasks };\n }\n case 'plan_edit_held':\n return { ...view, heldEdit: input.held ?? undefined };\n case 'isolation_handoff':\n return { ...view, handoff: handoffOf(input) };\n case 'isolation_merge':\n return input.result.outcome === 'merged'\n ? { ...view, mergeResult: input.result, handoff: null, runMerge: null }\n : { ...view, mergeResult: input.result };\n case 'run_closed':\n return { ...view, tasks: withoutIsolation(view.tasks), handoff: null, runMerge: null, mergeResult: null };\n // A checkpoint's whole question and every status `review_needed` implies\n // arrive in the status update that follows; `review_needed`'s own list is\n // flat, so as a plan it would lift subtasks to the top level.\n case 'checkpoint':\n case 'review_needed':\n case 'review_approved':\n case 'execution_complete':\n case 'execution_stopped':\n case 'execution_action':\n case 'task_output':\n case 'task_log':\n case 'isolation_blocked':\n case 'planner_message':\n case 'planner_turn_started':\n case 'planner_skill_loaded':\n case 'planner_turn_ended':\n case 'planner_text_delta':\n case 'planner_thinking_delta':\n case 'planner_text_retracted':\n case 'planner_usage':\n case 'planner_liveness':\n case 'subagent_started':\n case 'subagent_finished':\n case 'research_step':\n case 'research_step_done':\n case 'plan_token':\n case 'approval_request':\n case 'approval_settled':\n case 'approval_decided':\n return view;\n default: {\n // Listed rather than defaulted, so a new message fails to compile until\n // someone decides what it does to a run.\n const unhandled: never = input;\n return unhandled;\n }\n }\n}\n"],"mappings":"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","names":["text","import_uuid","import_uuid","text","oneLine","text","lines","text","text","text","blockIds","answered","id","text","announceTool","parseArgs","settleTool","startSubagent","finishSubagent","reportUsage","requestApproval","settleApproval","decideApproval","endTurn","text","live","MarkdownIt","text"]}
1
+ {"version":3,"sources":["../src/plan-utils.ts","../src/models/Task.ts","../src/conversation/skillTokens.ts","../src/services/PlanTree.ts","../src/services/TaskRefs.ts","../src/services/TaskOps.ts","../src/taskRow/status.ts","../src/services/PlannedTask.ts","../src/services/ModelAllowlistResolver.ts","../src/services/researchStepSummary.ts","../src/conversation/format.ts","../src/services/harness/agentTools.ts","../src/conversation/records.ts","../src/services/blocking.ts","../src/services/SessionMessage.ts","../src/services/conflictFiles.ts","../src/services/runSettingsText.ts","../src/models/Usage.ts","../src/conversation/lanes.ts","../src/conversation/reduce.ts","../src/conversation/transcript.ts","../src/utils/sameMessage.ts","../src/conversation/taskLog.ts","../src/conversation/promptHold.ts","../src/conversation/turnGate.ts","../src/conversation/detail.ts","../src/conversation/notices.ts","../src/conversation/markdown.ts","../src/conversation/taskLogFollow.ts","../src/taskRow/actions.ts","../src/services/AssignmentScope.ts","../src/taskRow/view.ts","../src/taskRow/texts.ts","../src/services/runView.ts"],"sourcesContent":["/**\n * Browser-safe entry point: pure plan-validation utilities with no Node or\n * AI-service dependencies. UI surfaces (the VS Code webview runs in a browser)\n * import runtime values from here instead of the main barrel, which bundles the\n * Gemini/OpenAI services and their `fs`/`child_process` imports.\n */\nexport { canMergeTasks, canSplitTask, canSetDependencies, dependencyCandidates, dependentsOf } from './services/TaskOps';\nexport type { TaskRef } from './services/TaskOps';\nexport { summarizeToolCall } from './services/researchStepSummary';\nexport { truncateCheckpointSummary, CHECKPOINT_TRUNCATE_LENGTH } from './services/SessionMessage';\nexport { capConflictFiles } from './services/conflictFiles';\nexport { blockingFailures, type BlockingSubject } from './services/blocking';\nexport { SUPERVISOR_LEVEL_LABEL, parseCount } from './services/runSettingsText';\n// The shared conversation view (#51) is pure too, so every surface — a webview\n// included — draws from the same reducer.\nexport * from './conversation';\n// The task row view is pure for the same reason: the webview draws a task card\n// from the facts the TUI paints its plan row from.\nexport * from './taskRow';\nexport { taskOrderLabel, taskRef, taskRefOf, titledTaskRef, titledTaskRefOf, resolveTaskRef, resolveUserTaskRef } from './services/TaskRefs';\nexport type { RefTask } from './services/TaskRefs';\n// The one runner default, shared with the webview so its initial state cannot\n// drift from the plans the host builds.\nexport { DEFAULT_RUNNERS, pausedOnLimit } from './models/Task';\n// The run view is pure too: a surface seeds its state from the one empty run\n// rather than re-declaring the shape.\nexport { EMPTY_RUN } from './services/runView';\n\nexport * from './models/Usage';\n\nexport { walkPlan, taskPlacement, subtreeIds } from './services/PlanTree';\nexport type { TreeTask, TaskPlacement } from './services/PlanTree';\n\n// The one rule for the effort a model change keeps, so a surface's model\n// picker lands where core's resolver would.\nexport { clampThinkingEffort } from './services/ModelAllowlistResolver';\n","import { v4 as uuidv4 } from 'uuid';\nimport type { PlanIsolation } from '../interfaces/IWorktreeIsolation';\nimport type { AttemptUsage, PlannerUsage, UsageRecord, UsageTotals } from './Usage';\nimport type { ExecutionRecord, SupervisorLevel } from './Execution';\nimport type { SkillSource } from '../services/SkillsService';\nimport type { SupervisionMemorySnapshot } from '../services/LoopGuards';\nimport type { SupervisorSnapshot } from '../services/Supervisor';\nimport { SKILL_NAME_PATTERN } from '../conversation/skillTokens';\nimport { subtreeIds, walkPlan } from '../services/PlanTree';\n\nexport interface UserStep {\n order: number;\n instruction: string;\n completed: boolean;\n}\n\n/** One deterministic signal gathered while verifying a completed task. `completion_marker` is only in verdicts saved before completion was reported through `task_complete` alone. */\nexport interface VerificationCheck {\n name: 'exit_code' | 'completion_marker' | 'task_complete' | 'manual';\n passed: boolean;\n /** A check that did not apply. Skipped checks don't affect the verdict. */\n skipped: boolean;\n detail: string;\n}\n\n/** Evidence-based verdict for a completed task. Single end-to-end outcome produced by verification. */\nexport interface Verdict {\n outcome: 'pass' | 'fail';\n reason: string;\n checks: VerificationCheck[];\n decidedAt: string;\n}\n\nexport interface TaskOutputSummary {\n reviewReason: string;\n /** The `task_complete` summary, the task's report; absent when the attempt ended without one, and from sessions saved before it was kept. */\n report?: string;\n /** Empty when there is a report: the turn's final text is the report itself. */\n logTail: string;\n capturedAt: string;\n}\n\nexport type TaskType = 'ai' | 'user';\n/**\n * `skipped` is terminal and verdict-less: the task will not be waited for, and\n * nothing it did lands. Its dependents go ahead without it once the work it\n * waited on is done. There is no stored `blocked`: a task is blocked when a\n * failed dependency says so (ADR-0034), and a file that kept the old status\n * loads as pending.\n */\nexport type TaskStatus = 'pending' | 'approved' | 'in_progress' | 'completed' | 'failed' | 'awaiting_user' | 'skipped';\nexport type TaskMode = string;\n\n/**\n * Why an `awaiting_user` task waits (ADR-0018, W1): a structured turn that\n * ended without a `task_complete` call, a checkpoint question, work that did not\n * land, an ops task that changed tracked files (ADR-0020), or its runner's\n * usage limit. Saved, so no surface has to guess it from whether an attempt\n * is live.\n */\nexport type AwaitingReason = 'input' | 'checkpoint' | 'conflict' | 'files-changed' | 'usage-limit';\n\nexport function isAwaitingReason(value: unknown): value is AwaitingReason {\n return value === 'input' || value === 'checkpoint' || value === 'conflict' || value === 'files-changed' || value === 'usage-limit';\n}\n\nexport interface TaskModelAssignment {\n modelId: string;\n modelLabel: string;\n thinkingEffort?: string;\n /**\n * All variant ids the model offered when this assignment was made. Carried\n * on the assignment because runners need it at spawn time (opencode's TUI\n * only honors an assigned variant when the others are config-disabled) and\n * the discovery catalog isn't available there.\n */\n availableVariants?: string[];\n}\n\nexport type RunnerId = string;\n\n/**\n * Bring loaded tasks to the structured-only shape, in place. A task saved\n * while the terminal transport existed may say it ran there, and why; neither\n * means anything now, and such a task left no session to continue. Its\n * completion marker id went with the text markers: completion is reported\n * only through `task_complete`.\n */\nexport function migrateLoadedTasks(tasks: readonly Task[]): void {\n for (const task of tasks) {\n if (typeof task.runnerSessionId !== 'string') delete task.runnerSessionId;\n if (typeof task.carriedFrom !== 'string') delete task.carriedFrom;\n if (typeof task.runnerSessionOwner !== 'string') delete task.runnerSessionOwner;\n const legacy = task as Task & { transport?: { kind?: unknown; nativeSessionId?: unknown } };\n if (!task.runnerSessionId && legacy.transport?.kind === 'structured' && typeof legacy.transport.nativeSessionId === 'string') {\n task.runnerSessionId = legacy.transport.nativeSessionId;\n }\n delete legacy.transport;\n delete (task as { completionMarker?: unknown }).completionMarker;\n // The effort once had a second home on the task; the spawn reads only the model's.\n const effort = (task as { thinkingEffort?: unknown }).thinkingEffort;\n if (typeof effort === 'string' && task.assignedModel && !task.assignedModel.thinkingEffort) task.assignedModel.thinkingEffort = effort;\n delete (task as { thinkingEffort?: unknown }).thinkingEffort;\n migrateLoadedTasks(task.subtasks ?? []);\n }\n}\n\n/**\n * A task skill as one attempt received it: read from the task's own worktree\n * (or global) at spawn, kept so the user can see what the runner was told\n * even after the skill's file changes.\n */\nexport interface TaskSkillSnapshot {\n name: string;\n source: SkillSource;\n path: string;\n content: string;\n}\n\n/** A task skill as a surface is told of it: the body stays in the task's log file and the session. */\nexport type TaskSkillNotice = Omit<TaskSkillSnapshot, 'content'>;\n\nexport interface Task {\n id: string;\n order: number;\n title: string;\n description: string;\n type: TaskType;\n status: TaskStatus;\n dependencies: string[];\n prompt?: string;\n userSteps?: UserStep[];\n subtasks: Task[];\n verdict?: Verdict;\n outputSummary?: TaskOutputSummary;\n assignedModel?: TaskModelAssignment;\n assignedRunner: RunnerId;\n taskMode?: TaskMode;\n autonomy?: 'AFK' | 'HITL';\n sliceType?: 'HITL' | 'AFK';\n userStoriesCovered?: string[];\n /** The runner's saved session for a later continue; cleared when a fresh attempt starts. */\n runnerSessionId?: string;\n /**\n * The runner that session belongs to: a session cannot cross runners, so\n * Continue is offered only while the task is still assigned to it. Absent\n * on a plan saved before it was recorded; the last attempt's runner stands\n * in (see `sessionOwner`).\n */\n runnerSessionOwner?: RunnerId;\n /** Set only while `status` is `awaiting_user`, and not always then — a pause saved by an older build has none. */\n awaitingReason?: AwaitingReason;\n /**\n * When a task paused on its runner's usage limit is resumed on its own (ISO\n * time): the reset the runner announced, plus a short margin. Absent when no\n * reset time could be read or the user cancelled the resume — the task then\n * waits for a manual retry. Set only with `awaitingReason` `usage-limit`.\n */\n resumeAt?: string;\n /**\n * The runner a task paused on its usage limit was moved off (ADR-0018, U1):\n * its next attempt is a carry-over, a fresh session that starts from that\n * attempt's files. Cleared once that attempt runs, and by a retry.\n */\n carriedFrom?: RunnerId;\n /** Why the task was skipped, as whoever skipped it put it; set only while `status` is `skipped`, and not always then. */\n skipReason?: string;\n /**\n * An ops task (ADR-0020): it changes no repository files, runs at the\n * workspace root rather than in a worktree, and waits for the change tasks\n * it depends on to be merged into the user's branch. Top-level AI tasks\n * only; absent means a change task.\n */\n ops?: boolean;\n /**\n * The dependencies, by title, whose work was not merged into the user's\n * branch when the user force-started this task past its merge gate\n * (ADR-0020). Cleared when the task is retried.\n */\n forcedPastGate?: string[];\n /**\n * Task skills (`applies-to: task`) attached by name. Their bodies are put in\n * the runner's prompt at spawn, resolved where the task runs — a subtask's\n * are its own, never its parent's. Absent means none.\n */\n skills?: string[];\n /** The skills the latest attempt was given, as read when it spawned. */\n attemptSkills?: TaskSkillSnapshot[];\n /**\n * Who put the task in the plan, when it was not the user's own planning:\n * `supervisor` for a task an Act supervisor added during a run, which\n * counts as approved to run (ADR-0029). Set by the session, never by an op.\n */\n addedBy?: 'supervisor';\n attemptUsage?: AttemptUsage[];\n}\n\nexport interface DiscoveredMode {\n id: string;\n label: string;\n description: string;\n}\n\nexport type ResearchToolType =\n | 'read_file' | 'read_files' | 'glob' | 'grep' | 'find_symbol' | 'list_dir'\n | 'bash' | 'fetch' | 'web_search' | 'spawn_research_agent'\n | 'task_query' | 'task_output' | 'task_diff'\n /**\n * A tool belonging to a harness planner's own toolbox (ADR-0009) that has no\n * Ordewell equivalent — Edit, WebFetch, TodoWrite, whatever a coding agent\n * ships next. The real name travels in `toolLabel` rather than being\n * relabelled as a tool it is not; the union stays closed so the\n * exhaustiveness checks in every surface's icon/label switch survive.\n */\n | 'agent_tool';\n\n/**\n * What happened when a research tool call ran, for honest per-surface\n * rendering. The broadcast seam carries this on every `research_step_done` so\n * surfaces do not have to pattern-match refusal text to tell a refused `rm`\n * from a successful `rm` — the old render path flipped a `✓` for both.\n */\nexport type ResearchStepOutcome = 'success' | 'failure' | 'refused' | 'denied' | 'not_executed';\n\nexport interface ResearchStep {\n id: string;\n tool: ResearchToolType;\n /** The tool's own name when it came from a harness planner — always set for `agent_tool`. */\n toolLabel?: string;\n args: string;\n result: string;\n success: boolean;\n outcome: ResearchStepOutcome;\n /** The model's tool_call id, so a surface can match `tool_result` to the\n * pending `tool_call` it announced — robust under parallel same-tool rounds. */\n toolCallId?: string;\n /** The research subagent that ran the call, so a reload regroups it under that subagent. */\n subagentId?: string;\n timestamp: string;\n thinkingText?: string;\n}\n\nexport interface UserPromptEntry {\n id: string;\n type: 'user_prompt' | 'system';\n content: string;\n timestamp: string;\n}\n\nexport type SubagentOutcome = 'done' | 'failed' | 'stopped';\n\n/**\n * One subagent's whole run, logged when it finishes: what it was asked, how it\n * ended and what it reported. Its steps stay separate entries carrying the same\n * `subagentId`, so an older reader that knows only steps still shows them.\n */\nexport interface SubagentLogEntry {\n id: string;\n type: 'subagent';\n subagentId: string;\n brief: string;\n model?: string;\n outcome: SubagentOutcome;\n digest: string;\n usage?: UsageTotals;\n timestamp: string;\n}\n\nexport type ResearchLogEntry = ResearchStep | UserPromptEntry | SubagentLogEntry;\n\nexport interface ResearchProgress {\n // 'liveness' carries no content: a raw-line signal from the harness process\n // (ADR-0009) that reaches a surface even when a turn is producing nothing\n // visible — a subagent's filtered chatter, most often — so an idle watchdog\n // downstream doesn't mistake \"nothing to show\" for \"nothing happening\".\n //\n // The turn-scoped kinds below carry one planner turn's stream (#47); see the\n // matching SessionMessage variants for the invariants each one keeps.\n // 'text_delta' is reply text as the model streams it (`text`, `segmentId`),\n // an envelope included: the turn's owner routes each segment to prose or to\n // the plan display, so no backend has to tell them apart. 'text_retracted'\n // takes back an attempt's text: `segmentId`'s, or when absent everything the\n // backend call that sends it has streamed.\n // 'usage' reports one model call (`record`). 'subagent_started' carries\n // `brief` and `model`; 'subagent_finished' carries `outcome`, `digest` and\n // `usage`.\n type:\n | 'thinking' | 'tool_call' | 'tool_result' | 'plan_token' | 'interrupted' | 'liveness'\n | 'text_delta' | 'text_retracted' | 'usage' | 'subagent_started' | 'subagent_finished';\n /** Minted by whoever runs the turn and passed through untouched; absent outside a turn. */\n turnId?: string;\n /** One continuous run of model text — text before a tool call is its own segment. */\n segmentId?: string;\n text?: string;\n tool?: string;\n /** Harness planners (ADR-0009): the agent's own name for a tool Ordewell has no member for. */\n toolLabel?: string;\n toolArgs?: string;\n toolResult?: string;\n planToken?: string;\n step?: ResearchStep;\n /** The model's tool_call id, threaded on tool_call and tool_result so a\n * surface can match the result to its pending call — robust under parallel\n * same-tool rounds where LIFO-by-name matching mislabels summaries. */\n toolCallId?: string;\n /** Present when this event originates from (or reports on) one spawned research subagent (issue #34). */\n subagentId?: string;\n record?: UsageRecord;\n brief?: string;\n model?: string;\n outcome?: SubagentOutcome;\n digest?: string;\n usage?: UsageTotals;\n}\n\nexport interface ThinkingBlock {\n id: string;\n text: string;\n}\n\nexport interface StreamThinkingEvent {\n type: 'thinking';\n block: ThinkingBlock;\n}\n\nexport interface StreamStepEvent {\n type: 'step';\n step: ResearchStep;\n}\n\nexport type StreamEvent = StreamThinkingEvent | StreamStepEvent;\n\nexport interface DiscoveredModel {\n modelId: string;\n modelLabel: string;\n runnerProvider?: string;\n /**\n * Human-facing provider name as the runner itself reports it (e.g.\n * \"OpenCode Zen\" for `runnerProvider: 'opencode'`). Populated from the\n * runner's own provider catalog when available; when absent the UI derives a\n * label from `runnerProvider` by title-casing.\n */\n runnerProviderLabel?: string;\n /**\n * The runner whose catalog listed this model. Stamped once, at the single\n * `ModelDiscovery.discover` choke point, so a flat cross-runner list can\n * still say where each entry came from — `runnerProvider` alone cannot:\n * OpenCode reports most of its catalog as `openrouter`, which names the\n * serving backend, not the agent Ordewell would spawn.\n */\n runnerId?: string;\n /** The runner's display name (`OpenCode`), from its manifest. */\n runnerLabel?: string;\n variants: { id: string; label: string }[];\n /**\n * The model's context window when the runner or catalog reports it (#49).\n * Read by the planner-model lookup so context fill can be shown; absent when\n * unknown rather than defaulted to zero.\n */\n contextWindow?: number;\n}\n\nexport type PlanStatus = 'draft' | 'approved' | 'rejected' | 'running' | 'completed';\n\n/**\n * One entry of the planner's persisted dialogue (ADR-0002). The single source\n * of truth for both UI redisplay and conversational context. Tool-call results\n * are NOT stored here — they live in the AI service's tool-use history;\n * `researchLog` remains the persisted tool trace for the UI.\n */\nexport interface ConversationMessage {\n role: 'user' | 'assistant';\n content: string;\n timestamp: string;\n /**\n * Timeline marker: 'plan_generated' records the point in the dialogue where\n * the plan was committed (the UI anchors the plan card there on restore);\n * 'system' is a host-injected notice; 'compaction' is the summary a\n * user-triggered compaction left in place of the earlier messages — always\n * the transcript's first entry. 'skill_load' is a skill loaded into the\n * conversation, its snapshot in `skill`; one the user invoked follows the\n * message that named it. 'execution' is a call at the command seam\n * (ADR-0029), its record in `execution`. 'wake_up' is the digest a wake-up\n * gave the supervisor (role 'user': the model was told it), and\n * 'supervisor' what the supervisor said in a wake-up turn (ADR-0029).\n * 'error' is a planner turn that ended on the planner's usage limit, drawn\n * as a failure and never replayed to the planner: it is not the planner's\n * answer, and its inputs are sent again (see {@link PlannerResendState}).\n * Absent for ordinary chat turns, so sessions saved before markers existed\n * degrade gracefully.\n */\n kind?: 'plan_generated' | 'system' | 'compaction' | 'skill_load' | 'execution' | 'wake_up' | 'supervisor' | 'error';\n actor?: 'Ordewell setting';\n /** Present exactly when `kind` is 'skill_load'. */\n skill?: SkillLoad;\n /** Present exactly when `kind` is 'execution'. */\n execution?: ExecutionRecord;\n /** A user's message that was force sent, stopping the turn before it (ADR-0023). */\n forced?: true;\n /**\n * What a reply showed, run by run, where each began (ADR-0017 A1). Beside\n * `content`, which stays the reply as the planner is told it. Absent on\n * entries saved before runs were kept, which reload as one message.\n */\n runs?: ReplyRun[];\n}\n\n/**\n * One run of a planner reply's text: the segment it streamed under, its\n * settled text, and when it began. A run that never streamed (a message the\n * conversation wrote in the planner's place) has a segment no stream used.\n */\nexport interface ReplyRun {\n segmentId: string;\n text: string;\n /** ISO timestamp. */\n startedAt: string;\n}\n\n/**\n * A skill's SKILL.md as it was when loaded into a planner conversation. A\n * snapshot rather than a reference: a resumed, forked or rewound conversation\n * replays the body the planner originally saw, even after the file changed or\n * was deleted.\n */\nexport interface SkillLoad {\n invokedBy: 'user' | 'planner';\n name: string;\n source: SkillSource;\n /** The SKILL.md that won, home-abbreviated (`~/...`): which copy loaded is what a reader needs from it. */\n path: string;\n content: string;\n /**\n * Set when the user named a task skill: it is not loaded into the planner's\n * context, which is only told to attach it to the tasks it fits. `content`\n * is empty; the description is what the planner's directive quotes.\n */\n attaches?: { description: string };\n}\n\n/** A skill load as a surface announces it — the body stays with the transcript. */\nexport type SkillLoadNotice = Omit<SkillLoad, 'content'>;\n\n/** A message the user sent, as opposed to a skill load their message caused or a wake-up digest. */\nexport function isUserMessage(entry: Pick<ConversationMessage, 'role' | 'kind'>): boolean {\n return entry.role === 'user' && entry.kind !== 'skill_load' && entry.kind !== 'wake_up';\n}\n\n/** A follow-up an older build queued behind a run's batch boundary; read only to carry it over as a {@link PendingPlanTurn}. */\nexport interface QueuedMessage {\n id: string;\n text: string;\n timestamp: string;\n skills?: SkillLoad[];\n}\n\n/** Who a planner turn answers (ADR-0029): the user's message, or a wake-up batch the supervisor is given. */\nexport type PlanTurnSource = 'user' | 'supervisor';\n\n/**\n * A planner turn's input not yet answered by a turn that ended. It leaves the\n * plan with the change its turn made, in the same save, so a reload replays\n * exactly the inputs no turn answered — once. A supervisor's input is a\n * wake-up batch not yet delivered (ADR-0029): it stays until a turn lands\n * with it, whatever turns fail meanwhile.\n */\nexport interface PendingPlanTurn {\n id: string;\n source: PlanTurnSource;\n /** The user's message, or a wake-up batch's digest. */\n text: string;\n timestamp: string;\n /** What its `/name` tokens loaded when it was sent, so a replay sends the same skills. */\n skills?: SkillLoad[];\n /** Force sent: it waits ahead of every input not forced, and its turn is its own (ADR-0023, F2). */\n forced?: true;\n}\n\n/**\n * The run's own copy of the user's run settings (ADR-0030): taken when the\n * user starts it, changed at once by a change made in this session, and\n * lowered by a tripped guard or a failed supervisor.\n */\nexport interface RunSettings {\n mergeAtGatesAutomatically: boolean;\n /** Absent on a run started before supervisor levels existed: Off. */\n supervisorLevel?: SupervisorLevel;\n /** Absent on a run started before ADR-0030: the user's setting. */\n supervisorRetryLimit?: number;\n /** Absent on a run started before ADR-0030: the user's setting. */\n wakeUpReadBudget?: number;\n /** Why the supervisor stopped for the rest of this run, which carries on as Off; absent while it watches. */\n unsupervised?: string;\n}\n\n/**\n * What supervision remembers across a daemon restart (ADR-0029): the loop\n * guards' memory and the wake-up state not yet delivered with a turn.\n */\nexport interface SupervisionSnapshot {\n /** Retries, failed-attempt shapes, the supervisor's edits and what the user was told. */\n guards?: SupervisionMemorySnapshot;\n /** The events inside their debounce window and the wake-up rate's timestamps. */\n wake?: SupervisorSnapshot;\n}\n\n/**\n * What waits on the planner's usage limit. With `at`, the inputs no turn\n * answered are sent again then, on their own; without it — the reset could\n * not be read, the resend hit the limit again, or it was cancelled — they go\n * with the next input: the user's message, or a wake-up.\n */\nexport interface PlannerResendState {\n /** The runner whose account hit the limit; a planner on another one is not held by it. */\n runner?: RunnerId;\n at?: string;\n}\n\nexport interface LegacyPlanState {\n runSettings?: RunSettings;\n /** What supervision remembers across a daemon restart (ADR-0029); absent on plans saved before it existed. */\n supervision?: SupervisionSnapshot;\n tasks: Task[];\n generatedAt: string;\n status: PlanStatus;\n runners: RunnerId[];\n lastUpdated: string;\n researchLog?: ResearchLogEntry[];\n /** The planner dialogue — user messages and assistant messages, in order (ADR-0002). */\n conversationHistory?: ConversationMessage[];\n /** Full markdown PRD once written by the planner (PRD mode), also saved to .scratch/<slug>/PRD.md. */\n prdMarkdown?: string;\n /** Planner turn inputs no turn has answered yet (ADR-0029); a reload replays them. */\n pendingTurns?: PendingPlanTurn[];\n /** Written by builds that queued mid-run edits; a load moves it into {@link pendingTurns}. */\n queuedMessages?: QueuedMessage[];\n /**\n * The plan's isolation run (ADR-0013), written from the orchestrator at\n * persist time and read back only when a saved plan is adopted. It names\n * branches and worktrees that belong to this plan alone: a fork of the plan\n * must leave it behind rather than share it.\n */\n isolation?: PlanIsolation;\n /** Kept so a reopened session shows the same token line (#49). */\n plannerUsage?: PlannerUsage;\n /** The planner hit its usage limit and the inputs its turn took wait to be sent again; absent otherwise. */\n plannerResend?: PlannerResendState;\n /**\n * The tasks the user approved to run: every task when they executed the\n * plan, and each one they started or retried themselves since. A command\n * from anyone else starts only these (ADR-0029); a task the planner added\n * after the approval waits for the user's. Only tasks still in the plan: a\n * task that leaves takes its approval with it.\n */\n approvedTasks?: string[];\n /**\n * The user approved the plan to run: Execute plan, signing off a review, or\n * autorun's start (ADR-0029, ADR-0030). Kept apart from {@link status},\n * which surfaces rewrite for display; a user's start of one task approves\n * that task, not the plan.\n */\n approved?: boolean;\n}\n\nexport interface Message {\n id: string;\n role: 'user' | 'planner' | 'system';\n content: string;\n timestamp: number;\n}\n\nexport interface TaskSnapshot extends Task {\n completedAt: number;\n verdict?: Verdict;\n retryCount: number;\n finalized: boolean;\n}\n\n/** The plan a surface reads whole carries the approval record, so it can tell which tasks wait for the user (ADR-0035). */\nexport type PlanState = (\n | {\n phase: 'planning';\n history: Message[];\n message: string;\n pendingTasks: Task[];\n }\n | {\n phase: 'executing';\n history: Message[];\n message: string;\n executionLog: TaskSnapshot[];\n pendingTasks: Task[];\n goal: string;\n runners: string[];\n status: PlanStatus;\n }\n) & ApprovalRecord;\n\nfunction hasPhase(raw: unknown): raw is PlanState {\n return typeof raw === 'object' && raw !== null && 'phase' in raw;\n}\n\nfunction hasTasks(raw: unknown): raw is LegacyPlanState {\n return typeof raw === 'object' && raw !== null && 'tasks' in raw && Array.isArray((raw as Record<string, unknown>).tasks);\n}\n\nfunction logEntryToMessage(entry: ResearchLogEntry): Message {\n const timestamp = new Date(entry.timestamp).getTime();\n if (!('type' in entry)) {\n return { id: entry.id, role: 'system', content: JSON.stringify({ tool: entry.tool, args: entry.args, result: entry.result }), timestamp };\n }\n if (entry.type === 'subagent') {\n const { subagentId, brief, outcome, digest } = entry;\n return { id: entry.id, role: 'system', content: JSON.stringify({ subagentId, brief, outcome, digest }), timestamp };\n }\n return { id: entry.id, role: entry.type === 'user_prompt' ? 'user' : 'system', content: entry.content, timestamp };\n}\n\nfunction migrateHistory(raw: LegacyPlanState): Message[] {\n const messages: Message[] = [];\n\n if (raw.researchLog) {\n messages.push(...raw.researchLog.map(logEntryToMessage));\n }\n\n if (raw.queuedMessages) {\n for (const qm of raw.queuedMessages) {\n messages.push({\n id: qm.id,\n role: 'system',\n content: qm.text,\n timestamp: new Date(qm.timestamp).getTime(),\n });\n }\n }\n\n return messages;\n}\n\nexport function migratePlanState(raw: unknown): PlanState {\n if (hasPhase(raw)) return raw;\n\n if (!hasTasks(raw)) {\n return {\n phase: 'planning',\n history: [],\n message: '',\n pendingTasks: [],\n };\n }\n\n const hasExecution = raw.tasks.some(\n (t) => t.status === 'completed' || t.status === 'failed',\n );\n\n const messages = migrateHistory(raw);\n const record = approvalRecordOf(raw);\n\n if (hasExecution) {\n const executionLog: TaskSnapshot[] = raw.tasks\n .filter((t) => t.status === 'completed' || t.status === 'failed')\n .map((t) => ({\n ...t,\n completedAt: new Date(raw.lastUpdated).getTime(),\n verdict: t.verdict,\n retryCount: 0,\n finalized: true,\n }));\n\n const pendingTasks = raw.tasks.filter(\n (t) => t.status !== 'completed' && t.status !== 'failed',\n );\n\n return {\n phase: 'executing',\n history: messages,\n message: '',\n executionLog,\n pendingTasks,\n goal: '',\n runners: raw.runners,\n status: raw.status,\n ...record,\n };\n }\n\n return {\n phase: 'planning',\n history: messages,\n message: '',\n pendingTasks: raw.tasks,\n ...record,\n };\n}\n\nexport { taskOrderLabel, taskRef, taskRefOf, titledTaskRef, titledTaskRefOf, resolveTaskRef, resolveUserTaskRef } from '../services/TaskRefs';\n\nexport function createTask(overrides: Partial<Task> = {}): Task {\n const skills = skillNames(overrides.skills);\n return {\n id: overrides.id ?? uuidv4(),\n order: overrides.order ?? 0,\n title: overrides.title ?? '',\n description: overrides.description ?? '',\n type: overrides.type ?? 'ai',\n status: overrides.status ?? 'pending',\n dependencies: overrides.dependencies ?? [],\n prompt: overrides.prompt,\n userSteps: overrides.userSteps,\n subtasks: overrides.subtasks ?? [],\n verdict: overrides.verdict,\n outputSummary: overrides.outputSummary,\n ...(overrides.attemptUsage ? { attemptUsage: structuredClone(overrides.attemptUsage) } : {}),\n assignedModel: overrides.assignedModel,\n assignedRunner: overrides.assignedRunner ?? DEFAULT_RUNNERS[0],\n taskMode: overrides.taskMode ?? 'build',\n autonomy: overrides.autonomy,\n sliceType: overrides.sliceType,\n userStoriesCovered: overrides.userStoriesCovered,\n ...(opsFlag(overrides.ops, overrides.type) ? { ops: true } : {}),\n ...(skills ? { skills } : {}),\n ...(overrides.addedBy === 'supervisor' ? { addedBy: 'supervisor' as const } : {}),\n };\n}\n\n/**\n * A name a skill can have, lower-cased as `/name` is. Anything else — a path\n * separator, `..` — is joined into a path and could only reach outside the\n * skill dirs.\n */\nconst SKILL_NAME = new RegExp(`^${SKILL_NAME_PATTERN}$`);\n\nexport function isSkillName(name: string): boolean {\n return SKILL_NAME.test(name);\n}\n\n/**\n * The `skills` field as a task stores it, however it arrived: the planner's\n * JSON is untyped. Names are trimmed, lower-cased and deduplicated, and one\n * no skill could have is dropped; none at all is stored absent, so a plan\n * without skills reads exactly as it did before them.\n */\nexport function skillNames(value: unknown): string[] | undefined {\n if (!Array.isArray(value)) return undefined;\n const names = [...new Set(value.filter((v): v is string => typeof v === 'string').map((v) => v.trim().toLowerCase()).filter(isSkillName))];\n return names.length > 0 ? names : undefined;\n}\n\n/**\n * The skills of a task a merge or a split makes from others: what the edit\n * chose when it named any, none when it chose an explicit `[]`, else what the\n * tasks it came from had — a malformed value is not a request to drop them.\n */\nexport function inheritedSkills(chosen: unknown, inherited: readonly string[] | undefined): string[] | undefined {\n if (Array.isArray(chosen) && chosen.length === 0) return undefined;\n return skillNames(chosen) ?? skillNames(inherited);\n}\n\n/**\n * The `ops` flag as a task stores it (ADR-0020), however it arrived. Only a\n * literal `true` on an AI task marks an ops task: the planner's JSON is\n * untyped, and a quoted \"true\" read as ops would move a task out of its\n * worktree. Anything else is a change task, stored absent so saved plans need\n * no migration. Whether the task may be ops at all — a subtask may not — is\n * for whoever knows where it sits: the planner intake refuses it (`checkPlanInvariants`).\n */\nexport function opsFlag(value: unknown, type: Task['type'] = 'ai'): true | undefined {\n return value === true && type === 'ai' ? true : undefined;\n}\n\n/**\n * The flag of a task a merge or a split makes from others: what the edit\n * chose, else ops only when every task it came from was. A merge that takes\n * in a change edits files, so it is a change; a split part runs where its\n * task did.\n */\nexport function inheritedOps(from: readonly Pick<Task, 'ops'>[], chosen?: boolean): boolean {\n return chosen ?? from.every((t) => opsFlag(t.ops) === true);\n}\n\n/**\n * The runner set a plan has until one is chosen. The one runner named outside\n * its declaration on purpose: a default is a product choice that no manifest\n * or connector implies.\n */\nexport const DEFAULT_RUNNERS: readonly RunnerId[] = ['claude-code'];\n\nexport function createEmptyPlan(): LegacyPlanState {\n return {\n tasks: [],\n generatedAt: new Date().toISOString(),\n status: 'draft',\n runners: [...DEFAULT_RUNNERS],\n lastUpdated: new Date().toISOString(),\n };\n}\n\nexport function flattenTasks(tasks: readonly Task[]): Task[] {\n return [...walkPlan(tasks)].map(({ task }) => task);\n}\n\n/**\n * A phase-tagged plan rejoined into its tree. The execution log is flat — a\n * finished subtask is logged on its own as well as inside its parent — and in\n * the order tasks finished, so read as a list it puts subtasks at the top level\n * under orders that clash with real top-level tasks. A task's own entry is the\n * latest word on it: its parent's copy was taken when the parent last changed.\n */\nexport function rejoinPlanTree<T extends { id: string; order: number; subtasks?: T[] }>(pending: readonly T[], log: readonly T[]): T[] {\n const latest = new Map<string, T>();\n for (const task of [...pending, ...log]) latest.set(task.id, task);\n const nested = new Set<string>();\n const markNested = (task: T): void => {\n for (const sub of task.subtasks ?? []) {\n nested.add(sub.id);\n markNested(sub);\n }\n };\n for (const task of latest.values()) markNested(task);\n const rebuild = (task: T): T => {\n const own = latest.get(task.id) ?? task;\n return own.subtasks?.length ? { ...own, subtasks: own.subtasks.map(rebuild) } : own;\n };\n return [...latest.values()].filter((task) => !nested.has(task.id)).map(rebuild).sort((a, b) => a.order - b.order);\n}\n\n/**\n * A flattened task with the parent it hangs under, null for a top-level task,\n * and the path label and reference (`#2.1.3`) `TaskRefs` renders for it.\n */\nexport interface TaskWithParent {\n task: Task;\n parent: Task | null;\n label: string;\n ref: string;\n}\n\nexport function flattenTasksWithParents(tasks: readonly Task[]): TaskWithParent[] {\n return [...walkPlan(tasks)].map(({ task, parent, label }) => ({ task, parent: parent ?? null, label, ref: `#${label}` }));\n}\n\nexport function addTaskToPlan(tasks: readonly Task[], partial: Partial<Task>): Task[] {\n const maxOrder = tasks.reduce((max, t) => Math.max(max, t.order), 0);\n const newTask = createTask({\n ...partial,\n order: partial.order ?? maxOrder + 1,\n status: 'pending',\n });\n return renumberTasks([...tasks, newTask]);\n}\n\nexport function removeTaskFromPlan(tasks: readonly Task[], taskId: string): Task[] {\n const removed = subtreeIds(tasks, taskId);\n const prune = (level: readonly Task[]): Task[] => level\n .filter((t) => !removed.has(t.id))\n .map((t) => ({\n ...t,\n dependencies: t.dependencies.filter((depId) => !removed.has(depId)),\n subtasks: prune(t.subtasks),\n }));\n return renumberTasks(prune(tasks));\n}\n\nexport function updateTaskInPlan(tasks: readonly Task[], taskId: string, changes: Partial<Task>): Task[] {\n return renumberTasks(\n tasks.map((t) => {\n if (t.id === taskId) return { ...t, ...changes, id: t.id };\n return { ...t, subtasks: updateTaskInPlan(t.subtasks, taskId, changes) };\n })\n );\n}\n\nexport function renumberTasks(tasks: readonly Task[]): Task[] {\n return tasks.map((t, i) => ({\n ...t,\n order: i + 1,\n subtasks: renumberTasks(t.subtasks),\n }));\n}\n\n/** A task paused on its runner's usage limit, whether it resumes on its own or waits for the user (#84). */\nexport function pausedOnLimit(task: Readonly<Task>): boolean {\n return task.status === 'awaiting_user' && task.awaitingReason === 'usage-limit';\n}\n\n/** A task paused on a usage limit that resumes on its own when the limit resets (#84). */\nexport function waitsForReset(task: Readonly<Task>): boolean {\n return pausedOnLimit(task) && !!task.resumeAt;\n}\n\n/** The user's approval record, as a plan carries it (ADR-0029). */\nexport type ApprovalRecord = Pick<LegacyPlanState, 'approved' | 'approvedTasks'>;\n\n/** A copy of the plan's approval record, for a plan read whole; a field the plan lacks stays absent. */\nexport function approvalRecordOf(plan: ApprovalRecord): ApprovalRecord {\n return {\n ...(plan.approved !== undefined ? { approved: plan.approved } : {}),\n ...(plan.approvedTasks ? { approvedTasks: [...plan.approvedTasks] } : {}),\n };\n}\n\n/**\n * A task the scheduler leaves for the user (ADR-0035): an AI task not started\n * yet, in a plan they approved, outside their approval record — the planner\n * added it since. It starts once they start it or execute the plan. In a plan\n * they never approved nothing is theirs yet, so nothing is singled out.\n */\nexport function waitsForApproval(task: Pick<Task, 'id' | 'type' | 'status'>, record: ApprovalRecord): boolean {\n return record.approved === true\n && task.type === 'ai'\n && (task.status === 'pending' || task.status === 'approved')\n && !(record.approvedTasks ?? []).includes(task.id);\n}\n\n/**\n * Who put each task of an adopted list in the plan. A task the plan already\n * had keeps its origin, whatever the planner wrote; a new one is the\n * supervisor's when `bySupervisor`, and nobody's in particular otherwise, so\n * no planner can mark its own task as the supervisor's. `added` lists the new\n * tasks, subtasks included.\n */\nexport function stampOrigin(before: readonly Task[], after: readonly Task[], bySupervisor: boolean): { tasks: Task[]; added: string[] } {\n const prior = new Map(flattenTasks([...before]).map((t) => [t.id, t]));\n const added: string[] = [];\n const stamp = (tasks: readonly Task[]): Task[] => tasks.map((t) => {\n const was = prior.get(t.id);\n const origin = was ? was.addedBy : bySupervisor ? 'supervisor' : undefined;\n if (!was) added.push(t.id);\n const stamped: Task = { ...t, subtasks: stamp(t.subtasks ?? []) };\n if (origin) stamped.addedBy = origin;\n else delete stamped.addedBy;\n return stamped;\n });\n return { tasks: stamp(after), added };\n}\n\n/** Done, running, or held for the user: execution state only a runner or the user can change. */\nconst SETTLED_STATUSES: ReadonlySet<TaskStatus> = new Set<TaskStatus>(['completed', 'in_progress', 'awaiting_user']);\n\nfunction holdsSettledWork(task: Task): boolean {\n return SETTLED_STATUSES.has(task.status) || (task.subtasks ?? []).some(holdsSettledWork);\n}\n\n/**\n * Lay a planner-written task list over the plan it rewrites without letting it\n * change execution state. A planner restates tasks; it never witnessed one run,\n * so the status it writes is not evidence. A settled task is kept exactly as\n * it stands wherever the rewrite names it, and put back beside its old\n * neighbour where the rewrite leaves it out. Every other task keeps the status\n * it had; a task the rewrite adds starts pending.\n */\nexport function keepExecutionState(current: readonly Task[], rewrite: Task[]): Task[] {\n const existing = new Map(flattenTasks(current).map((t) => [t.id, t]));\n const named = new Set(flattenTasks(rewrite).map((t) => t.id));\n\n const overlay = (tasks: Task[], was: readonly Task[]): Task[] => {\n const result = tasks.map((t): Task => {\n const prior = existing.get(t.id);\n if (prior && SETTLED_STATUSES.has(prior.status)) return { ...prior };\n return {\n ...t,\n status: prior?.status ?? 'pending',\n skipReason: prior?.skipReason,\n verdict: prior?.verdict,\n outputSummary: prior?.outputSummary,\n runnerSessionId: prior?.runnerSessionId,\n runnerSessionOwner: prior?.runnerSessionOwner,\n carriedFrom: prior?.carriedFrom,\n attemptSkills: prior?.attemptSkills,\n attemptUsage: prior?.attemptUsage,\n // Where a task that has run ran is fixed, like its runner session (ADR-0020).\n ...(prior?.status === 'failed' ? { ops: prior.ops } : {}),\n forcedPastGate: prior?.forcedPastGate,\n subtasks: overlay(t.subtasks ?? [], prior?.subtasks ?? []),\n };\n });\n was.forEach((left, i) => {\n if (named.has(left.id) || !holdsSettledWork(left)) return;\n const neighbour = was.slice(0, i).reverse().find((t) => result.some((r) => r.id === t.id));\n const at = neighbour ? result.findIndex((r) => r.id === neighbour.id) + 1 : 0;\n result.splice(at, 0, { ...left });\n });\n return result;\n };\n\n return renumberTasks(overlay(rewrite, current));\n}\n","/** A name a skill can have, lower-cased: the one pattern for a `/name` token and for a skill folder. */\nexport const SKILL_NAME_PATTERN = '[a-z0-9][a-z0-9_-]*';\n\n/**\n * A `/skill-name` token anywhere in a message: whitespace (or string start)\n * before it, a skill name in any case, optional trailing punctuation that\n * isn't part of the name, then whitespace (or string end). The punctuation\n * group is what lets \"/grilling,\" name \"grilling\".\n */\nconst SKILL_TOKEN = new RegExp(`(^|\\\\s)\\\\/(${SKILL_NAME_PATTERN})([,.!?;:]*)(?=\\\\s|$)`, 'gi');\n\n/** Where a skill name is invoked: `start` is its `/`, `end` is just past the name, before any punctuation. */\nexport interface SkillToken {\n name: string;\n start: number;\n end: number;\n}\n\n/**\n * The first `/name` token for each name in `text`, names lower-cased. Only\n * the first counts because a skill loads once per message however often it is\n * named, so a later repeat is plain text.\n */\nexport function skillTokens(text: string): SkillToken[] {\n const tokens: SkillToken[] = [];\n const seen = new Set<string>();\n for (const match of text.matchAll(SKILL_TOKEN)) {\n const name = match[2].toLowerCase();\n if (seen.has(name)) continue;\n seen.add(name);\n const start = match.index + match[1].length;\n tokens.push({ name, start, end: start + 1 + match[2].length });\n }\n return tokens;\n}\n\n/** The tokens in a sent message that loaded one of `loaded` — what a surface highlights in the user's bubble. */\nexport function loadedSkillTokens(text: string, loaded: readonly string[]): SkillToken[] {\n return skillTokens(text).filter((t) => loaded.includes(t.name));\n}\n","/** Plan placement and dependency rules, shared with browser-bundled surfaces. */\nexport interface TreeTask<T> {\n id: string;\n order: number;\n title: string;\n subtasks?: readonly T[];\n}\n\nexport interface DependencyTask<T> extends TreeTask<T> {\n dependencies: readonly string[];\n}\n\nexport interface TaskPlacement<T> {\n task: T;\n parent?: T;\n ancestors: readonly T[];\n siblings: readonly T[];\n label: string;\n}\n\nexport function* walkPlan<T extends TreeTask<T>>(tasks: readonly T[]): Generator<TaskPlacement<T>> {\n function* walk(level: readonly T[], ancestors: readonly T[], parentLabel?: string): Generator<TaskPlacement<T>> {\n for (const task of level) {\n const label = parentLabel ? `${parentLabel}.${task.order}` : String(task.order);\n yield { task, parent: ancestors.at(-1), ancestors, siblings: level, label };\n yield* walk(task.subtasks ?? [], [...ancestors, task], label);\n }\n }\n yield* walk(tasks, []);\n}\n\nexport function taskPlacement<T extends TreeTask<T>>(tasks: readonly T[], id: string): TaskPlacement<T> | undefined {\n for (const row of walkPlan(tasks)) if (row.task.id === id) return row;\n return undefined;\n}\n\n/** Includes the root: deletion has to detach every edge into the removed tree. */\nexport function subtreeIds<T extends TreeTask<T>>(tasks: readonly T[], id: string): Set<string> {\n const found = taskPlacement(tasks, id);\n return new Set(found ? [...walkPlan([found.task])].map(({ task }) => task.id) : []);\n}\n\n/** Pickers offer earlier siblings; API validity is independent of display order. */\nexport function dependencyCandidates<T extends TreeTask<T>>(tasks: readonly T[], taskId?: string): T[] {\n if (!taskId) return [...tasks];\n const found = taskPlacement(tasks, taskId);\n return found ? found.siblings.filter((t) => t.order < found.task.order) : [];\n}\n\n/** The surviving tasks whose dependency lists a subtree removal will change. */\nexport function dependentsOf<T extends DependencyTask<T>>(tasks: readonly T[], taskId: string): T[] {\n const removed = subtreeIds(tasks, taskId);\n return [...walkPlan(tasks)].map(({ task }) => task)\n .filter((t) => !removed.has(t.id) && t.dependencies.some((id) => removed.has(id)));\n}\n\nexport interface DependencyCheck { ok: boolean; error?: string }\n\n/** Target restrictions, separate from cycles so a planner batch can check its final graph. */\nexport function dependencyTargetErrors<T extends TreeTask<T>>(\n tasks: readonly T[], taskId: string, dependencies: readonly string[],\n): string[] {\n const found = taskPlacement(tasks, taskId);\n if (!found) return ['Task not found'];\n const descendants = subtreeIds(tasks, taskId);\n const errors: string[] = [];\n for (const dep of dependencies) {\n if (dep === taskId) { errors.push(`\"${found.task.title}\" cannot depend on itself`); continue; }\n const target = taskPlacement(tasks, dep)?.task;\n if (!target) { errors.push(`Unknown dependency \"${dep}\"`); continue; }\n if (found.ancestors.some((t) => t.id === dep) || descendants.has(dep)) {\n errors.push(`\"${found.task.title}\" cannot depend on \"${target.title}\", its ancestor or descendant`);\n }\n }\n return errors;\n}\n\n/** The tasks on one dependency cycle, in dependency order, or null. */\nexport function findDependencyCycle<T extends DependencyTask<T>>(tasks: readonly T[]): T[] | null {\n const byId = new Map([...walkPlan(tasks)].map(({ task }) => [task.id, task]));\n const path: string[] = [];\n const done = new Set<string>();\n const visit = (id: string): string[] | null => {\n if (done.has(id)) return null;\n const at = path.indexOf(id);\n if (at >= 0) return path.slice(at);\n path.push(id);\n for (const dep of byId.get(id)?.dependencies ?? []) {\n const hit = visit(dep);\n if (hit) return hit;\n }\n path.pop();\n done.add(id);\n return null;\n };\n for (const id of byId.keys()) {\n const hit = visit(id);\n if (hit) return hit.map((key) => byId.get(key)!);\n }\n return null;\n}\n\nexport function canSetDependencies<T extends DependencyTask<T>>(\n tasks: readonly T[], taskId: string, dependencies: readonly string[],\n): DependencyCheck {\n const [error] = dependencyTargetErrors(tasks, taskId, dependencies);\n if (error) return { ok: false, error };\n const replace = (level: readonly T[]): T[] => level.map((t) => ({\n ...t,\n dependencies: t.id === taskId ? dependencies : t.dependencies,\n subtasks: replace(t.subtasks ?? []),\n }));\n const cycle = findDependencyCycle(replace(tasks));\n return cycle\n ? { ok: false, error: `Dependency cycle detected: ${[...cycle, cycle[0]].map((t) => `\"${t.title}\"`).join(' → ')}` }\n : { ok: true };\n}\n","import { taskPlacement, walkPlan, type TreeTask } from './PlanTree';\n\n/**\n * Task references: the one grammar for naming a task in a plan, both ways.\n * A label is rendered from a task's order under its parent (\"2\", \"2.1\"), and\n * a reference written by anyone — the planner, a tool call, a command — is\n * resolved back against the plan tree. Pure so a\n * browser-bundled surface can use it through `@ordewell/core/plan-utils`.\n */\n\n/** The shape a reference resolves over: the plan's task tree, or a surface's projection of it. */\nexport type RefTask<T> = TreeTask<T>;\n\n/**\n * The parent a label extends. A label is the full path (\"3.2.1\"), so a parent\n * below the top level carries the label it was itself reached by; without one\n * the parent's order stands for it, which is right for a top-level parent.\n */\nexport interface RefParent {\n order: number;\n label?: string;\n}\n\n/** Dotted path label for a task, e.g. \"2.1\" for the first subtask of task 2, \"2.1.3\" one level down. */\nexport function taskOrderLabel(task: { order: number }, parent?: RefParent): string {\n return parent ? `${parent.label ?? parent.order}.${task.order}` : String(task.order);\n}\n\n/** How a surface refers to a task in prose: \"#2\", or \"#2.1\" for a subtask. */\nexport function taskRef(task: { order: number }, parent?: RefParent): string {\n return `#${taskOrderLabel(task, parent)}`;\n}\n\n/** A task named in full, as a confirmation or a picker title does: \"#2 Deploy\". */\nexport function titledTaskRef(task: { order: number; title: string }, parent?: RefParent): string {\n return `${taskRef(task, parent)} ${task.title}`;\n}\n\n/** A task found in a plan tree, with its parent and the full path label its reference extends. */\nexport interface RefTaskMatch<T> {\n task: T;\n parent?: T;\n label: string;\n}\n\n/** The task a plan tree holds, by id, with its parent; undefined when the tree holds none. */\nexport function findTaskRef<T extends RefTask<T>>(tasks: readonly T[], id: string): RefTaskMatch<T> | undefined {\n return taskPlacement(tasks, id);\n}\n\n/**\n * The reference {@link taskRef} renders for the task a plan tree holds, by id\n * — its full path, dotted, for a subtask. Undefined when the tree holds no such task.\n */\nexport function taskRefOf<T extends RefTask<T>>(tasks: readonly T[], id: string): string | undefined {\n const found = findTaskRef(tasks, id);\n return found && `#${found.label}`;\n}\n\n/**\n * The reference and title {@link titledTaskRef} renders for the task a plan\n * tree holds, by id — its full path, dotted, for a subtask. Undefined when the\n * tree holds no such task.\n */\nexport function titledTaskRefOf<T extends RefTask<T>>(tasks: readonly T[], id: string): string | undefined {\n const found = findTaskRef(tasks, id);\n return found && `#${found.label} ${found.task.title}`;\n}\n\n/**\n * Resolve a written reference to a task at any depth: an id, then an order\n * label with or without \"#\" (\"#2\", \"2\", \"#2.1\"), then an exact title.\n *\n * An order label is read against the tree, never a flattened list: subtask\n * orders restart at 1 under each parent, so \"#2\" always means top-level task 2\n * and a subtask is reachable only by its dotted path (\"#2.1\", \"#2.1.3\").\n */\nexport function resolveTaskRef<T extends RefTask<T>>(tasks: readonly T[], ref: string | number): T | undefined {\n const s = String(ref).trim();\n if (!s) return undefined;\n for (const { task } of walkPlan(tasks)) if (task.id === s) return task;\n const label = s.startsWith('#') ? s.slice(1) : s;\n if (/^\\d+(\\.\\d+)*$/.test(label)) {\n let level: readonly T[] | undefined = tasks;\n let found: T | undefined;\n for (const order of label.split('.').map(Number)) {\n found = level?.find((t) => t.order === order);\n level = found?.subtasks;\n }\n return found;\n }\n for (const { task } of walkPlan(tasks)) if (task.title === s) return task;\n return undefined;\n}\n\n/**\n * A reference as the user types one: {@link resolveTaskRef}, then a unique\n * prefix of a task's id at any depth. Only the user's: a model's reference\n * that names no task is refused, never matched to the one task a fragment of\n * it happens to fit.\n */\nexport function resolveUserTaskRef<T extends RefTask<T>>(tasks: readonly T[], ref: string | number): T | undefined {\n const found = resolveTaskRef(tasks, ref);\n if (found) return found;\n const prefix = String(ref).trim();\n const matches = prefix ? [...walkPlan(tasks)].filter(({ task }) => task.id.startsWith(prefix)) : [];\n return matches.length === 1 ? matches[0].task : undefined;\n}\n","import {\n Task, RunnerId, flattenTasks,\n addTaskToPlan, removeTaskFromPlan, updateTaskInPlan, renumberTasks,\n opsFlag, inheritedOps, skillNames,\n} from '../models/Task';\nimport { v4 as uuidv4 } from 'uuid';\nimport { resolveTaskRef } from './TaskRefs';\nimport { taskPlacement } from './PlanTree';\nimport { extractObjectsWithKey, stripTrailingCommas, escapeControlCharsInStrings, PlanParseError, TASK_OPS_ENVELOPE_KEY } from './JsonExtractor';\nimport { validateTaskEdit, lockedTaskRefusal, type TaskEditActor, type TaskEditCheck } from './TaskEditValidator';\nimport { resolveAssignment, type AssignmentAdjustment, type AssignmentCatalog } from './TaskAssignment';\nimport { plannedTask, checkPlanInvariants, detectCycle, taskWhere, MODE_NOT_THE_PLANNERS, MANUAL_NOT_READ_ONLY, OPS_NOT_READ_ONLY, type IntakeCatalog, type PlannedTask, type PlanTaskError } from './PlannedTask';\nimport { taggedReadOnlyMode } from './ModeResolver';\n\n/**\n * Targeted task edits emitted by the planner conversation (the 'task_ops'\n * ConversationTurn). Task references accept a task id, a \"#<order>\" ref, or a\n * bare order number — cheap models rarely echo UUIDs correctly.\n */\n/**\n * A task as the planner writes it: its fields, less the mode, plus whether it\n * must not change files (ADR-0031), and `thinkingEffort` as a name for its\n * model's effort, so an effort can change without restating the model.\n */\nexport type PlannerTaskSpec = Partial<Task> & { readOnly?: boolean; thinkingEffort?: string | null };\n\nexport type TaskOp =\n | { op: 'update'; taskId: string; changes: PlannerTaskSpec }\n | { op: 'add'; task: PlannerTaskSpec; handle?: string }\n | { op: 'remove'; taskId: string }\n | { op: 'reorder'; taskIds: string[] }\n | { op: 'merge'; taskIds: string[]; merged: PlannerTaskSpec; handle?: string }\n | { op: 'split'; taskId: string; parts: PlannerTaskSpec[]; handle?: string }\n | { op: 'rearm'; taskId: string; changes?: PlannerTaskSpec };\n\n/** Fields the planner may change on an existing task. Everything else (id, status, verdict…) is system-owned. */\nexport const UPDATABLE_FIELDS: (keyof Task)[] = [\n 'title', 'description', 'prompt', 'dependencies', 'assignedRunner', 'assignedModel', 'taskMode', 'type', 'userSteps', 'autonomy', 'sliceType', 'ops', 'skills',\n];\n\n/**\n * The edit protocol as the planner reads it, kept beside the applier so the\n * prose can never undersell (or oversell) what {@link applyTaskOps} accepts.\n * `executionNote` rides on the ordering rule because that is the rule a\n * running execution changes.\n */\nexport function taskOpsProtocol(executionNote = '', tools = false): string[] {\n const updateChanges = [...UPDATABLE_FIELDS.filter((f) => f !== 'taskMode'), 'thinkingEffort', 'readOnly']\n .map((f) => (f === 'dependencies' ? '\"dependencies\"?:[\"<id or #order>\"]' : `\"${f}\"?`))\n .join(',');\n return [\n tools ? '- To modify specific tasks, call edit_plan, never a JSON reply. Its argument is:' : '- To modify specific tasks, reply with ONLY this JSON object:',\n tools ? ' {\"ops\": [' : ' {\"taskOps\": [',\n ` {\"op\":\"update\",\"taskId\":\"<id or #order>\",\"changes\":{${updateChanges}}},`,\n ' {\"op\":\"add\",\"task\":{\"title\",\"description\",\"prompt\",\"dependencies\":[\"<id or #order>\"],\"assignedRunner\"?,\"assignedModel\"?,\"readOnly\"?,\"ops\"?},\"handle\"?:\"<name>\"},',\n ' {\"op\":\"remove\",\"taskId\":\"<id or #order>\"},',\n ' {\"op\":\"reorder\",\"taskIds\":[\"<id or #order>\", \"... every task exactly once\"]}, // only to re-prioritise INDEPENDENT tasks',\n ' {\"op\":\"merge\",\"taskIds\":[\"<id or #order>\", \"...\"],\"merged\":{\"title\",\"description\",\"prompt\"?,\"assignedRunner\"?,\"assignedModel\"?,...},\"handle\"?:\"<name>\"},',\n ' {\"op\":\"split\",\"taskId\":\"<id or #order>\",\"parts\":[{\"title\",\"description\",\"prompt\"?,\"assignedRunner\"?,\"assignedModel\"?,...}, ...],\"handle\"?:\"<name>\"},',\n ` {\"op\":\"rearm\",\"taskId\":\"<id or #order>\",\"changes\"?:{${updateChanges}}}`,\n ' ]}',\n tools ? '- For sweeping changes, you may instead call submit_plan with the full plan.' : '- For sweeping changes, you may instead emit a full {\"tasks\":[...]} plan JSON.',\n 'Every \"<id or #order>\" ref in a batch resolves against the plan shown above, before any op in the batch runs — an earlier remove/merge/split never shifts what a later \"#N\" means. \"#N\" is top-level task N; a subtask is named by its dotted label (\"#2.1\"), as the plan lists it.',\n 'Give \"add\", \"merge\", or \"split\" a \"handle\" (any name you choose, unused elsewhere in this batch) to let a LATER op in the same batch reference the task it produces — for \"split\", the handle names its last part. A handle used before its defining op is rejected.',\n `When creating or changing tasks, set \"assignedRunner\" and \"assignedModel\" ({\"modelId\",\"modelLabel\",\"thinkingEffort\"?}) using only the runners and models ${tools ? 'list_runners and list_models return' : 'listed in <available_models>'}.`,\n 'Set \"readOnly\": true on a task that must not change any file, never on one that must run commands (tests, scripts, builds) or an ops task, and \"readOnly\": false to lift it; you never set \"taskMode\". A task you move, split or edit keeps being read-only or not unless you say otherwise, and so do the subtasks of a read-only task you add.',\n 'Keep dependencies consistent: no cycles, no references to removed tasks, and never touch running or completed tasks — \"rearm\" is the one exception, below.',\n ...(tools ? ['edit_plan checks the batch when you call it and answers with what it will change, or with the error to fix — call it again in the same reply. The edit is applied when your reply ends; edits you make in one reply join one batch.'] : []),\n 'Just declare the dependencies you want — display order is repaired for you afterwards, so a rewire or a newly added prerequisite never needs a \"reorder\" op. Only a task that is running or completed cannot be shifted, so an edit that would need one to move is rejected.' + executionNote,\n 'Flipping \"type\" between \"ai\" and \"user\" is a content change, not just a label: an update to \"user\" needs \"userSteps\" in the SAME op, and an update to \"ai\" needs \"prompt\" in the SAME op — the model/mode/effort/autonomy fields (flipping to \"user\", which also makes the task HITL) or the userSteps (flipping to \"ai\") are cleared automatically.',\n '\"skills\" in \"changes\" REPLACES the task\\'s whole skill list. To add one, send the names the plan block shows in its skills:[...] plus the new one; to drop one, send the rest; [] removes them all.',\n '\"rearm\" puts a failed OR completed task back to pending — verdict and output summary are cleared, any dependents it had blocked are released, and it may carry field changes (e.g. a corrected \"prompt\") applied in the same op. A running task cannot be re-armed. Never rearm a task just to relabel it — only when it should actually run again.',\n ];\n}\n\nexport function textHasTaskOps(text: string): boolean {\n return text.includes(`\"${TASK_OPS_ENVELOPE_KEY}\"`);\n}\n\n/** Parse a `{\"taskOps\":[...]}` reply. Throws PlanParseError when the JSON is unusable. */\nexport function parseTaskOpsJson(text: string): TaskOp[] {\n // Extract by the taskOps key specifically — a reply may also carry a\n // tasks-keyed object (schema echo, example), which must not shadow the ops.\n // Candidates are tried back to front: the last emission is the final answer.\n const { matches, fallback } = extractObjectsWithKey(text, TASK_OPS_ENVELOPE_KEY);\n const candidates = matches.length > 0 ? [...matches].reverse() : [fallback.json];\n\n let lastError: PlanParseError | null = null;\n for (const json of candidates) {\n try {\n return parseTaskOpsObject(json, text);\n } catch (err) {\n if (!(err instanceof PlanParseError)) throw err;\n if (!lastError) lastError = err;\n }\n }\n throw lastError ?? new PlanParseError('No JSON object found in task-ops reply', text);\n}\n\nfunction parseTaskOpsObject(json: string, text: string): TaskOp[] {\n let parsed: unknown;\n try {\n parsed = JSON.parse(escapeControlCharsInStrings(stripTrailingCommas(json)));\n } catch (err) {\n throw new PlanParseError(`Task-ops JSON is invalid: ${err instanceof Error ? err.message : String(err)}`, text);\n }\n const ops = (parsed as { taskOps?: unknown }).taskOps;\n if (!Array.isArray(ops) || ops.length === 0) {\n throw new PlanParseError('\"taskOps\" must be a non-empty array', text);\n }\n for (const op of ops) {\n if (typeof op !== 'object' || op === null || typeof (op as { op?: unknown }).op !== 'string') {\n throw new PlanParseError('Every task op needs an \"op\" field (update | add | remove | reorder | merge | split)', text);\n }\n }\n return ops as TaskOp[];\n}\n\ntype RefResolution = { id: string } | { error: string };\n\n/**\n * Resolve an op's task reference to a task id: a batch handle, or anything\n * {@link resolveTaskRef} reads.\n *\n * Order labels and title matches are pinned to `originalTree` — the plan as it\n * stood before the batch began — so an earlier op's renumbering can never\n * make a later op's \"#4\" land on a different task than the planner saw. A\n * literal id has no such drift (ids are stable across mutations), so id\n * matches check `liveTree` — the batch's current, mutated tasks — which is\n * also how a later op reaches a task created earlier in the same batch\n * without a handle (e.g. a split's own chained parts).\n */\nfunction resolveRef(\n ref: unknown,\n originalTree: readonly Task[],\n liveTree: Task[],\n handleOwner: Map<string, number>,\n handleId: Map<string, string>,\n opIndex: number,\n): RefResolution {\n if (typeof ref !== 'string' && typeof ref !== 'number') return { error: `invalid reference \"${String(ref)}\"` };\n const s = String(ref).trim();\n\n const ownerIdx = handleOwner.get(s);\n if (ownerIdx !== undefined) {\n if (ownerIdx >= opIndex) {\n return { error: `handle \"${s}\" is defined by a later op in this batch and cannot be referenced yet` };\n }\n const id = handleId.get(s);\n if (!id) return { error: `handle \"${s}\" was never resolved` };\n return { id };\n }\n\n if (findInTasks(liveTree, s)) return { id: s };\n const task = resolveTaskRef(originalTree, s);\n return task ? { id: task.id } : { error: `task \"${s}\" not found` };\n}\n\n/** The fields of a planner's `changes` it may set, with the ops flag read as every entry point reads it. */\nfunction updatableChanges(raw: Partial<Task> | undefined): Partial<Task> {\n const changes: Partial<Task> = {};\n for (const key of UPDATABLE_FIELDS) {\n if (raw && key in raw) (changes as Record<string, unknown>)[key] = (raw as Record<string, unknown>)[key];\n }\n if ('ops' in changes) changes.ops = opsFlag(changes.ops);\n if ('skills' in changes) changes.skills = skillNames(changes.skills);\n return changes;\n}\n\nfunction findInTasks(tasks: readonly Task[], id: string): Task | undefined {\n return taskPlacement(tasks, id)?.task;\n}\n\nfunction findTopLevel(tasks: Task[], id: string): Task | undefined {\n return tasks.find((t) => t.id === id);\n}\n\n/** A task the repair may not reposition: execution has already reached it. */\nfunction isPinned(t: Task): boolean {\n return t.status === 'in_progress' || t.status === 'completed';\n}\n\n/** The first task in `parent`'s subtree execution has reached, if any: removing the parent would take it (ADR-0029). */\nfunction lockedInSubtree(parent: Task): string | null {\n for (const sub of parent.subtasks ?? []) {\n const locked = lockedTaskRefusal(sub, 'removed') ?? lockedInSubtree(sub);\n if (locked) return locked;\n }\n return null;\n}\n\n/**\n * Reorder top-level tasks so every dependency comes before its dependents,\n * moving as little as possible: pinned tasks keep the exact slot they are in,\n * and each free slot goes to the earliest-listed movable task whose\n * dependencies are already placed — so tasks the graph does not constrain keep\n * their relative order. Assumes an acyclic graph (the caller checks first).\n */\nfunction repairOrder(tasks: Task[]): { tasks: Task[] } | { error: string } {\n const byId = new Map(tasks.map((t) => [t.id, t]));\n const placed = new Set<string>();\n const movable = tasks.filter((t) => !isPinned(t));\n const result: Task[] = [];\n // Dependencies outside this list (a subtask id) constrain nothing here.\n const blockerOf = (t: Task): Task | undefined => {\n const id = t.dependencies.find((d) => byId.has(d) && !placed.has(d));\n return id ? byId.get(id) : undefined;\n };\n const place = (t: Task) => { result.push(t); placed.add(t.id); };\n\n for (const occupant of tasks) {\n if (isPinned(occupant)) {\n const blocker = blockerOf(occupant);\n if (blocker) return { error: pinnedRefusal(blocker, occupant, 'before') };\n place(occupant);\n continue;\n }\n const next = movable.findIndex((t) => !blockerOf(t));\n if (next < 0) {\n // Nothing is schedulable and the graph is acyclic, so every movable task\n // left waits — directly or through others — on a pinned task further down\n // that would have to come up to free this slot.\n const [stuck, pin] = trailToPin(movable[0], blockerOf);\n return { error: pinnedRefusal(stuck, pin, 'after') };\n }\n place(movable.splice(next, 1)[0]);\n }\n return { tasks: result };\n}\n\n/** Walk the waiting-on chain from `task` down to the pinned task holding it up. */\nfunction trailToPin(task: Task, blockerOf: (t: Task) => Task | undefined): [Task, Task] {\n let at = task;\n for (;;) {\n const blocker = blockerOf(at);\n if (!blocker || isPinned(blocker)) return [at, blocker ?? at];\n at = blocker;\n }\n}\n\n/** `\"B\" #2→#1, \"A\" #1→#3` for every task the repair actually moved, or null. */\nfunction describeMoves(before: Task[], after: Task[]): string | null {\n const wasAt = new Map(before.map((t, i) => [t.id, i + 1]));\n const moved = after\n .map((t, i) => ({ t, from: wasAt.get(t.id)!, to: i + 1 }))\n .filter((m) => m.from !== m.to);\n return moved.length ? moved.map((m) => `\"${m.t.title}\" #${m.from}→#${m.to}`).join(', ') : null;\n}\n\nfunction pinnedRefusal(other: Task, pin: Task, side: 'before' | 'after'): string {\n const word = pin.status === 'in_progress' ? 'running' : 'completed';\n return `\"${other.title}\" would have to run ${side} \"${pin.title}\", which is ${word} and cannot be moved`;\n}\n\nexport interface ApplyTaskOpsResult {\n ok: boolean;\n tasks: readonly Task[];\n errors: string[];\n /** Human-readable summary of what changed, for the chat transcript. */\n summary: string[];\n /** On ok, what the batch's tasks were adjusted to beyond what the planner wrote, as they stand at its end. */\n adjustments?: AssignmentAdjustment[];\n /** On ok, the id of the task each batch handle names. */\n handles?: ReadonlyMap<string, string>;\n}\n\n/**\n * Pre-flight check for a merge: would collapsing the selected tasks into one\n * (rewiring every dependent of any selected task to the survivor) keep the\n * dependency graph valid? Rejects locked tasks and merges whose rewiring would\n * introduce a cycle. Display order is NOT checked here — neither\n * consecutiveness (a UI concern) nor a dependency the merge pulls out of order,\n * which {@link applyTaskOps} repairs; refusing on order would make this\n * pre-flight stricter than the applier it stands in for.\n */\nexport function canMergeTasks(tasks: readonly Task[], selectedIds: string[]): { ok: boolean; error?: string } {\n if (selectedIds.length < 2) return { ok: false, error: 'Select at least two tasks to merge' };\n const idSet = new Set(selectedIds);\n const toMerge = tasks.filter((t) => idSet.has(t.id));\n if (toMerge.length < 2) return { ok: false, error: 'At least two valid tasks are required to merge' };\n for (const t of toMerge) {\n if (t.status === 'in_progress') return { ok: false, error: `\"${t.title}\" is running and cannot be merged` };\n if (t.status === 'completed') return { ok: false, error: `\"${t.title}\" is completed and cannot be merged` };\n }\n const ordered = [...toMerge].sort((a, b) => a.order - b.order);\n const survivorId = '__merge_sim__';\n const sim: Task[] = tasks\n .filter((t) => !idSet.has(t.id))\n .map((t) => ({ ...t, dependencies: t.dependencies.map((d) => (idSet.has(d) ? survivorId : d)).filter((d) => d !== t.id) }));\n const unionDeps = [...new Set(toMerge.flatMap((t) => t.dependencies))].filter((d) => !idSet.has(d));\n sim.push({ ...ordered[0], id: survivorId, title: '__merge_sim__', order: ordered[0].order, dependencies: unionDeps });\n const cycle = detectCycle(sim);\n if (cycle) return { ok: false, error: `Merging would create a dependency cycle involving \"${cycle}\"` };\n return { ok: true };\n}\n\n/**\n * The shape the dependency helpers below read. Structural rather than `Task`,\n * because the TUI projects tasks into its own `TaskView`: a surface's\n * dependency picker and the API's validation must agree on which dependencies\n * are legal, and a signature only core can satisfy would have forced the TUI\n * to keep a second copy of the rule.\n */\nexport interface TaskRef {\n id: string;\n order: number;\n title: string;\n dependencies: string[];\n}\n\nexport { dependencyCandidates, canSetDependencies, dependentsOf } from './PlanTree';\n\n/** Pre-flight check for a split: the task exists and is not locked by execution. */\nexport function canSplitTask(tasks: readonly Task[], taskId: string): { ok: boolean; error?: string } {\n const target = tasks.find((t) => t.id === taskId);\n if (!target) return { ok: false, error: 'Task not found' };\n if (target.status === 'in_progress') return { ok: false, error: `\"${target.title}\" is running and cannot be split` };\n if (target.status === 'completed') return { ok: false, error: `\"${target.title}\" is completed and cannot be split` };\n return { ok: true };\n}\n\n\nfunction askedReadOnly(spec: PlannerTaskSpec | undefined): boolean | undefined {\n return typeof spec?.readOnly === 'boolean' ? spec.readOnly : undefined;\n}\n\nfunction isReadOnly(task: Task, catalog: AssignmentCatalog | undefined): boolean {\n return task.taskMode !== undefined && task.taskMode === taggedReadOnlyMode(catalog?.runnerModes?.[task.assignedRunner]);\n}\n\n/**\n * The fields an edit changed, as the planner names them: those it wrote, and\n * `readOnly` when that flipped, never the mode it landed on (ADR-0031) nor a\n * model the resolver put in, which is reported beside the edit instead.\n */\nfunction changedFields(target: Task, written: Partial<Task>, landed: Partial<Task>, catalog: AssignmentCatalog | undefined): string[] {\n const fields = Object.keys(written).filter((f) => f !== 'taskMode');\n if (isReadOnly({ ...target, ...landed }, catalog) !== isReadOnly(target, catalog)) fields.push('readOnly');\n return fields;\n}\n\n/** Nothing discovered and no runner live: what an edit resolves without a catalog. */\nconst NO_CATALOG: AssignmentCatalog = { modelsByRunner: {} };\n\n/**\n * The ids an op's new tasks get, made once and kept for the op: the open\n * turn's held edit is applied again at each read of the plan as edited and\n * once more as it lands, and a start queued behind it names the task by the\n * id it read.\n */\nconst keptIds = new WeakMap<object, string[]>();\n\nfunction idsOf(op: unknown): () => string {\n if (typeof op !== 'object' || op === null) return uuidv4;\n const ids = keptIds.get(op) ?? [];\n keptIds.set(op, ids);\n let next = 0;\n return () => {\n if (next === ids.length) ids.push(uuidv4());\n return ids[next++];\n };\n}\n\n/**\n * Apply task ops to a snapshot of the plan, atomically: either every op\n * applies and the result validates (deps resolve, no cycles, running and\n * completed tasks untouched), or nothing is returned and `errors` explains\n * why. The caller commits `tasks` on ok.\n */\nexport function applyTaskOps(\n currentTasks: readonly Task[],\n newOps: TaskOp[],\n runners: RunnerId[],\n catalog?: AssignmentCatalog,\n held: readonly TaskOp[] = [],\n): ApplyTaskOpsResult {\n // Ops already accepted earlier in the batch apply first; errors number only\n // the new ones, as the planner wrote them in the call it is answered for.\n const ops = [...held, ...newOps];\n const opLabel = (i: number) => (i < held.length ? `earlier op ${i + 1} (${ops[i].op})` : `op ${i - held.length + 1} (${ops[i].op})`);\n let tasks: Task[] = JSON.parse(JSON.stringify(currentTasks));\n const errors: string[] = [];\n const summary: string[] = [];\n const adjustments: AssignmentAdjustment[] = [];\n\n // Batch handles: planner-chosen names for a task an add/merge/split op is\n // about to create, so a later op in the same batch can reference it before\n // it has a real id. Pre-scanned up front — a bad handle refuses the whole\n // batch before anything mutates.\n const handleOwner = new Map<string, number>();\n const handleId = new Map<string, string>();\n for (const [i, op] of ops.entries()) {\n const handle = (op as { handle?: unknown }).handle;\n if (handle === undefined) continue;\n if (typeof handle !== 'string' || !handle.trim()) {\n errors.push(`${opLabel(i)}: handle must be a non-empty string`);\n continue;\n }\n if (handleOwner.has(handle)) {\n errors.push(`${opLabel(i)}: handle \"${handle}\" is already used earlier in this batch`);\n continue;\n }\n if (resolveTaskRef(currentTasks, handle)) {\n errors.push(`${opLabel(i)}: handle \"${handle}\" collides with an existing task reference`);\n continue;\n }\n handleOwner.set(handle, i);\n }\n if (errors.length) return { ok: false, tasks: currentTasks, errors, summary: [] };\n\n const resolveDeps = (deps: unknown, opIndex: number): { ids: string[]; bad: string[] } => {\n const ids: string[] = [];\n const bad: string[] = [];\n const liveFlat = flattenTasks(tasks);\n for (const d of Array.isArray(deps) ? deps : []) {\n const r = resolveRef(d, currentTasks, tasks, handleOwner, handleId, opIndex);\n if ('error' in r) { bad.push(`${String(d)} (${r.error})`); continue; }\n if (!liveFlat.some((t) => t.id === r.id)) { bad.push(`${String(d)} (no longer exists in this batch)`); continue; }\n ids.push(r.id);\n }\n return { ids, bad };\n };\n\n const intake: IntakeCatalog = { runners, runnerModes: catalog?.runnerModes, autonomousDefault: catalog?.autonomousDefault, models: catalog };\n\n /**\n * A planned task's dependency refs, at every depth, as ids: a subtask may\n * name a task of its own tree by the id the planner gave it, or any task in\n * the plan the way every op does.\n */\n const resolveTree = (planned: PlannedTask, opIndex: number): { task: Task } | { error: string } => {\n const walk = (t: Task, parentTitle?: string): Task | string => {\n const ids: string[] = [];\n const bad: string[] = [];\n for (const d of t.dependencies) {\n const own = planned.renamed.get(d);\n if (own) { ids.push(own); continue; }\n const r = resolveDeps([d], opIndex);\n ids.push(...r.ids);\n bad.push(...r.bad);\n }\n if (bad.length) return `unknown dependencies${parentTitle !== undefined ? ` of ${taskWhere(t.title, parentTitle)}` : ''}: ${bad.join(', ')}`;\n const subtasks: Task[] = [];\n for (const sub of t.subtasks) {\n const done = walk(sub, t.title);\n if (typeof done === 'string') return done;\n subtasks.push(done);\n }\n return { ...t, dependencies: ids, subtasks };\n };\n const done = walk(planned.task);\n return typeof done === 'string' ? { error: done } : { task: done };\n };\n\n /** Why the edit cannot have this planned task: a rule it breaks, or something it asked for that is not the planner's. */\n const refusalOf = (planned: PlannedTask): string | undefined => [...planned.ignored, ...planned.errors][0]?.message;\n\n /**\n * The resolve-and-validate half shared by \"update\" and \"rearm\": resolve the\n * target, apply the field allowlist, run the edit validator under the op's\n * audience and the assignment resolver as the planner's edit, then resolve\n * any dependency refs. `refuseRunning` is rearm's extra lock check, kept\n * before the field work so its message wins. `changes` is what lands;\n * `fields` what the planner changed, as its summary names it.\n */\n const prepareEdit = (\n op: { taskId: string; changes?: PlannerTaskSpec },\n opIndex: number,\n label: string,\n audience: TaskEditActor,\n refuseRunning = false,\n ): { target: Task; changes: Partial<Task>; fields: string[]; check: TaskEditCheck } | { error: string } => {\n const ref = resolveRef(op.taskId, currentTasks, tasks, handleOwner, handleId, opIndex);\n if ('error' in ref) return { error: `${label}: ${ref.error}` };\n const target = findInTasks(tasks, ref.id);\n if (!target) return { error: `${label}: task \"${op.taskId}\" no longer exists in this batch (removed, merged, or split by an earlier op)` };\n if (refuseRunning && target.status === 'in_progress') return { error: `${label}: ${lockedTaskRefusal(target, 're-armed')}` };\n if (op.changes && 'taskMode' in op.changes) return { error: `${label}: ${MODE_NOT_THE_PLANNERS}` };\n const changes = updatableChanges(op.changes);\n if (op.changes && 'thinkingEffort' in op.changes) {\n const model = changes.assignedModel ?? target.assignedModel;\n if (!model) return { error: `${label}: \"thinkingEffort\" is the assigned model's — set \"assignedModel\" with it` };\n changes.assignedModel = { ...model, thinkingEffort: op.changes.thinkingEffort ?? undefined };\n }\n // Dependency refs are still unresolved (e.g. \"#3\") at this point, so the\n // check runs on everything but them. The shared plan invariants check\n // their resolved ids on the final graph: a later op may finish a rewire.\n const changesForCheck: Partial<Task> = { ...changes };\n delete changesForCheck.dependencies;\n const check = validateTaskEdit(audience, tasks, target.id, changesForCheck);\n if (!check.ok) return { error: `${label}: ${check.error}` };\n for (const field of check.clear ?? []) (changes as Record<string, unknown>)[field] = undefined;\n Object.assign(changes, check.set);\n const readOnly = askedReadOnly(op.changes);\n if (readOnly === true && (changes.type ?? target.type) === 'user') return { error: `${label}: ${MANUAL_NOT_READ_ONLY}` };\n if ((changes.ops ?? target.ops) && (readOnly ?? isReadOnly(target, catalog))) return { error: `${label}: ${OPS_NOT_READ_ONLY}` };\n const landed: Partial<Task> = { ...changes };\n const written = { ...target, ...changes };\n // A runner not allowed has nothing to resolve against; the plan's rules refuse it once the op is applied.\n if (written.type === 'user' || runners.includes(written.assignedRunner)) {\n const resolved = resolveAssignment({ writer: 'edit', task: written, before: target, readOnly, catalog: catalog ?? NO_CATALOG });\n if (!resolved.ok) return { error: `${label}: ${resolved.error}` };\n if (resolved.task.assignedModel !== written.assignedModel) landed.assignedModel = resolved.task.assignedModel;\n if (resolved.task.taskMode !== written.taskMode) landed.taskMode = resolved.task.taskMode;\n adjustments.push(...resolved.adjustments);\n }\n if ('dependencies' in changes) {\n const { ids, bad } = resolveDeps(changes.dependencies, opIndex);\n if (bad.length) return { error: `${label}: unknown dependencies: ${bad.join(', ')}` };\n landed.dependencies = ids;\n }\n return { target, changes: landed, fields: changedFields(target, changes, landed, catalog), check };\n };\n\n // A rule the batch ends in breach of is the op's that first broke it. What\n // the plan already broke before the batch — a task on a runner disabled\n // since, say — is not, so it never blocks an unrelated edit. A breach is\n // told by its task and rule, not its wording: the wording carries the title,\n // which an edit may change.\n const breachKey = (e: PlanTaskError) => `${e.taskId ?? ''}\\u0000${e.field}`;\n const standing = new Set(checkPlanInvariants(currentTasks, runners, catalog?.runnerModes).map(breachKey));\n const brokenBy = new Map<string, string>();\n let lastLabel = opLabel(0);\n\n for (const [i, op] of ops.entries()) {\n const label = opLabel(i);\n const newId = idsOf(op);\n switch (op.op) {\n case 'update': {\n const prep = prepareEdit(op, i, label, 'planner');\n if ('error' in prep) { errors.push(prep.error); break; }\n const { target, changes, fields, check } = prep;\n if (fields.length === 0) {\n const readOnly = askedReadOnly(op.changes);\n if (readOnly !== undefined && isReadOnly(target, catalog) === readOnly) { summary.push(`\"${target.title}\" is already ${readOnly ? '' : 'not '}read-only`); break; }\n errors.push(`${label}: no valid changes provided`);\n break;\n }\n tasks = updateTaskInPlan(tasks, target.id, changes);\n const clearedNote = check.clear?.length ? `; cleared ${check.clear.join(', ')}` : '';\n summary.push(`Updated \"${target.title}\"${fields.length ? ` (${fields.join(', ')})` : ''}${clearedNote}`);\n break;\n }\n case 'add': {\n const spec = op.task ?? {};\n if (!spec.title) { errors.push(`${label}: new task needs a title`); break; }\n const planned = plannedTask(spec, intake, { freshIds: true, newId });\n const refused = refusalOf(planned);\n if (refused) { errors.push(`${label}: ${refused}`); break; }\n adjustments.push(...planned.adjustments);\n const resolved = resolveTree(planned, i);\n if ('error' in resolved) { errors.push(`${label}: ${resolved.error}`); break; }\n tasks = addTaskToPlan(tasks, resolved.task);\n if (op.handle) handleId.set(op.handle, resolved.task.id);\n summary.push(`Added \"${spec.title}\"`);\n break;\n }\n case 'remove': {\n const ref = resolveRef(op.taskId, currentTasks, tasks, handleOwner, handleId, i);\n if ('error' in ref) { errors.push(`${label}: ${ref.error}`); break; }\n const target = findInTasks(tasks, ref.id);\n if (!target) { errors.push(`${label}: task \"${op.taskId}\" no longer exists in this batch (removed, merged, or split by an earlier op)`); break; }\n // Removing the task takes its whole subtree, so every task in it meets\n // the same lock rule as the named one (ADR-0029).\n const locked = lockedTaskRefusal(target, 'removed') ?? lockedInSubtree(target);\n if (locked) { errors.push(`${label}: ${locked}`); break; }\n tasks = removeTaskFromPlan(tasks, target.id);\n summary.push(`Removed \"${target.title}\"`);\n break;\n }\n case 'reorder': {\n const refs = (op.taskIds ?? []).map((r) => resolveRef(r, currentTasks, tasks, handleOwner, handleId, i));\n const badRef = refs.find((r): r is { error: string } => 'error' in r);\n if (badRef) { errors.push(`${label}: ${badRef.error}`); break; }\n const resolved = (refs as { id: string }[]).map((r) => findTopLevel(tasks, r.id));\n if (resolved.some((t) => !t)) { errors.push(`${label}: unknown task in reorder list`); break; }\n const orderIds = resolved.map((t) => t!.id);\n if (new Set(orderIds).size !== tasks.length) {\n errors.push(`${label}: reorder must list every top-level task exactly once (${tasks.length} tasks)`);\n break;\n }\n const byId = new Map(tasks.map((t) => [t.id, t]));\n tasks = renumberTasks(orderIds.map((id) => byId.get(id)!));\n summary.push('Reordered tasks');\n break;\n }\n case 'merge': {\n const refs = (op.taskIds ?? []).map((r) => resolveRef(r, currentTasks, tasks, handleOwner, handleId, i));\n const badRef = refs.find((r): r is { error: string } => 'error' in r);\n if (badRef) { errors.push(`${label}: ${badRef.error}`); break; }\n const resolved = (refs as { id: string }[]).map((r) => findTopLevel(tasks, r.id));\n if (resolved.some((t) => !t)) { errors.push(`${label}: unknown task in merge list (already removed, merged, or split by an earlier op)`); break; }\n const toMerge = [...new Map(resolved.map((t) => [t!.id, t!])).values()].sort((a, b) => a.order - b.order);\n if (toMerge.length < 2) { errors.push(`${label}: merge needs at least two tasks`); break; }\n const locked = toMerge.map((t) => lockedTaskRefusal(t, 'merged')).find((refusal) => refusal !== null);\n if (locked) { errors.push(`${label}: ${locked}`); break; }\n const idSet = new Set(toMerge.map((t) => t.id));\n const unionDepsRaw = [...new Set(toMerge.flatMap((t) => t.dependencies))].filter((d) => !idSet.has(d));\n const { ids, bad } = resolveDeps(unionDepsRaw, i);\n if (bad.length) { errors.push(`${label}: unknown dependencies: ${bad.join(', ')}`); break; }\n const spec = op.merged ?? {};\n if (!spec.title) { errors.push(`${label}: merged task needs a title`); break; }\n // Read-only only when every merged task was: one that writes makes the merged task write.\n const writes = toMerge.find((t) => !isReadOnly(t, catalog));\n const stories = [...new Set(toMerge.flatMap((t) => t.userStoriesCovered ?? []))];\n const planned = plannedTask(spec, intake, {\n freshIds: true,\n newId,\n from: {\n readOnly: !writes,\n fields: {\n description: toMerge.map((t) => t.description).filter(Boolean).join('\\n\\n'),\n prompt: toMerge.map((t) => t.prompt).filter(Boolean).join('\\n\\n---\\n\\n') || undefined,\n type: toMerge.some((t) => t.type === 'user') ? 'user' : 'ai',\n assignedRunner: toMerge[0].assignedRunner,\n assignedModel: toMerge.find((t) => t.assignedModel)?.assignedModel,\n taskMode: (writes ?? toMerge[0]).taskMode,\n autonomy: toMerge.find((t) => t.autonomy)?.autonomy,\n sliceType: toMerge.find((t) => t.sliceType)?.sliceType,\n ops: inheritedOps(toMerge),\n skills: toMerge.flatMap((t) => t.skills ?? []),\n userStoriesCovered: stories.length ? stories : undefined,\n },\n },\n });\n const refused = refusalOf(planned);\n if (refused) { errors.push(`${label}: ${refused}`); break; }\n adjustments.push(...planned.adjustments);\n const built = resolveTree({ ...planned, task: { ...planned.task, dependencies: [] } }, i);\n if ('error' in built) { errors.push(`${label}: ${built.error}`); break; }\n const mergedTask: Task = { ...built.task, dependencies: ids };\n const mergedId = mergedTask.id;\n const firstId = toMerge[0].id;\n const result: Task[] = [];\n let inserted = false;\n for (const t of tasks) {\n if (idSet.has(t.id)) {\n if (!inserted && t.id === firstId) { result.push(mergedTask); inserted = true; }\n continue;\n }\n result.push({ ...t, dependencies: t.dependencies.map((d) => (idSet.has(d) ? mergedId : d)) });\n }\n if (!inserted) result.push(mergedTask);\n tasks = renumberTasks(result);\n if (op.handle) handleId.set(op.handle, mergedId);\n summary.push(`Merged ${toMerge.length} tasks into \"${spec.title}\"`);\n break;\n }\n case 'split': {\n const ref = resolveRef(op.taskId, currentTasks, tasks, handleOwner, handleId, i);\n if ('error' in ref) { errors.push(`${label}: ${ref.error}`); break; }\n const target = findTopLevel(tasks, ref.id);\n if (!target) { errors.push(`${label}: task \"${op.taskId}\" not found`); break; }\n const locked = lockedTaskRefusal(target, 'split');\n if (locked) { errors.push(`${label}: ${locked}`); break; }\n const parts = op.parts ?? [];\n if (parts.length < 2) { errors.push(`${label}: split needs at least two parts`); break; }\n const newTasks: Task[] = [];\n let prevId: string | undefined;\n let buildError = false;\n for (let p = 0; p < parts.length; p++) {\n const spec = parts[p];\n if (!spec || !spec.title) { errors.push(`${label}: split part ${p + 1} needs a title`); buildError = true; break; }\n // Part 0 inherits the original's (external) dependencies, resolved\n // against the current plan. Later parts chain onto the previous part\n // — a sibling id created in this same op, so it needs no resolution.\n let deps: string[];\n if (p === 0) {\n const { ids, bad } = resolveDeps(target.dependencies, i);\n if (bad.length) { errors.push(`${label}: split part 1 unknown dependencies: ${bad.join(', ')}`); buildError = true; break; }\n deps = ids;\n } else {\n deps = prevId ? [prevId] : [];\n }\n const planned = plannedTask(spec, intake, {\n freshIds: true,\n newId,\n from: {\n readOnly: isReadOnly(target, catalog),\n fields: {\n type: target.type,\n assignedRunner: target.assignedRunner,\n assignedModel: target.assignedModel,\n taskMode: target.taskMode,\n autonomy: target.autonomy,\n sliceType: target.sliceType,\n ops: inheritedOps([target]),\n skills: target.skills,\n userStoriesCovered: target.userStoriesCovered,\n },\n },\n });\n const refused = refusalOf(planned);\n if (refused) { errors.push(`${label}: split part ${p + 1}: ${refused}`); buildError = true; break; }\n adjustments.push(...planned.adjustments);\n const resolved = resolveTree({ ...planned, task: { ...planned.task, dependencies: [] } }, i);\n if ('error' in resolved) { errors.push(`${label}: split part ${p + 1}: ${resolved.error}`); buildError = true; break; }\n const nt: Task = { ...resolved.task, dependencies: deps };\n newTasks.push(nt);\n prevId = nt.id;\n }\n if (buildError) break;\n const tailId = newTasks[newTasks.length - 1].id;\n const result: Task[] = [];\n for (const t of tasks) {\n if (t.id === target.id) { result.push(...newTasks); continue; }\n result.push({ ...t, dependencies: t.dependencies.map((d) => (d === target.id ? tailId : d)) });\n }\n tasks = renumberTasks(result);\n if (op.handle) handleId.set(op.handle, tailId);\n summary.push(`Split \"${target.title}\" into ${newTasks.length} tasks`);\n break;\n }\n case 'rearm': {\n // Re-arming is the sanctioned exception to the planner lock — its whole\n // point is to touch a task the lock would otherwise refuse — so it\n // validates as a direct edit; well-formedness still applies.\n const prep = prepareEdit(op, i, label, 'direct', true);\n if ('error' in prep) { errors.push(prep.error); break; }\n const { target, changes, fields, check } = prep;\n tasks = updateTaskInPlan(tasks, target.id, { ...changes, status: 'pending', verdict: undefined, outputSummary: undefined, awaitingReason: undefined, resumeAt: undefined, skipReason: undefined });\n const clearedNote = check.clear?.length ? `; cleared ${check.clear.join(', ')}` : '';\n const changedNote = fields.length ? ` (${fields.join(', ')})` : '';\n summary.push(`Re-armed \"${target.title}\"${changedNote}${clearedNote}`);\n break;\n }\n default:\n errors.push(`${label}: unknown op \"${(op as { op: string }).op}\"`);\n }\n if (errors.length) break;\n lastLabel = label;\n // Invariants are judged on the final state, so a later op may complete an\n // earlier one; here they only record which op a breach belongs to.\n const now = new Set(checkPlanInvariants(tasks, runners, catalog?.runnerModes).map(breachKey));\n for (const key of brokenBy.keys()) if (!now.has(key)) brokenBy.delete(key);\n for (const key of now) if (!standing.has(key) && !brokenBy.has(key)) brokenBy.set(key, label);\n }\n\n if (!errors.length) {\n for (const e of checkPlanInvariants(tasks, runners, catalog?.runnerModes)) {\n const key = breachKey(e);\n if (!standing.has(key)) errors.push(`${brokenBy.get(key) ?? lastLabel}: ${e.message}`);\n }\n }\n\n // Display order is maintained, not demanded: whatever the batch produced,\n // the plan comes back with dependencies ahead of their dependents. The\n // planner never has to re-declare the whole order to move one task.\n if (!errors.length) {\n const repaired = repairOrder(tasks);\n if ('error' in repaired) {\n errors.push(repaired.error);\n } else {\n const moves = describeMoves(tasks, repaired.tasks);\n if (moves) summary.push(`Reordered to keep dependencies first: ${moves}`);\n tasks = renumberTasks(repaired.tasks);\n }\n }\n\n if (errors.length) return { ok: false, tasks: currentTasks, errors, summary: [] };\n // A later op may move or remove what an earlier one adjusted: only what still stands is reported.\n const landed = new Map(flattenTasks(tasks).map((t) => [t.id, t]));\n const told = new Set<string>();\n const standingAdjustments = adjustments.filter((a) => {\n const task = landed.get(a.taskId);\n const now = a.field === 'assignedModel' ? task?.assignedModel?.modelId : task?.assignedModel?.thinkingEffort;\n const key = `${a.taskId}\\u0000${a.field}`;\n if (task === undefined || (now ?? null) !== a.to || told.has(key)) return false;\n told.add(key);\n return true;\n });\n return { ok: true, tasks, errors: [], summary, handles: handleId, adjustments: standingAdjustments };\n}\n","import type { AwaitingReason } from '../models/Task';\n\n/**\n * What a row's status means to a reader, before any surface picks a word,\n * icon or colour for it. `quiet` is a running task whose runner has printed\n * nothing for a while — the status is still `in_progress`, so only the row,\n * never the store, tells the two apart.\n */\nexport type TaskStatusKind = 'todo' | 'running' | 'quiet' | 'awaiting' | 'blocked' | 'failed' | 'skipped' | 'done';\n\n/** A task with a runner live behind it. `in_progress` is the store's own status. */\nexport const isTaskRunning = (task: { status: string }): boolean =>\n task.status === 'in_progress' || task.status === 'running';\n\n/** Statuses of a task that has not started: what can still be started by hand, or flipped between change and ops (ADR-0020). */\nexport const NOT_STARTED: ReadonlySet<string> = new Set(['pending', 'approved', 'blocked']);\n\nexport function taskStatusKind(task: { status: string; idleSince?: string | null }): TaskStatusKind {\n switch (task.status) {\n case 'completed': return 'done';\n case 'failed': return 'failed';\n case 'skipped': return 'skipped';\n case 'blocked': return 'blocked';\n case 'awaiting_user': return 'awaiting';\n }\n if (!isTaskRunning(task)) return 'todo';\n return task.status === 'in_progress' && task.idleSince ? 'quiet' : 'running';\n}\n\nconst AWAITING_LABELS: Record<AwaitingReason, string> = {\n input: 'Waiting for your input',\n checkpoint: 'Checkpoint',\n conflict: 'Merge conflict',\n 'files-changed': 'Changed tracked files',\n 'usage-limit': 'Paused on a usage limit',\n};\n\n/** What an awaiting_user task waits on (ADR-0018, W1); null when no reason was saved. */\nexport function awaitingLabel(task: { status: string; awaitingReason?: AwaitingReason }): string | null {\n return task.status === 'awaiting_user' && task.awaitingReason ? AWAITING_LABELS[task.awaitingReason] : null;\n}\n\n/** \"Blocked by #1, #2.1\": the failed tasks a blocked task waits on, by reference (ADR-0034). */\nexport function blockedByLabel(refs: readonly string[]): string {\n return `Blocked by ${refs.join(', ')}`;\n}\n\n/** \"Skipped: no GPU on this host\", or \"Skipped\" when no reason was given. */\nexport function skippedLabel(reason: string | null): string {\n return reason ? `Skipped: ${reason}` : 'Skipped';\n}\n\n/**\n * A task added after the user approved the plan, which the scheduler leaves\n * for them (ADR-0035). Not a runner approval: nothing has started, so no\n * runner is asking anything.\n */\nexport const WAITS_FOR_APPROVAL_LABEL = 'Waits for your approval';\n\n/** Runner requests a task waits on (ADR-0018, A1); null when none do. */\nexport function approvalLabel(count: number | undefined): string | null {\n if (!count) return null;\n return count > 1 ? `Waiting for approval (${count})` : 'Waiting for approval';\n}\n\n/**\n * When a paused task resumes, as a reader's clock shows it: \"8:10pm\", or\n * \"Oct 14, 8:10pm\" when it is not today. Read in the local time zone of\n * whoever formats it.\n */\nexport function resumeTime(at: Date, now: Date = new Date()): string {\n const clock = at.toLocaleTimeString('en-US', { hour: 'numeric', minute: at.getMinutes() === 0 ? undefined : '2-digit', hour12: true })\n .replace(/[ \\u202f]([AP]M)$/i, (_m, meridiem: string) => meridiem.toLowerCase());\n if (at.toDateString() === now.toDateString()) return clock;\n return `${at.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}, ${clock}`;\n}\n\n/** \"Resumes at 8:10pm\" for a task paused on a usage limit that resumes on its own; null for any other. */\nexport function resumeLabel(task: { status: string; awaitingReason?: AwaitingReason; resumeAt?: string | null }, now: Date = new Date()): string | null {\n if (task.status !== 'awaiting_user' || task.awaitingReason !== 'usage-limit' || !task.resumeAt) return null;\n const at = new Date(task.resumeAt);\n return Number.isNaN(at.getTime()) ? null : `Resumes at ${resumeTime(at, now)}`;\n}\n","import { dependencyTargetErrors, findDependencyCycle } from './PlanTree';\nimport { v4 as uuidv4 } from 'uuid';\nimport { Task, RunnerId, TaskModelAssignment, DEFAULT_RUNNERS, createTask, flattenTasksWithParents, inheritedSkills, skillNames } from '../models/Task';\nimport { taggedReadOnlyMode, type RunnerModeInfo } from './ModeResolver';\nimport { resolveAssignment, type AssignmentAdjustment, type AssignmentCatalog } from './TaskAssignment';\n\n/** One reason a planned task was refused, pinned to the task and field it is about. */\nexport interface PlanTaskError {\n /** Absent when the envelope itself is wrong rather than one of its tasks. */\n taskId?: string;\n field: string;\n message: string;\n}\n\n/** What a planned task may be given: the runners it may run on and their modes. */\nexport interface IntakeCatalog {\n runners: readonly RunnerId[];\n /** Absent when no runner's modes are known: the mode is then guessed (ADR-0031). */\n runnerModes?: Partial<Record<RunnerId, readonly RunnerModeInfo[]>>;\n autonomousDefault?: boolean;\n /**\n * An edit's assignments are resolved against the catalog as it is planned,\n * and a model it names that the runner does not offer is refused; a\n * submitted plan's models are resolved as it lands instead (ADR-0003).\n */\n models?: AssignmentCatalog;\n}\n\n/** Where a planned task lands, which decides what it inherits. */\nexport interface Placement {\n /** The task it is a subtask of. */\n parent?: Pick<Task, 'title' | 'sliceType' | 'autonomy'> & { readOnly: boolean };\n /**\n * A task made from others — a merge, or a split part: what the planner\n * leaves out comes from these fields, and it stays read-only when they were.\n */\n from?: { fields: Partial<Task>; readOnly: boolean };\n /**\n * An edit's tasks get ids of their own, so a planner cannot name one after\n * a task already in the plan. A submitted plan keeps the planner's, which\n * its dependencies are written against; one it left out is made up.\n */\n freshIds?: boolean;\n /** Where a made-up id comes from: a new one each time, unless the caller keeps them. */\n newId?: () => string;\n}\n\nexport interface PlannedTask {\n task: Task;\n /** Rules the task, or one of its subtasks, breaks on its own. */\n errors: PlanTaskError[];\n /**\n * What the planner asked for that is not its to set — a mode, or read-only\n * on a manual task (ADR-0031). A whole plan lands without it; an edit is\n * refused.\n */\n ignored: PlanTaskError[];\n /** The planner's id for each task of the tree that was given a fresh one. */\n renamed: Map<string, string>;\n /** What the tree's assignments were adjusted to beyond what the planner wrote, for the planner to be told. */\n adjustments: AssignmentAdjustment[];\n}\n\n/** The planner names no mode (ADR-0031): it says read-only, and the mode follows. */\nexport const MODE_NOT_THE_PLANNERS = '\"taskMode\" is the user\\'s to choose: set \"readOnly\": true on a task that must not change files, and leave it out otherwise';\n\n/** A manual task runs in no mode, so it cannot be read-only. */\nexport const MANUAL_NOT_READ_ONLY = '\"readOnly\" is for AI tasks: a manual task runs in no mode';\n\n/** An ops task acts — runs commands — in the session's mode (ADR-0020); a read-only mode refuses that. */\nexport const OPS_NOT_READ_ONLY = '\"readOnly\" is not for an ops task: it runs commands, in the session\\'s mode, and a read-only mode refuses them';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction text(value: unknown): string | undefined {\n return typeof value === 'string' || typeof value === 'number' ? String(value) : undefined;\n}\n\n/**\n * Why a task may not be an ops task (ADR-0020), or null when it may: the flag\n * decides where the task runs, and a manual task runs nowhere, a subtask\n * where its parent does.\n */\nexport function opsPlacementRefusal(type: Task['type'], isSubtask: boolean): string | null {\n if (type !== 'ai') return 'is a manual task: only an AI task can be an ops task';\n if (isSubtask) return 'is a subtask, which runs with its parent: only a top-level task can be an ops task';\n return null;\n}\n\n/** How an error names a task, so the planner can find the object it wrote. */\nexport function taskWhere(title: string, parentTitle?: string): string {\n return parentTitle !== undefined ? `subtask \"${title}\" of \"${parentTitle}\"` : `Task \"${title}\"`;\n}\n\n/**\n * What each planned task asked to attach, as the planner wrote it. Kept beside\n * the task rather than on it: {@link skillNames} drops a name no skill could\n * have, and the plan's skill check still owes a warning for it. A copy of the\n * task (assignment coercion) does not carry it, so check what was planned.\n */\nconst skillsAsked = new WeakMap<Task, unknown[]>();\n\n/** The `skills` a planned task was submitted with, before normalization; undefined for a task not planned here. */\nexport function requestedSkills(task: Task): readonly unknown[] | undefined {\n return skillsAsked.get(task);\n}\n\n/** The model as a task stores it; a top-level `thinkingEffort` is the model's, as the effort has one home. */\nfunction modelOf(raw: Record<string, unknown>, from: TaskModelAssignment | undefined): TaskModelAssignment | undefined {\n const effort = text(raw.thinkingEffort);\n if (isRecord(raw.assignedModel)) {\n const m = raw.assignedModel;\n return {\n modelId: text(m.modelId) ?? '',\n modelLabel: text(m.modelLabel) ?? '',\n thinkingEffort: text(m.thinkingEffort) ?? effort,\n };\n }\n return from && effort !== undefined ? { ...from, thinkingEffort: effort } : from;\n}\n\n/**\n * Build a task from what a planner wrote, by whichever route it arrived: a\n * submitted plan, or an edit that adds, merges or splits. Every fallback a\n * planner's omission meets is here, so the routes cannot drift apart:\n *\n * - the runner is the one named, else the task's it is made from, else the\n * first one allowed — never a substitute for one named but unknown, which\n * {@link checkPlanInvariants} refuses;\n * - an AI task's prompt is its own, else its description, else its title, so\n * it is never unschedulable;\n * - the assignment — model, effort, and the mode decided from read-only or\n * not, never named (ADR-0031) — is the resolver's (`resolveAssignment`),\n * as it is for every writer: a model a merge or split carries is read as\n * what the task was made from, so a part moved to another runner gets that\n * runner's;\n * - an AI subtask with no slice classification takes its parent's: an `ai`\n * sub-step of an AFK slice is AFK. Not a blanket default, which would strip\n * a human gate the planner intended; a manual subtask must still say HITL.\n */\nexport function plannedTask(spec: unknown, catalog: IntakeCatalog, at: Placement = {}): PlannedTask {\n const raw = isRecord(spec) ? spec : {};\n const { parent, from, freshIds, newId = uuidv4 } = at;\n const base = from?.fields ?? {};\n const errors: PlanTaskError[] = [];\n const ignored: PlanTaskError[] = [];\n const renamed = new Map<string, string>();\n const adjustments: AssignmentAdjustment[] = [];\n\n const title = text(raw.title) ?? '';\n const where = taskWhere(title, parent?.title);\n const plannerId = text(raw.id);\n const id = freshIds || !plannerId ? newId() : plannerId;\n if (freshIds && plannerId) renamed.set(plannerId, id);\n\n const type: Task['type'] = raw.type === 'user' || raw.type === 'ai' ? raw.type : base.type ?? 'ai';\n const ai = type === 'ai';\n const assignedRunner = text(raw.assignedRunner) ?? base.assignedRunner ?? catalog.runners[0] ?? DEFAULT_RUNNERS[0];\n const description = text(raw.description) ?? base.description ?? title;\n\n // A manual task stores no ops flag, so this is the one place it can still be seen.\n if (raw.ops === true && !ai) errors.push({ taskId: id, field: 'ops', message: `${where} ${opsPlacementRefusal(type, !!parent)}` });\n if (raw.taskMode !== undefined) ignored.push({ taskId: id, field: 'taskMode', message: `${where}: ${MODE_NOT_THE_PLANNERS}` });\n if (!ai && raw.readOnly === true) ignored.push({ taskId: id, field: 'readOnly', message: `${where}: ${MANUAL_NOT_READ_ONLY}` });\n const ops = raw.ops !== undefined ? raw.ops === true : base.ops;\n if (ai && ops && raw.readOnly === true) ignored.push({ taskId: id, field: 'readOnly', message: `${where}: ${OPS_NOT_READ_ONLY}` });\n // A read-only task's subtasks run as tasks of their own, so they would\n // otherwise get write access the planner said the work must not have.\n const asked = typeof raw.readOnly === 'boolean' ? raw.readOnly : undefined;\n const readOnly = ai && !ops && (asked ?? from?.readOnly ?? parent?.readOnly ?? false);\n\n const assignedModel = ai ? modelOf(raw, base.assignedModel) : undefined;\n const slice = (value: unknown): 'AFK' | 'HITL' | undefined => (value === 'AFK' || value === 'HITL' ? value : undefined);\n // Explicit child values always win; inheritance only fills a gap, and only for `ai` tasks.\n const autonomy = ai ? slice(raw.autonomy) ?? base.autonomy ?? parent?.autonomy : undefined;\n const sliceType = slice(raw.sliceType) ?? base.sliceType ?? (ai ? parent?.sliceType : undefined);\n\n const subtasks: Task[] = [];\n if (Array.isArray(raw.subtasks)) {\n for (const s of raw.subtasks) {\n const child = plannedTask(s, catalog, { parent: { title, sliceType, autonomy, readOnly }, freshIds, newId });\n subtasks.push(child.task);\n errors.push(...child.errors);\n ignored.push(...child.ignored);\n adjustments.push(...child.adjustments);\n for (const [was, now] of child.renamed) renamed.set(was, now);\n }\n }\n\n const fields = {\n id,\n order: Number(raw.order ?? 0),\n title,\n description,\n type,\n dependencies: Array.isArray(raw.dependencies) ? raw.dependencies.map(String) : base.dependencies ?? [],\n prompt: text(raw.prompt) || base.prompt || (ai ? description || title || undefined : undefined),\n userSteps: Array.isArray(raw.userSteps)\n ? raw.userSteps.map((s) => (isRecord(s) ? s : {})).map((s) => ({ order: Number(s.order ?? 0), instruction: String(s.instruction ?? ''), completed: false }))\n : base.userSteps,\n subtasks,\n assignedModel,\n assignedRunner,\n autonomy,\n sliceType,\n userStoriesCovered: Array.isArray(raw.userStoriesCovered) ? raw.userStoriesCovered.map(String) : base.userStoriesCovered,\n ops,\n skills: from ? inheritedSkills(raw.skills, base.skills) : skillNames(raw.skills),\n };\n let taskMode = base.taskMode;\n let landedModel = assignedModel;\n if (ai && catalog.runners.includes(assignedRunner)) {\n const resolved = resolveAssignment({\n writer: catalog.models ? 'edit' : 'plan',\n task: { ...createTask(fields), taskMode },\n from: from ? { assignedRunner: base.assignedRunner ?? assignedRunner, assignedModel: base.assignedModel, taskMode: base.taskMode } : undefined,\n readOnly,\n catalog: { modelsByRunner: {}, ...catalog.models, runnerModes: catalog.runnerModes, autonomousDefault: catalog.autonomousDefault },\n });\n if (!resolved.ok) {\n // The planner names no mode: one it cannot have is about the read-only answer it gave (ADR-0031).\n errors.push({ taskId: id, field: resolved.field === 'taskMode' ? 'readOnly' : resolved.field, message: `${where}: ${resolved.error}` });\n } else {\n taskMode = resolved.task.taskMode;\n landedModel = resolved.task.assignedModel;\n adjustments.push(...resolved.adjustments);\n }\n }\n // With no runner modes to read, `plan` is the guess that keeps a read-only task from writing.\n if (taskMode === undefined && readOnly && !catalog.runnerModes) taskMode = 'plan';\n\n const task = createTask({ ...fields, assignedModel: landedModel, taskMode });\n if (Array.isArray(raw.skills)) skillsAsked.set(task, raw.skills);\n return { task, errors, ignored, renamed, adjustments };\n}\n\n/**\n * The rules a plan's tasks are held to together, subtasks included, whichever\n * route they arrived by and whoever wrote them, the planner or the user.\n * `runners` are the ones the writer may put a task on (`assignableRunners`),\n * any when undefined; with `runnerModes`, an ops task is held off its\n * runner's read-only mode.\n */\nexport function checkPlanInvariants(\n tasks: readonly Task[],\n runners: readonly RunnerId[] | undefined,\n runnerModes?: Partial<Record<RunnerId, readonly RunnerModeInfo[]>>,\n): PlanTaskError[] {\n const rows = flattenTasksWithParents(tasks);\n const errors: PlanTaskError[] = [];\n const seen = new Set<string>();\n for (const { task: t, parent } of rows) {\n const where = taskWhere(t.title, parent?.title);\n const fail = (field: string, message: string) => errors.push({ taskId: t.id, field, message });\n if (seen.has(t.id)) fail('id', `${where} has id \"${t.id}\", which another task in the plan has too: every task, subtasks included, needs an id of its own`);\n seen.add(t.id);\n if (t.autonomy === 'AFK' && t.userSteps && t.userSteps.length > 0) {\n fail('userSteps', `${where} has autonomy \"AFK\" but contains userSteps. AFK tasks must not have user touchpoints.`);\n }\n if (t.type === 'user' && t.sliceType && t.sliceType !== 'HITL') {\n fail('sliceType', `User ${where} has sliceType \"${t.sliceType}\". User tasks must have sliceType \"HITL\".`);\n }\n const opsRefused = t.ops ? opsPlacementRefusal(t.type, parent !== null) : null;\n if (opsRefused) fail('ops', `${where} ${opsRefused}`);\n if (t.ops && t.taskMode !== undefined && t.taskMode === taggedReadOnlyMode(runnerModes?.[t.assignedRunner])) {\n fail('taskMode', `${where} is an ops task, which runs commands, so it cannot run in its runner's read-only mode`);\n }\n if (runners && t.type !== 'user' && !runners.includes(t.assignedRunner)) {\n fail('assignedRunner', `${where} has invalid assignedRunner \"${t.assignedRunner}\". Expected one of: ${runners.join(', ')}`);\n }\n }\n for (const { task: t, parent } of rows) {\n // Self-dependencies are reported with the cycle below, including its full path.\n for (const error of dependencyTargetErrors(tasks, t.id, t.dependencies.filter((id) => id !== t.id))) {\n errors.push({ taskId: t.id, field: 'dependencies', message: `${taskWhere(t.title, parent?.title)}: ${error}` });\n }\n }\n const cycle = findCycle(rows.map((r) => r.task));\n // Pinned to a task on the cycle: a plan whose only fault is a rule a task\n // breaks is worth naming back to the planner, not re-asking for as JSON.\n if (cycle) errors.push({ taskId: cycle[0].id, field: 'dependencies', message: `Dependency cycle detected: ${[...cycle, cycle[0]].map((t) => `\"${t.title}\"`).join(' → ')}` });\n return errors;\n}\n\n/** The tasks on one dependency cycle, in dependency order, or null when there is none. A self-dependency is a cycle of one. */\nexport function findCycle(tasks: readonly Task[]): Task[] | null {\n return findDependencyCycle(tasks);\n}\n\n/** The title of a task on a dependency cycle, or null when there is none. */\nexport function detectCycle(tasks: readonly Task[]): string | null {\n return findCycle(tasks)?.[0].title ?? null;\n}\n","import type { DiscoveredModel, RunnerId } from '../models/Task';\n\n/**\n * The ids a runner may actually run: the user's allowlist with the ids that\n * provably belong to a *different* runner dropped. `undefined` means no\n * restriction.\n *\n * Model ids are scoped to the agent that lists them, so an OpenRouter slug\n * allowlisted for Claude Code does not limit it — it points it at something it\n * cannot spawn, and the plan only dies once a task is already running. But\n * \"this runner didn't list it\" is not enough to call an id wrong: discovery can\n * be stale or return no list at all. What settles it is\n * whether *another* runner listed the id. So:\n *\n * - listed for this runner → keep;\n * - listed for no runner → unknown, and the user said it explicitly, so keep it\n * and let the runner validate last (the same call `resolveAssignment` makes);\n * - listed only for other runners → provably not this runner's, so drop it.\n *\n * When that leaves nothing, the whole allowlist was about some other runner\n * (a settings file written before a surface scoped its picker to one). No\n * restriction is the only safe reading — the alternative is handing the planner\n * a list of models that cannot run.\n */\nexport function effectiveAllowlist(\n allowlist: string[] | undefined,\n runner: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>> | undefined,\n): string[] | undefined {\n if (!allowlist || allowlist.length === 0) return undefined;\n if (!modelsByRunner) return allowlist;\n\n const own = new Set((modelsByRunner[runner] ?? []).map((m) => m.modelId));\n const elsewhere = new Set<string>();\n for (const [other, models] of Object.entries(modelsByRunner)) {\n if (other === runner) continue;\n for (const m of models ?? []) elsewhere.add(m.modelId);\n }\n\n const kept = allowlist.filter((id) => own.has(id) || !elsewhere.has(id));\n return kept.length > 0 ? kept : undefined;\n}\n\nexport function filterModelsForPrompt(\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n perRunnerAllowlist: Partial<Record<RunnerId, string[]>>,\n): Partial<Record<RunnerId, DiscoveredModel[]>> {\n const result: Partial<Record<RunnerId, DiscoveredModel[]>> = {};\n for (const [runner, models] of Object.entries(modelsByRunner)) {\n if (!models) continue;\n const allowed = effectiveAllowlist(perRunnerAllowlist[runner], runner, modelsByRunner);\n if (!allowed) {\n result[runner] = models;\n continue;\n }\n const allowedSet = new Set(allowed);\n const intersection = models.filter((m) => allowedSet.has(m.modelId));\n // A set allowlist is a hard constraint: the planner must never see models\n // outside it. An allowed id no runner has listed is one discovery doesn't\n // cover, so synthesize an entry rather than leaking the full list.\n const covered = new Set(intersection.map((m) => m.modelId));\n const missing = allowed\n .filter((id) => !covered.has(id))\n .map((id) => ({ modelId: id, modelLabel: id.split('/').pop() || id, variants: [] }));\n result[runner] = [...intersection, ...missing];\n }\n return result;\n}\n\n/** Canonical low→high ordering of the well-known effort ladder. */\nconst EFFORT_LADDER = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'ultra'];\n/** Runner-specific spellings mapped onto the ladder. */\nconst EFFORT_ALIASES: Record<string, string> = { disabled: 'none', adaptive: 'medium' };\n\n/**\n * The one rule for an effort and a model: the effort a task keeps on a model,\n * whether it was written with it or carried from the model before. Kept where\n * the model offers it; otherwise mapped to the nearest rung the model\n * supports (so a Claude-style \"xhigh\" on a low/medium/high model becomes\n * \"high\"); undefined — the runner's own default — when no mapping exists or\n * the model offers no levels, which is how a model discovery does not list\n * reads (`variants` empty). Core's resolver and every surface's model picker\n * call it, so a model change lands on the same effort wherever it is made.\n */\nexport function clampThinkingEffort(\n effort: string | undefined,\n variants: { id: string }[],\n): string | undefined {\n if (!effort) return undefined;\n if (variants.length === 0) return undefined;\n const ids = new Set(variants.map((v) => v.id));\n if (ids.has(effort)) return effort;\n const canon = EFFORT_ALIASES[effort] ?? effort;\n if (ids.has(canon)) return canon;\n const idx = EFFORT_LADDER.indexOf(canon);\n if (idx < 0) return undefined;\n for (let d = 1; d < EFFORT_LADDER.length; d++) {\n const lower = EFFORT_LADDER[idx - d];\n if (lower && ids.has(lower)) return lower;\n const higher = EFFORT_LADDER[idx + d];\n if (higher && ids.has(higher)) return higher;\n }\n return undefined;\n}\n","import type { ResearchStepOutcome } from '../models/Task';\n\n/**\n * One-line human summary of a research tool call, shared by every surface that\n * renders live planner progress (VS Code webview, CLI, TUI). Kept in core so\n * the arg-shape heuristics (file path vs. pattern vs. shell command) live in\n * one place instead of being re-derived per surface — which also means a new\n * tool becomes readable in all three UIs by being handled here once.\n */\n\nfunction ellipsize(text: string, max: number): string {\n const oneLine = text.replace(/\\s+/g, ' ').trim();\n return oneLine.length > max ? `${oneLine.slice(0, max)}…` : oneLine;\n}\n\n/**\n * @param toolLabel The agent's own name for the tool, when a harness planner\n * produced the call (ADR-0009). It replaces the member name in the summary, so\n * the timeline says `Edit` rather than the catch-all `agent_tool` — and says\n * `WebFetch` rather than claiming a shell command ran.\n */\nexport function summarizeToolCall(tool: string, argsJson: string, toolLabel?: string): string {\n const display = toolLabel?.trim() || tool;\n if (tool === 'agent_tool') {\n // No Ordewell equivalent, so no arg shape to rely on: show the agent's name\n // plus whichever conventional field the call happens to carry.\n try {\n const args = JSON.parse(argsJson);\n const hint = args.path ?? args.file_path ?? args.filePath ?? args.pattern ?? args.query ?? args.url ?? args.command;\n if (hint) return `${display} ${ellipsize(String(hint), 50)}`;\n } catch {\n // fall through to the bare name\n }\n return display;\n }\n\n if (tool === 'spawn_research_agent') {\n try {\n const args = JSON.parse(argsJson);\n const prompt = typeof args.prompt === 'string' ? args.prompt : '';\n const oneLine = prompt.replace(/\\s+/g, ' ').trim();\n return `spawn: \"${oneLine.slice(0, 60)}${oneLine.length > 60 ? '…' : ''}\"`;\n } catch {\n return 'spawn_research_agent';\n }\n }\n\n try {\n const args = JSON.parse(argsJson);\n\n // Ordered by specificity: a tool's defining argument wins over the generic\n // `path`, which several of the newer tools also accept as a search root.\n if (tool === 'find_symbol' && args.symbol) {\n return `find_symbol ${args.symbol}${args.language ? ` [${args.language}]` : ''}`;\n }\n if (tool === 'web_search' && args.query) {\n return `web_search \"${ellipsize(String(args.query), 50)}\"`;\n }\n if (tool === 'fetch' && args.url) {\n return `fetch ${ellipsize(String(args.url), 60)}`;\n }\n // The pattern is what a glob is about; the generic `path` below is only its\n // search root, and reporting that read as \"glob src\" for every call.\n if (tool === 'glob' && args.pattern) {\n return `glob ${ellipsize(String(args.pattern), 50)}`;\n }\n if (tool === 'grep' && args.pattern) {\n const mode = args.output_mode && args.output_mode !== 'content' ? ` (${args.output_mode})` : '';\n const scope = args.include ? ` in ${args.include}` : '';\n return `grep ${ellipsize(String(args.pattern), 40)}${scope}${mode}`;\n }\n\n const path = args.filePath || args.file_path || args.path;\n if (path) {\n const basename = String(path).split('/').pop() || String(path);\n return `${display} ${basename}`;\n }\n if (args.pattern) {\n return `${display} ${args.pattern}`;\n }\n if (args.command) {\n return `bash: ${String(args.command).slice(0, 40)}`;\n }\n } catch {\n // fall through to the bare tool name below\n }\n return display;\n}\n\n/**\n * Classify a tool outcome from its result text and success flag, so a surface\n * can render a refused `rm` or a denied `npm test` distinctly from a\n * successful run without re-deriving the refusal signatures per surface. The\n * refusal/denial strings come from `commandPolicy.ts`, `BaseFileSystem.ts`,\n * `webReadPolicy.ts` and the research-subagent wrapper — keeping the matching\n * here means the signatures stay in one place alongside the human summary.\n */\nexport function classifyOutcome(success: boolean, output: string): ResearchStepOutcome {\n if (!success) {\n if (/^(Command|Fetch|Web search) refused:/.test(output) || /is not available\\. You are a read-only research subagent/.test(output)) return 'refused';\n if (/not approved/i.test(output) || /^Access denied:/.test(output) || /needs user approval/i.test(output)) return 'denied';\n return 'failure';\n }\n return 'success';\n}\n","import type { DiffStat, ToolHeadline } from './blocks';\n\n// eslint-disable-next-line no-control-regex\nconst ANSI_OR_CTRL_RE = /\\x1b\\[[0-9;?]*[A-Za-z]|\\x1b\\][^\\x07\\x1b]*(?:\\x07|\\x1b\\\\)?|\\x1b[()][AB012]|\\x1b[=>]|[\\x00-\\x08\\x0b-\\x1f\\x7f]/g;\n\n/**\n * How a command row names an Ordewell research tool. A harness planner's call\n * keeps the agent's own name instead (`toolLabel`, ADR-0009), so the row says\n * which tool actually ran.\n */\nconst DISPLAY_NAMES: Record<string, string> = {\n read_file: 'Read',\n read_files: 'Read',\n list_dir: 'List',\n glob: 'Glob',\n grep: 'Grep',\n find_symbol: 'Symbol',\n bash: 'Bash',\n fetch: 'Fetch',\n web_search: 'WebSearch',\n spawn_research_agent: 'Agent',\n};\n\n// Tried in order for a tool with no rule of its own: the field that names what\n// a call is about comes before the free text around it.\nconst HINT_FIELDS = ['file_path', 'filePath', 'path', 'url', 'pattern', 'query', 'command', 'description', 'prompt'] as const;\n\nfunction parseArgs(args: string): Record<string, unknown> | null {\n try {\n const parsed: unknown = JSON.parse(args);\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed as Record<string, unknown> : null;\n } catch {\n return null;\n }\n}\n\nfunction oneLine(text: string): string {\n return text.replace(/\\s+/g, ' ').trim();\n}\n\n// A command's later lines can change what it does (a heredoc body, a chained\n// step), so they are counted rather than folded into the first.\nfunction firstLineOf(command: string): string {\n const lines = command.trim().split(/\\r?\\n/);\n const more = lines.length - 1;\n return more > 0 ? `${lines[0]} … +${more} line${more === 1 ? '' : 's'}` : lines[0];\n}\n\nfunction text(value: unknown): string {\n return typeof value === 'string' ? value : '';\n}\n\nfunction searchArg(pattern: string, path: string, include = ''): string {\n return `${pattern}${path ? ` in ${path}` : ''}${include ? ` (${include})` : ''}`;\n}\n\nfunction hintArg(args: Record<string, unknown>): string {\n for (const field of HINT_FIELDS) {\n const value = text(args[field]);\n if (value) return field === 'command' ? firstLineOf(value) : oneLine(value);\n }\n const firstText = Object.values(args).find((v): v is string => typeof v === 'string' && v.trim() !== '');\n return firstText ? oneLine(firstText) : '';\n}\n\nfunction keyArgOf(tool: string, args: Record<string, unknown>): string {\n switch (tool) {\n case 'bash':\n return firstLineOf(text(args.command));\n case 'read_file':\n case 'list_dir':\n return text(args.path);\n case 'read_files':\n return Array.isArray(args.paths) ? args.paths.map(String).join(', ') : '';\n case 'glob':\n return searchArg(text(args.pattern), text(args.path));\n case 'grep':\n return searchArg(text(args.pattern), text(args.path), text(args.include));\n case 'find_symbol':\n return `${text(args.symbol)}${text(args.language) ? ` [${text(args.language)}]` : ''}`;\n case 'fetch':\n return text(args.url);\n case 'web_search':\n return oneLine(text(args.query));\n case 'spawn_research_agent':\n return oneLine(text(args.prompt));\n default:\n return hintArg(args);\n }\n}\n\n/**\n * The one-line head of a command row, shared by every surface: the tool's name\n * and the argument that says what the call is about.\n *\n * @param args The call's arguments as announced (JSON). Anything that is not a\n * JSON object is shown as it came, on one line.\n * @param toolLabel A harness planner's own name for the tool (ADR-0009).\n */\nexport function toolHeadline(tool: string, args: string, toolLabel?: string): ToolHeadline {\n const name = toolLabel?.trim() || DISPLAY_NAMES[tool] || tool;\n const parsed = parseArgs(args);\n return { name, keyArg: parsed ? keyArgOf(tool, parsed) : oneLine(args) };\n}\n\nexport interface OutputPreview {\n lines: string[];\n hiddenLineCount: number;\n}\n\n/** The lines of a tool's output as a reader sees them — what {@link outputPreview} shows and counts. */\nexport function outputLines(output: string): string[] {\n // Line endings first: CR is itself a control character the escape pass drops.\n const lines = output.replace(/\\r\\n?/g, '\\n').replace(ANSI_OR_CTRL_RE, '').split('\\n');\n while (lines.length > 0 && lines[lines.length - 1].trim() === '') lines.pop();\n return lines;\n}\n\n/** The head of a tool's output for a collapsed row, and how many lines it leaves out. */\nexport function outputPreview(output: string, maxLines: number): OutputPreview {\n const lines = outputLines(output);\n const shown = lines.slice(0, Math.max(0, maxLines));\n return { lines: shown, hiddenLineCount: lines.length - shown.length };\n}\n\n/**\n * The lines a diff adds and removes, or null when `output` is not one: every\n * line a hunk header, context, an addition or a removal, and at least one of\n * the last two.\n */\nexport function diffStat(output: string): DiffStat | null {\n const lines = outputLines(output);\n let added = 0;\n let removed = 0;\n for (const line of lines) {\n if (line.startsWith('+')) added += 1;\n else if (line.startsWith('-')) removed += 1;\n else if (!(line.startsWith('@@') || line.startsWith(' ') || line === '' || line.startsWith('\\\\'))) return null;\n }\n return added + removed > 0 ? { added, removed } : null;\n}\n\n/** `gap` stands between two hunks, for the lines a diff leaves out. */\nexport type DiffRowKind = 'added' | 'removed' | 'context' | 'gap';\n\nexport interface DiffRow {\n kind: DiffRowKind;\n /** The line in the file: the old file's for a removal, the new file's otherwise. */\n line?: number;\n text: string;\n}\n\nconst HUNK_RANGE = /^@@ -(\\d+)(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/;\n\n/** A diff as the rows a surface draws, numbered as an editor would number them. */\nexport function diffRows(output: string): DiffRow[] {\n const rows: DiffRow[] = [];\n let oldLine = 1;\n let newLine = 1;\n for (const line of outputLines(output)) {\n const range = HUNK_RANGE.exec(line);\n if (range) {\n if (rows.length > 0) rows.push({ kind: 'gap', text: '' });\n oldLine = Number(range[1]);\n newLine = Number(range[2]);\n } else if (line.startsWith('+')) {\n rows.push({ kind: 'added', line: newLine++, text: line.slice(1) });\n } else if (line.startsWith('-')) {\n rows.push({ kind: 'removed', line: oldLine++, text: line.slice(1) });\n } else if (!line.startsWith('\\\\')) {\n rows.push({ kind: 'context', line: newLine, text: line.slice(1) });\n oldLine += 1;\n newLine += 1;\n }\n }\n return rows;\n}\n\nfunction lines(count: number): string {\n return `${count} line${count === 1 ? '' : 's'}`;\n}\n\n/** \"Added 2 lines, removed 1 line\": the summary every surface puts on an edit's row. */\nexport function diffSummary({ added, removed }: DiffStat): string {\n if (!removed) return `Added ${lines(added)}`;\n if (!added) return `Removed ${lines(removed)}`;\n return `Added ${lines(added)}, removed ${lines(removed)}`;\n}\n","import type { ResearchToolType } from '../../models/Task';\n\n/**\n * Map a coding agent's own tool name onto Ordewell's research vocabulary\n * (ADR-0009, T5).\n *\n * A harness planner brings its own toolbox, and most of it overlaps ours: a\n * `Read` is a `read_file`, a `Grep` is a `grep`. Those map onto existing\n * members and render in every surface through the code path that is already\n * there. Everything else — `Edit`, `WebFetch`, `TodoWrite`, `Task`, whatever\n * ships next — becomes `agent_tool` carrying its real name.\n *\n * Nothing is relabelled as a tool it is not. Calling a web fetch a `bash` to\n * avoid adding a union member would put a lie in the timeline, which is the\n * point ADR-0008 spent its effort establishing.\n */\nconst KNOWN_TOOLS: Record<string, ResearchToolType> = {\n // Claude Code\n read: 'read_file',\n grep: 'grep',\n glob: 'glob',\n bash: 'bash',\n ls: 'list_dir',\n webfetch: 'fetch',\n websearch: 'web_search',\n // Codex — its sandboxed command tool is a shell by another name\n shell: 'bash',\n exec_command: 'bash',\n local_shell: 'bash',\n // OpenCode\n list: 'list_dir',\n fetch: 'fetch',\n // Ordewell's own research shell (ADR-0026), under every runner's name for it\n runcommand: 'bash',\n};\n\n/**\n * Claude Code and Codex call it `mcp__ordewell__<tool>`, OpenCode `ordewell_<tool>`.\n * Spelled out rather than built from `ORDEWELL_MCP_SERVER_NAME`: the webview\n * bundles this file, and `../mcp` brings the Node-only server with it.\n */\nconst ORDEWELL_TOOL_PREFIX = /^(mcp__ordewell__|ordewell_)/i;\n\n/**\n * The tools that write a file, by their normalized names: Claude Code's,\n * OpenCode's, and the change kinds a Codex row is named for. Their output is\n * a diff (see `fileDiff.ts`) when the runner reported one.\n */\nconst FILE_EDIT_TOOLS = new Set(['edit', 'write', 'multiedit', 'notebookedit', 'applypatch', 'patch', 'add', 'update', 'delete', 'filechange']);\n\nexport function isFileEditTool(name: string): boolean {\n return FILE_EDIT_TOOLS.has(name.trim().toLowerCase().replace(/[_-]/g, ''));\n}\n\nexport interface MappedTool {\n tool: ResearchToolType;\n /** The agent's own name, kept whenever it differs from the member it mapped to. */\n toolLabel?: string;\n}\n\n/**\n * Classify one agent tool name. Case- and separator-insensitive, because the\n * three agents disagree on `Read` vs `read` vs `read_file` for the same thing.\n */\nexport function mapAgentTool(name: string): MappedTool {\n const normalized = name.trim().replace(ORDEWELL_TOOL_PREFIX, '').toLowerCase().replace(/[_-]/g, '');\n const direct = KNOWN_TOOLS[normalized] ?? KNOWN_TOOLS[name.trim().toLowerCase()];\n if (direct) {\n // The label survives even on a mapped tool: `Read` and `read_file` render\n // the same way, but the transcript should still say which one ran.\n return { tool: direct, toolLabel: name };\n }\n return { tool: 'agent_tool', toolLabel: name };\n}\n\n/**\n * Normalize an agent's tool arguments into the shapes `summarizeToolCall`\n * already knows how to read, so a harness `Read` gets a one-line summary\n * instead of a bare tool name. Unknown keys are preserved — the raw args stay\n * visible under the surfaces' output chevron.\n */\nexport function normalizeAgentArgs(tool: ResearchToolType, args: Record<string, unknown>): Record<string, unknown> {\n const out = { ...args };\n const alias = (from: string, to: string) => {\n if (out[to] === undefined && out[from] !== undefined) out[to] = out[from];\n };\n if (tool === 'read_file' || tool === 'list_dir') {\n alias('filePath', 'path');\n alias('file_path', 'path');\n alias('target', 'path');\n }\n if (tool === 'bash') {\n alias('cmd', 'command');\n alias('script', 'command');\n // Codex hands the command over as an argv array; the summary wants a string.\n if (typeof out.command !== 'string' && Array.isArray(out.command)) {\n out.command = (out.command as unknown[]).join(' ');\n }\n }\n if (tool === 'fetch') alias('uri', 'url');\n if (tool === 'web_search') alias('q', 'query');\n return out;\n}\n","import type { ResearchStep, ResearchStepOutcome, SkillLoadNotice } from '../models/Task';\nimport type { UsageLine } from '../models/Usage';\nimport type { MessageBlock, MessageRole, PlanMarkerStatus, SkillLoadBlock, SubagentBlock, ToolBlock, ToolStatus, UsageBlock } from './blocks';\nimport { diffStat, outputLines, toolHeadline } from './format';\nimport { isFileEditTool } from '../services/harness/agentTools';\n\n/*\n * How the session's records — messages, research steps, subagents, transcript\n * markers, usage totals — read as blocks. Shared by the live view and the\n * reload, so the two cannot disagree about what a record shows.\n */\n\n/** A line that is done: nothing streams into it any more. */\nexport function settledMessage(id: string, role: MessageRole, text: string, turnId?: string): MessageBlock {\n return { type: 'message', id, role, text, streaming: false, ...(turnId ? { turnId } : {}) };\n}\n\n/** The user's message, marked with the skills it loaded when it loaded any, and when it was force sent. */\nexport function userMessage(id: string, text: string, skills: readonly SkillLoadNotice[], { turnId, forced }: { turnId?: string; forced?: boolean } = {}): MessageBlock {\n const block = settledMessage(id, 'user', text, turnId);\n return {\n ...block,\n ...(skills.length > 0 ? { skills: skills.map((s) => s.name) } : {}),\n ...(forced ? { forced: true } : {}),\n };\n}\n\n/** What a surface is told of a load: everything but the body, which only the planner is sent. */\nexport function skillLoadNotice({ invokedBy, name, source, path, attaches }: SkillLoadNotice): SkillLoadNotice {\n return { invokedBy, name, source, path, ...(attaches ? { attaches } : {}) };\n}\n\n/** `load_skill` as each harness names it: bare, `mcp__ordewell__load_skill`, `ordewell_load_skill`. */\nconst LOAD_SKILL_TOOL = /(?:^|_)load_skill$/;\n\n/**\n * A research step as a surface is sent it. A `load_skill` result is a skill's\n * body, which only the planner is sent; the session keeps it in the skill-load\n * entry, so the step need only say which skill loaded.\n */\nexport function surfaceStep(step: ResearchStep): ResearchStep {\n if (!step.success || !LOAD_SKILL_TOOL.test(step.toolLabel ?? step.tool)) return step;\n const name = loadedSkillName(step.args);\n return { ...step, result: name ? `Loaded skill ${name}.` : 'Loaded a skill.' };\n}\n\nfunction loadedSkillName(args: string): string | undefined {\n try {\n const parsed: unknown = JSON.parse(args);\n const name = typeof parsed === 'object' && parsed !== null && 'name' in parsed ? parsed.name : undefined;\n return typeof name === 'string' ? name : undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function skillLoadBlock(id: string, { invokedBy, name, source, path, attaches }: SkillLoadNotice, turnId?: string): SkillLoadBlock {\n return { type: 'skill_load', id, invokedBy, name, source, path, ...(attaches ? { attaches } : {}), ...(turnId ? { turnId } : {}) };\n}\n\ntype SubagentFields = Omit<SubagentBlock, 'type' | 'id' | 'toolCallId' | 'model' | 'usage' | 'turnId'>\n & { toolCallId?: string; model?: string; usage?: SubagentBlock['usage']; turnId?: string };\n\nexport function subagentBlock(id: string, { toolCallId, model, usage, turnId, ...fields }: SubagentFields): SubagentBlock {\n return {\n type: 'subagent', id, ...fields,\n ...(toolCallId ? { toolCallId } : {}),\n ...(model ? { model } : {}),\n ...(usage ? { usage } : {}),\n ...(turnId ? { turnId } : {}),\n };\n}\n\nexport function usageBlock(id: string, { totals, bySubagent, byModel, model, contextFill }: UsageLine): UsageBlock {\n return { type: 'usage', id, totals, ...(byModel ? { byModel } : {}), ...(model ? { model } : {}), ...(bySubagent ? { bySubagent } : {}), ...(contextFill ? { contextFill } : {}) };\n}\n\nconst STATUS_OF_OUTCOME: Record<ResearchStepOutcome, ToolStatus> = {\n success: 'ok',\n failure: 'error',\n refused: 'denied',\n denied: 'denied',\n not_executed: 'interrupted',\n};\n\nexport function finishedTool(call: ToolBlock, output: string, outcome: ResearchStepOutcome): ToolBlock {\n const diff = outcome === 'success' && isFileEditTool(call.toolLabel ?? call.tool) ? diffStat(output) : null;\n return { ...call, status: STATUS_OF_OUTCOME[outcome], outcome, output, outputLineCount: outputLines(output).length, ...(diff ? { diff } : {}) };\n}\n\nexport function settledTool(call: ToolBlock, step: ResearchStep): ToolBlock {\n return finishedTool(call, step.result, step.outcome);\n}\n\nexport interface AnnouncedCall {\n tool: string;\n toolLabel?: string;\n args: string;\n toolCallId?: string;\n turnId?: string;\n}\n\nexport function pendingTool(id: string, { tool, toolLabel, args, toolCallId, turnId }: AnnouncedCall): ToolBlock {\n return {\n type: 'tool', id, tool, headline: toolHeadline(tool, args, toolLabel), args, status: 'pending', output: '', outputLineCount: 0,\n ...(toolCallId ? { toolCallId } : {}),\n ...(toolLabel ? { toolLabel } : {}),\n ...(turnId ? { turnId } : {}),\n };\n}\n\n/** The row of a call known only from its result — a reload, or a result whose call was never announced. */\nexport function toolFromStep(id: string, step: ResearchStep, turnId?: string): ToolBlock {\n return settledTool(pendingTool(id, { ...step, turnId }), step);\n}\n\n/**\n * What a plan marker says, read from the transcript entry `PlannerConversation`\n * writes for it (\"Plan generated with 2 tasks.\", \"Plan updated — now 1 task.\").\n * That entry is the only record of the marker a reload has, so the live view\n * reads the same text rather than counting tasks itself.\n */\nexport function planMarker(content: string): { status: Exclude<PlanMarkerStatus, 'building'>; taskCount?: number } {\n const count = /(\\d+) tasks?\\b/.exec(content);\n return { status: content.startsWith('Plan updated') ? 'updated' : 'generated', ...(count ? { taskCount: Number(count[1]) } : {}) };\n}\n","/** What the blocked rule reads of a task; structural, so a surface's own task shape answers it too. */\nexport interface BlockingSubject {\n id: string;\n status: string;\n dependencies: readonly string[];\n subtasks?: readonly BlockingSubject[];\n}\n\n/** Statuses of a task that has not started, the only ones a block holds back. */\nconst UNSTARTED: ReadonlySet<string> = new Set(['pending', 'approved']);\n\n/**\n * The blocked rule (ADR-0034): a task not started yet is blocked while a\n * dependency failed or is itself blocked. One already at work — force-started,\n * or waiting on the user — is not, and does not pass a block on. Each\n * blocked task maps to the failed tasks it waits on, in dependency order and\n * named once; an unblocked task is absent. Nothing is stored, so a retry that\n * passes is all it takes to lift a block.\n *\n * Takes the plan tree or a flat list; a subtask follows the same rule.\n */\nexport function blockingFailures(tasks: readonly BlockingSubject[]): Map<string, string[]> {\n const byId = new Map<string, BlockingSubject>();\n const index = (list: readonly BlockingSubject[]): void => {\n for (const t of list) {\n byId.set(t.id, t);\n index(t.subtasks ?? []);\n }\n };\n index(tasks);\n\n const memo = new Map<string, string[]>();\n const failuresOf = (id: string, visiting: Set<string>): string[] => {\n const known = memo.get(id);\n if (known) return known;\n const task = byId.get(id);\n // A dependency cycle the planner left has no failure at its root.\n if (!task || !UNSTARTED.has(task.status) || visiting.has(id)) return [];\n visiting.add(id);\n const failed = new Set<string>();\n for (const depId of task.dependencies) {\n const dep = byId.get(depId);\n // A skipped dependency releases its dependents: nobody waits for it.\n if (!dep || dep.status === 'completed' || dep.status === 'skipped') continue;\n if (dep.status === 'failed') failed.add(depId);\n else for (const root of failuresOf(depId, visiting)) failed.add(root);\n }\n visiting.delete(id);\n const result = [...failed];\n memo.set(id, result);\n return result;\n };\n\n const blocked = new Map<string, string[]>();\n for (const id of byId.keys()) {\n const failures = failuresOf(id, new Set());\n if (failures.length > 0) blocked.set(id, failures);\n }\n return blocked;\n}\n","import type { AwaitingReason, ConversationMessage, LegacyPlanState, PlanState, PendingPlanTurn, ReplyRun, ResearchStep, RunnerId, RunSettings, SkillLoadNotice, SubagentOutcome, Task, TaskSkillNotice, TaskSnapshot, Verdict } from '../models/Task';\nimport type { AttemptUsage, ModelUsage, PlanUsage, UsageTotals } from '../models/Usage';\nimport type { ExecutionRecord } from '../models/Execution';\nimport type { TaskLogEvent } from '../models/TaskLog';\nimport type { ApprovalKind } from '../interfaces/IApproval';\nimport type { ApprovalSource } from './ApprovalPolicy';\nimport type { AutoMergeTrigger } from './TaskOrchestrator';\nimport type { IsolationHandoff, IsolationMergeResult, TaskIsolation } from '../interfaces/IWorktreeIsolation';\nimport type { QueuedTaskMessage } from '../interfaces/IRunner';\nimport { canContinue } from './continuation';\nimport { skillLoadNotice, surfaceStep } from '../conversation/records';\nimport { blockingFailures } from './blocking';\n\nexport type SerializedTaskStatus = {\n id: string;\n status: Task['status'];\n verdict: { outcome: 'pass' | 'fail'; reason: string; checks: Verdict['checks'] } | null;\n /** Advisory silence timestamp from VerdictEngine — not part of task status semantics. */\n idleSince?: string | null;\n /** Absent unless the plan has an isolation run, so a shared-root plan's updates are unchanged. */\n isolation?: TaskIsolation;\n /** What an `awaiting_user` task waits on, when it was saved (ADR-0018, W1). */\n awaitingReason?: AwaitingReason;\n /** When a task paused on a usage limit resumes on its own (ISO time); absent when it waits for a manual retry. */\n resumeAt?: string;\n /** Why a `skipped` task was skipped; absent when no reason was given, and on any other status. */\n skipReason?: string;\n /** The whole question of the checkpoint the task waits at; absent when it waits at none. */\n checkpoint?: string;\n /** Messages waiting for a structured task's turn to end, oldest first; absent when there are none. */\n queued?: QueuedTaskMessage[];\n /** Set when the task can be continued in its saved runner session (ADR-0018, K1); the id itself stays in the daemon. */\n continuable?: true;\n /**\n * How many of a structured task's runner requests wait for an answer\n * (ADR-0018, A1) — \"waiting for approval\", which leaves `status` alone.\n * Absent when none do.\n */\n awaitingApproval?: number;\n /**\n * The ancestors an ops or user task waits on at its merge gate: their\n * work has landed but is not merged into the user's branch (ADR-0020).\n * Absent when it waits for no Merge all.\n */\n mergeGate?: string[];\n /** The ancestors, by title, a force start went past the merge gate of (ADR-0020). */\n forcedPastGate?: string[];\n /**\n * Added after the user approved the plan and not approved since, so the\n * scheduler leaves it for them (ADR-0035). Absent for any other task.\n */\n waitsForApproval?: true;\n attemptUsage?: AttemptUsage[];\n};\n\n/**\n * Landed work not yet in the user's branch. `paused` means the running plan\n * waits at a merge gate with no attempts active.\n */\nexport interface RunMergeView {\n waitingAtGate: boolean;\n paused: boolean;\n repos: IsolationHandoff['repos'];\n landed: IsolationHandoff['landed'];\n}\n\nexport type SerializedTask = {\n id: string;\n order: number;\n title: string;\n type: string;\n /** Without it a plan broadcast after a run reads as every task pending. */\n status: Task['status'];\n description: string;\n dependencies: string[];\n assignedRunner: RunnerId;\n assignedModel: Task['assignedModel'] | null;\n taskMode: string;\n prompt: string | null;\n subtasks: SerializedTask[];\n userSteps: Task['userSteps'];\n autonomy: Task['autonomy'];\n sliceType: Task['sliceType'];\n userStoriesCovered: Task['userStoriesCovered'];\n /** As on {@link SerializedTaskStatus}: only while the task is `awaiting_user`. */\n awaitingReason?: AwaitingReason;\n resumeAt?: string;\n /** As on {@link SerializedTaskStatus}: only while the task is `skipped`. */\n skipReason?: string;\n /** Set only on an ops task (ADR-0020). */\n ops?: true;\n /** Task skills attached by name; absent when none. */\n skills?: string[];\n /** Set only on a task an Act supervisor added (ADR-0029). */\n addedBy?: 'supervisor';\n attemptUsage?: AttemptUsage[];\n};\n\n/** Skill loads go out as notices: their bodies are for the planner, and stay in the session. */\nexport type SerializedConversationMessage = Omit<ConversationMessage, 'skill'> & { skill?: SkillLoadNotice };\nexport type SerializedPendingTurn = Omit<PendingPlanTurn, 'skills'> & { skills?: SkillLoadNotice[] };\n\n/**\n * A task as a surface is sent it: its attempt's skills are notices, whole in\n * the session only, and its runner session id stays there too — no surface shows it,\n * and only a continue reads the runner's own session id.\n */\nexport type SurfaceTask<T extends Task = Task> = Omit<T, 'attemptSkills' | 'subtasks' | 'runnerSessionId'> & {\n attemptSkills?: TaskSkillNotice[];\n subtasks: SurfaceTask[];\n};\n\n/** A plan as the daemon and the VS Code webview are sent it: the session's own state, minus every skill body. */\nexport type SurfacePlan = Omit<LegacyPlanState, 'tasks' | 'conversationHistory' | 'pendingTurns' | 'queuedMessages'> & {\n tasks: SurfaceTask[];\n conversationHistory?: SerializedConversationMessage[];\n pendingTurns?: SerializedPendingTurn[];\n};\n\n/** The phase-tagged shape of {@link SurfacePlan}. */\nexport type SurfacePlanState =\n | (Omit<Extract<PlanState, { phase: 'planning' }>, 'pendingTasks'> & { pendingTasks: SurfaceTask[] })\n | (Omit<Extract<PlanState, { phase: 'executing' }>, 'pendingTasks' | 'executionLog'> & { pendingTasks: SurfaceTask[]; executionLog: SurfaceTask<TaskSnapshot>[] });\n\nexport type SerializedPlan = {\n runSettings?: LegacyPlanState['runSettings'];\n /** What waits on the planner's usage limit, and when it goes, so a surface can say so and offer to cancel it. */\n plannerResend?: LegacyPlanState['plannerResend'];\n tasks: SerializedTask[];\n runners: RunnerId[];\n generatedAt: string;\n conversationHistory?: SerializedConversationMessage[];\n prdMarkdown?: string;\n};\n\n/** What a held edit does to a task once it lands. */\nexport type HeldEditMark = 'added' | 'changed' | 'removed';\n\n/**\n * The plan as the open planner turn's edit would leave it, in plan order with\n * the removed tasks where they were; flat, a subtask after its parent. `label`\n * is the task's `#2.1` reference; `mark` is absent for a task the edit leaves\n * alone. Proposed, not approved: the tasks need the user's go-ahead to run.\n */\nexport interface HeldEdit {\n turnId: string;\n tasks: Array<{ label: string; mark?: HeldEditMark; task: SerializedTask }>;\n}\n\n/** How a planner turn ended: the reply kind it settled on, a user stop, or a failure. */\nexport type PlannerTurnOutcome = 'message' | 'plan' | 'task_ops' | 'stopped' | 'error';\n\n/**\n * Everything a session tells its surfaces, over one broadcast seam.\n *\n * A planner turn (#47) streams between `planner_turn_started` and\n * `planner_turn_ended` with the same `turnId`; every turn-scoped message in\n * between carries it. The stream is provisional and the settled messages are\n * authoritative:\n * - `planner_message` settles the streamed text of each run it carries in that\n * run's segment, where it streamed — a surface drops what it accumulated\n * there and shows the run's text instead.\n * - A reply that is a JSON envelope (plan, taskOps, taskQuery) never arrives\n * as `planner_text_delta`; it streams as `plan_token`, the \"building plan\"\n * display.\n * - A subagent's own text never appears in the reply; its activity arrives\n * tagged with its `subagentId`.\n */\nexport type SessionMessage =\n /**\n * The plan, whole. `turnId` names the planner turn whose commit this\n * broadcast carries, so the turn's building plan becomes the marker; it is\n * absent on every other broadcast of the plan.\n */\n | { type: 'plan_generated'; plan: SerializedPlan; goal: string; runners: RunnerId[]; turnId?: string }\n /**\n * The settled reply of a planner turn, emitted by the session once the turn\n * is classified. `turnId` is absent for replies sent outside a streamed turn.\n * `supervisor`: the supervisor said it in a wake-up turn (ADR-0029).\n * `runs`: what the reply shows, run by run, each authoritative over its\n * segment's `planner_text_delta`s; `content` stays the whole reply. Without\n * runs (a note the conversation wrote, an older daemon) the message is\n * authoritative over the turn's final segment.\n */\n | { type: 'planner_message'; content: string; timestamp: string; turnId?: string; supervisor?: true; runs?: ReplyRun[] }\n /**\n * A planner turn began. Emitted once per turn by whoever runs the turn,\n * before any other message carrying its `turnId`. `prompt` is the user's\n * message, as typed, when the turn answers one; `skills` are what its\n * `/name` tokens loaded, absent when none did. `wakeUps` are the wake-up\n * digests the turn delivers, shown ahead of the prompt; `supervisor` marks a\n * wake-up turn, which no user message opened (ADR-0029). `forced`: the\n * prompt was force sent, and this turn replaces the one it stopped.\n */\n | { type: 'planner_turn_started'; turnId: string; prompt?: string; skills?: SkillLoadNotice[]; wakeUps?: string[]; supervisor?: true; forced?: true }\n | { type: 'planner_skill_loaded'; turnId: string; skill: SkillLoadNotice }\n /**\n * What the open planner turn's task edit would leave, sent whenever the\n * edit it holds changes (ADR-0029: it lands as the reply ends). `held` is\n * null once nothing is held: the edit landed, was refused as it landed, or\n * the turn ended without it. The plan itself is untouched until it lands.\n */\n | { type: 'plan_edit_held'; held: HeldEdit | null }\n /**\n * A planner turn is over; nothing more carries its `turnId`. Emitted exactly\n * once per `planner_turn_started`, stop and failure included, after the\n * turn's `planner_message` when it has one. `forceSent`: a force send\n * stopped it, and the forced turn follows — the user did not stop the\n * conversation, so a surface keeps the prompts it holds (ADR-0023, F2).\n */\n | { type: 'planner_turn_ended'; turnId: string; outcome: PlannerTurnOutcome; forceSent?: true }\n /**\n * Reply prose as it streams, appended in order within its segment. A segment\n * is one continuous run of model text; text before a tool call is its own\n * segment, and a later segment never rewrites an earlier one. Never carries\n * a JSON envelope or a subagent's text (see the union's invariants).\n */\n | { type: 'planner_text_delta'; turnId: string; segmentId: string; text: string }\n /**\n * Exposed reasoning as it streams, from the planner or — tagged with\n * `subagentId` — from one of its subagents. Never part of the reply. The one\n * thinking message for every backend: `segmentId` is set only where the\n * backend streams thinking in segments (the API loops; harness planners do\n * not), and `turnId` is absent for thinking outside a turn (one-shot plans).\n */\n | { type: 'planner_thinking_delta'; turnId?: string; segmentId?: string; subagentId?: string; text: string }\n /**\n * Text streamed for an attempt the turn discarded (a corrective retry) is\n * taken back: a surface removes it. With `segmentId`, only that segment;\n * without, all of the turn's text not yet settled by a `planner_message`.\n * A segment that streamed to the plan display (`plan_token`) takes the\n * turn's building plan with it.\n */\n | { type: 'planner_text_retracted'; turnId: string; segmentId?: string }\n /**\n * The planner's running usage for the session, subagents included, emitted\n * after a model call reports usage. `totals` already contains every\n * `bySubagent` entry. `contextFill` is the last planner prompt against the\n * model's window, omitted when the window is unknown. Cost appears only as\n * reported by a provider or runner (see `UsageRecord`).\n */\n | {\n type: 'planner_usage';\n byModel?: ModelUsage[];\n model?: string;\n turnId?: string;\n totals: UsageTotals;\n bySubagent?: Record<string, UsageTotals>;\n contextFill?: { usedTokens: number; windowTokens: number };\n }\n /**\n * A subagent began work on `brief`. Emitted by the planner backend that\n * spawned it (ADR-0005 research agents, or a harness planner's own), before\n * any message tagged with its `subagentId`.\n */\n | { type: 'subagent_started'; turnId?: string; subagentId: string; brief: string; model?: string }\n /**\n * A subagent is done; nothing more is tagged with its `subagentId`. Emitted\n * once per `subagent_started`. `digest` is what it handed back to the\n * planner; `usage` is its own share, already counted in `planner_usage`.\n */\n | { type: 'subagent_finished'; turnId?: string; subagentId: string; outcome: SubagentOutcome; digest: string; usage?: UsageTotals }\n | { type: 'status_update'; tasks: SerializedTaskStatus[]; runMerge?: RunMergeView; usage?: PlanUsage }\n | { type: 'review_needed'; tasks: SerializedTask[] }\n | { type: 'review_approved' }\n | { type: 'checkpoint'; taskId: string; taskTitle: string; summary: string }\n | { type: 'execution_complete'; summary: ExecutionSummary }\n | { type: 'execution_stopped' }\n // A call at the command seam (ADR-0029), with who made it: `text` is the\n // line the transcript keeps for it, so a reload shows what was shown live.\n | { type: 'execution_action'; record: ExecutionRecord; text: string }\n | { type: 'task_updated'; taskId: string; changes: Record<string, unknown> }\n | { type: 'task_started'; taskId: string; order: number; title: string; runner: RunnerId; modelId?: string }\n | { type: 'task_output'; taskId: string; text: string }\n /**\n * A structured task's log as it happens (ADR-0018, P1): the next events of\n * the task's attempt `attempt`, in order — the same ones appended to that\n * attempt's file, so a surface folding these and one replaying the file\n * draw the same blocks.\n */\n | { type: 'task_log'; taskId: string; attempt: number; events: TaskLogEvent[] }\n // A run did not start because tracked files are modified. It waits for the\n // user to stash (`continueWithStash`) or to run without isolation this once\n // (`continueWithoutIsolation`); nothing is spawned until then. `repos` names\n // the dirty repos of a group; a group of one names none.\n | { type: 'isolation_blocked'; reason: 'dirty'; repos?: string[]; message: string }\n // An isolated run settled: for each repo, the branch its work landed on and\n // the commit that branch forked from; and what landed, in plan order. Sent\n // before `execution_complete`, which surfaces treat as the end of the stream.\n // `deferredTo`: an Act supervisor handles it first; the unmarked handoff\n // that follows its wake-up turn, if the run is still unmerged, comes after.\n | { type: 'isolation_handoff'; repos: IsolationHandoff['repos']; landed: IsolationHandoff['landed']; deferredTo?: IsolationHandoff['deferredTo'] }\n // What \"Merge all\" did, for every surface watching rather than only the one\n // that asked: merged, blocked with each repo and why, or stopped part-way\n // with the repos that stay merged. `trigger`: Ordewell ran it by itself,\n // at a merge gate or at the run's end, with merge at gates automatically on.\n | { type: 'isolation_merge'; result: IsolationMergeResult; trigger?: AutoMergeTrigger }\n // The Session cleared the isolated run up and forgot it: a Merge all that\n // left nothing to hand over, or a discard. Sent after the `isolation_merge`\n // that caused it, and never for a merge that leaves the run going. The one\n // word on it: a surface folds this rather than guessing from a merge result.\n | { type: 'run_closed' }\n // Carries no content — see `ResearchProgress['liveness']`. Exists only so a\n // surface's idle watchdog sees the harness process working even during a\n // stretch that produces nothing visible.\n | { type: 'planner_liveness' }\n // `toolLabel` carries a harness planner's own name for the tool (ADR-0009) —\n // always set when `tool` is `agent_tool`, so no surface has to render the\n // catch-all member name at the user.\n | { type: 'research_step'; tool: string; toolLabel?: string; args: string; subagentId?: string; toolCallId?: string; turnId?: string }\n // The \"building plan\" display only: a JSON envelope as it streams, never\n // reply prose. `turnId` is absent for a one-shot plan, which has no turn.\n // `segmentId` names the segment the envelope streams in; a turn's next\n // envelope is a new segment, and the display starts over with it.\n | { type: 'plan_token'; token: string; turnId?: string; segmentId?: string }\n | { type: 'research_step_done'; step: ResearchStep; subagentId?: string; turnId?: string }\n // Planner research wants something outside its default envelope and is\n // blocked until a human answers. Broadcast rather than returned, because the\n // human may be on any surface (or several at once) and the request outlives\n // whichever HTTP call triggered it.\n | { type: 'approval_request'; id: string; kind: ApprovalKind; subject: string; scope: string; detail?: string; turnId?: string }\n | { type: 'approval_settled'; id: string; granted: boolean }\n // A decision reached with no round-trip prompt: pre-approved via config,\n // remembered from earlier in this session, or the operator's mode floor\n // (allow/deny skipping the human entirely). The interactive path above\n // already has full visibility via approval_request/approval_settled; this\n // is the one that previously had none — a model silently auto-running\n // `npm test` because the scope was already granted looked identical, from\n // every UI, to it never having been asked in the first place.\n | {\n type: 'approval_decided';\n kind: ApprovalKind;\n subject: string;\n scope: string;\n detail?: string;\n granted: boolean;\n source: Exclude<ApprovalSource, 'asked'>;\n };\n\n/**\n * A plan a surface read whole rather than off the message stream: a route's\n * answer, a loaded session. Folds into a {@link RunView} as a plan refresh.\n */\nexport type PlanSnapshot = { type: 'plan_snapshot'; plan: SurfacePlan | SurfacePlanState };\n\n/** What only the status stream says about a task; a plan refresh keeps these as they were. */\nexport type RunTaskStatus = Partial<Pick<\n SerializedTaskStatus,\n 'verdict' | 'idleSince' | 'isolation' | 'checkpoint' | 'queued' | 'continuable' | 'awaitingApproval' | 'mergeGate' | 'forcedPastGate' | 'waitsForApproval'\n>>;\n\n/** A task in the run view: the plan's fields, then the status stream's. */\nexport type RunTask = Omit<SerializedTask, 'subtasks'> & RunTaskStatus & { subtasks: RunTask[] };\n\n/**\n * A session's run as every surface draws it (the [run view](../../../../CONTEXT.md)):\n * folded from {@link SessionMessage}s and plan snapshots by `reduceRun`, or\n * taken whole from `Session.runSnapshot()` by a surface that joins late.\n */\nexport interface RunView {\n /** In plan order, subtasks nested under their parent. */\n tasks: RunTask[];\n runSettings?: RunSettings;\n runMerge: RunMergeView | null;\n usage?: PlanUsage;\n handoff: IsolationHandoff | null;\n mergeResult: IsolationMergeResult | null;\n /** The edit the open planner turn holds, as it would leave the plan; absent when it holds none. */\n heldEdit?: HeldEdit;\n}\n\nexport type RunInput = SessionMessage | PlanSnapshot;\n\n/**\n * A line a run wants the user to read — how it isolates, what it shares. Not a\n * {@link SessionMessage}: hosts that show notices as toasts already do, and\n * widening the union would break every exhaustive switch over it. A host with\n * no toast channel (the daemon) hands these to its clients by its own means.\n */\nexport type SessionNotice = { type: 'notice'; level: 'info' | 'warn' | 'error'; message: string };\n\nexport type SessionBroadcaster = (msg: SessionMessage) => void;\n\nexport function serializeTask(t: SurfaceTask): SerializedTask {\n return {\n id: t.id,\n order: t.order,\n title: t.title,\n type: t.type,\n status: t.status,\n description: t.description,\n dependencies: t.dependencies || [],\n assignedRunner: t.assignedRunner,\n assignedModel: t.assignedModel || null,\n taskMode: t.taskMode || 'build',\n prompt: t.prompt || null,\n subtasks: (t.subtasks || []).map(serializeTask),\n userSteps: t.userSteps || undefined,\n autonomy: t.autonomy || undefined,\n sliceType: t.sliceType || undefined,\n userStoriesCovered: t.userStoriesCovered || undefined,\n ...(t.status === 'awaiting_user' && t.awaitingReason ? { awaitingReason: t.awaitingReason } : {}),\n ...(t.status === 'awaiting_user' && t.awaitingReason === 'usage-limit' && t.resumeAt ? { resumeAt: t.resumeAt } : {}),\n ...(t.status === 'skipped' && t.skipReason ? { skipReason: t.skipReason } : {}),\n ...(t.ops ? { ops: true as const } : {}),\n ...(t.attemptUsage ? { attemptUsage: structuredClone(t.attemptUsage) } : {}),\n ...(t.skills?.length ? { skills: [...t.skills] } : {}),\n ...(t.addedBy ? { addedBy: t.addedBy } : {}),\n };\n}\n\nexport function serializeTaskStatus(\n t: Task,\n idleSince: string | null = null,\n isolation: TaskIsolation | null = null,\n queued: readonly QueuedTaskMessage[] = [],\n awaitingApproval = 0,\n mergeGate: readonly string[] = [],\n checkpoint = '',\n waitsForApproval = false,\n): SerializedTaskStatus {\n return {\n id: t.id,\n status: t.status,\n verdict: t.verdict\n ? { outcome: t.verdict.outcome, reason: t.verdict.reason, checks: t.verdict.checks || [] }\n : null,\n idleSince,\n ...(t.attemptUsage ? { attemptUsage: structuredClone(t.attemptUsage) } : {}),\n ...(isolation ? { isolation } : {}),\n ...(t.status === 'awaiting_user' && t.awaitingReason ? { awaitingReason: t.awaitingReason } : {}),\n ...(t.status === 'awaiting_user' && t.awaitingReason === 'usage-limit' && t.resumeAt ? { resumeAt: t.resumeAt } : {}),\n ...(t.status === 'awaiting_user' && t.awaitingReason === 'checkpoint' && checkpoint ? { checkpoint } : {}),\n ...(t.status === 'skipped' && t.skipReason ? { skipReason: t.skipReason } : {}),\n ...(queued.length > 0 ? { queued: queued.map((m) => ({ ...m })) } : {}),\n ...(canContinue(t) ? { continuable: true as const } : {}),\n ...(awaitingApproval > 0 ? { awaitingApproval } : {}),\n ...(mergeGate.length > 0 ? { mergeGate: [...mergeGate] } : {}),\n ...(t.forcedPastGate?.length ? { forcedPastGate: [...t.forcedPastGate] } : {}),\n ...(waitsForApproval ? { waitsForApproval: true as const } : {}),\n };\n}\n\nfunction surfaceConversation(history: LegacyPlanState['conversationHistory']): SerializedConversationMessage[] | undefined {\n return history?.map(({ skill, ...m }) => (skill ? { ...m, skill: skillLoadNotice(skill) } : m));\n}\n\nfunction surfacePendingTurns(pending: LegacyPlanState['pendingTurns']): SerializedPendingTurn[] | undefined {\n return pending?.map(({ skills, ...t }) => (skills ? { ...t, skills: skills.map(skillLoadNotice) } : t));\n}\n\nexport function surfaceTask<T extends Task>({ attemptSkills, subtasks, runnerSessionId: _runnerSessionId, ...task }: T): SurfaceTask<T> {\n return {\n ...task,\n ...(attemptSkills ? { attemptSkills: attemptSkills.map(({ name, source, path }): TaskSkillNotice => ({ name, source, path })) } : {}),\n subtasks: (subtasks ?? []).map(surfaceTask),\n };\n}\n\n/** The one place a plan's skill bodies come off before it leaves the session: every wire path that carries plan state goes through here. */\nexport function surfacePlan({ queuedMessages: _carriedOverAtLoad, ...plan }: LegacyPlanState): SurfacePlan {\n return {\n ...plan,\n tasks: plan.tasks.map(surfaceTask),\n conversationHistory: surfaceConversation(plan.conversationHistory),\n pendingTurns: surfacePendingTurns(plan.pendingTurns),\n researchLog: plan.researchLog?.map((e) => ('type' in e ? e : surfaceStep(e))),\n };\n}\n\nexport function surfacePlanState(state: PlanState): SurfacePlanState {\n return state.phase === 'planning'\n ? { ...state, pendingTasks: state.pendingTasks.map(surfaceTask) }\n : { ...state, pendingTasks: state.pendingTasks.map(surfaceTask), executionLog: state.executionLog.map(surfaceTask) };\n}\n\nexport function serializePlan(plan: LegacyPlanState): SerializedPlan {\n return {\n tasks: plan.tasks.map(serializeTask),\n runners: plan.runners,\n generatedAt: plan.generatedAt,\n runSettings: plan.runSettings,\n ...(plan.plannerResend ? { plannerResend: plan.plannerResend } : {}),\n conversationHistory: surfaceConversation(plan.conversationHistory),\n prdMarkdown: plan.prdMarkdown,\n };\n}\n\n/**\n * What a finished run did, task by task: `blocked` are those a failure kept\n * from starting (ADR-0034); `skipped` ended without a verdict and landed\n * nothing, so they are neither completed nor failed.\n */\nexport interface ExecutionSummary {\n total: number;\n completed: number;\n failed: number;\n blocked: number;\n skipped: number;\n}\n\nexport function executionSummary(tasks: readonly Task[]): ExecutionSummary {\n const blocked = blockingFailures(tasks);\n return {\n total: tasks.length,\n completed: tasks.filter((t) => t.status === 'completed').length,\n failed: tasks.filter((t) => t.status === 'failed').length,\n blocked: tasks.filter((t) => blocked.has(t.id)).length,\n skipped: tasks.filter((t) => t.status === 'skipped').length,\n };\n}\n\nexport const CHECKPOINT_TRUNCATE_LENGTH = 120;\n\n/** Truncate a checkpoint summary to a single line of at most CHECKPOINT_TRUNCATE_LENGTH chars. */\nexport function truncateCheckpointSummary(summary: string): string {\n // Take the first line only (checkpoint summaries often contain reasoning across lines)\n const firstLine = summary.split('\\n')[0].trim();\n if (firstLine.length <= CHECKPOINT_TRUNCATE_LENGTH) return firstLine;\n return firstLine.slice(0, CHECKPOINT_TRUNCATE_LENGTH - 1) + '…';\n}\n","/**\n * Pure, no-imports helper so a browser surface can format a conflict's files\n * without pulling `isolationRecord` — and its `path` import — into a webview\n * bundle. Kept out of `isolationRecord.ts` for exactly that reason.\n */\nexport function capConflictFiles(files: string[], max = 5): string {\n return files.length <= max ? files.join(', ') : `${files.slice(0, max).join(', ')}, +${files.length - max} more`;\n}\n","import type { SupervisorLevel } from '../models/Execution';\nimport type { GlobalRunSettings } from './SettingsService';\n\n/** How every surface words the run settings (ADR-0030), so they all say the same thing. */\n\nexport const SUPERVISOR_LEVEL_LABEL: Record<SupervisorLevel, string> = { off: 'Off', watch: 'Watch', act: 'Act' };\n\nconst plural = (n: number, one: string, many: string): string => `${n} ${n === 1 ? one : many}`;\nconst onOff = (value: boolean): string => (value ? 'on' : 'off');\n\nexport const supervisorSummary = (run: GlobalRunSettings): string =>\n `Supervisor: ${SUPERVISOR_LEVEL_LABEL[run.supervisorLevel]}, ${plural(run.supervisorRetryLimit, 'retry', 'retries')} per task, ${plural(run.wakeUpReadBudget, 'read', 'reads')} per wake-up`;\nexport const automergeSummary = (run: GlobalRunSettings): string => `Merge automatically (gates, end of run): ${onOff(run.mergeAtGatesAutomatically)}`;\nexport const autorunSummary = (run: GlobalRunSettings): string => `Autorun: ${onOff(run.autorun)}`;\n\nexport const ACT_RISK = 'Tasks it adds run too, ops tasks included, which can act on real systems unattended.';\nexport const AUTORUN_RISK = 'Plans start without review, ops tasks included, which can act on real systems unattended. In Full, the planner may also start tasks it adds later.';\n\n/** `on`/`off` as a switch's value; null for anything else. */\nexport function parseSwitch(arg: string): boolean | null {\n return arg === 'on' ? true : arg === 'off' ? false : null;\n}\n\n/** A whole number at least `min`, as typed; null for anything else. */\nexport function parseCount(arg: string | undefined, min: number): number | null {\n if (arg === undefined || !/^\\d+$/.test(arg)) return null;\n const n = Number(arg);\n return n >= min ? n : null;\n}\n","/**\n * What one model call consumed, as its provider or runner reported it. Shared\n * by the planner's usage line (#49) and per-attempt task usage (#26): a record\n * says nothing about who asked for the call, so either can hold a list of them.\n *\n * Every measure is optional because backends report different subsets. An\n * absent field means \"not reported\" — never zero — so a total can tell the two\n * apart.\n */\nexport interface UsageRecord {\n /** The provider or runner id that reported the call — `openai`, `claude-code`, … */\n source: string;\n model?: string;\n /** A session breakdown can name a model without identifying the current context. */\n aggregate?: true;\n inputTokens?: number;\n outputTokens?: number;\n /** The share of `inputTokens` served from the provider's prompt cache. */\n cachedInputTokens?: number;\n /**\n * Filled only from a provider's or runner's own report, never from a price\n * table or an estimate: prices go stale, and a subscription runner has no\n * per-token price at all. No report means no cost, not a guessed one.\n */\n reportedCost?: { amount: number; currency: string };\n /**\n * The model's context window: as the runner or provider reported it, or,\n * when it reported none, from that runner's or provider's own model listing\n * (`ContextWindowFill`). Never from a table kept in Ordewell.\n */\n contextWindow?: number;\n /** Set when a subagent made the call; its usage still counts toward the total. */\n subagentId?: string;\n}\n\n/**\n * A running sum of {@link UsageRecord}s. A measure stays absent until some\n * record reports it. Cost is kept per currency: two runners may bill in\n * different ones, and there is no honest exchange rate to fold them together.\n */\nexport interface UsageTotals {\n inputTokens?: number;\n outputTokens?: number;\n cachedInputTokens?: number;\n reportedCost?: Record<string, number>;\n}\n\n/**\n * The input side of a call whose provider reports its prompt in parts — the\n * uncached tail, with cache reads and cache writes beside it rather than inside\n * it (Anthropic, and OpenCode after it). The prompt the model saw is all three;\n * only the reads were served from cache, since a write is billed as fresh\n * input. A part left unreported adds nothing, and with no part reported there\n * is no measure at all.\n */\nexport function partedPromptUsage(parts: { uncached?: number; cacheRead?: number; cacheWrite?: number }): Pick<UsageRecord, 'inputTokens' | 'cachedInputTokens'> {\n const reported = [parts.uncached, parts.cacheRead, parts.cacheWrite].filter((n): n is number => n !== undefined);\n return {\n ...(reported.length > 0 ? { inputTokens: reported.reduce((a, b) => a + b, 0) } : {}),\n ...(parts.cacheRead !== undefined ? { cachedInputTokens: parts.cacheRead } : {}),\n };\n}\n\nconst TOKEN_FIELDS = ['inputTokens', 'outputTokens', 'cachedInputTokens'] as const;\n\nexport function addUsage(totals: UsageTotals, record: UsageRecord): UsageTotals {\n const next: UsageTotals = { ...totals };\n for (const field of TOKEN_FIELDS) {\n const reported = record[field];\n if (reported !== undefined) next[field] = (totals[field] ?? 0) + reported;\n }\n if (record.reportedCost) {\n const { amount, currency } = record.reportedCost;\n next.reportedCost = { ...totals.reportedCost, [currency]: (totals.reportedCost?.[currency] ?? 0) + amount };\n }\n return next;\n}\n\n/**\n * What the planner has consumed over a session (#49). `totals` includes every\n * `bySubagent` entry. `lastPromptTokens` and `contextWindow` track the\n * planner's own calls only — a subagent runs its own model, whose window says\n * nothing about the planner's.\n */\nexport interface PlannerUsage {\n totals: UsageTotals;\n bySubagent?: Record<string, UsageTotals>;\n byModel?: ModelUsage[];\n source?: string;\n model?: string;\n lastPromptTokens?: number;\n contextWindow?: number;\n}\n\nexport function addPlannerUsage(usage: PlannerUsage, record: UsageRecord): PlannerUsage {\n const next: PlannerUsage = { ...usage, totals: addUsage(usage.totals, record), byModel: addModelUsage(usage.byModel ?? [], record) };\n if (record.subagentId) {\n next.bySubagent = { ...usage.bySubagent, [record.subagentId]: addUsage(usage.bySubagent?.[record.subagentId] ?? {}, record) };\n return next;\n }\n if (!record.aggregate) {\n if (record.source !== usage.source || record.model !== usage.model) {\n delete next.lastPromptTokens;\n delete next.contextWindow;\n }\n next.source = record.source;\n next.model = record.model;\n }\n if (record.inputTokens !== undefined) next.lastPromptTokens = record.inputTokens;\n // A reported window of 0 means \"not known\", not \"no room\": keep it out so the\n // fill is omitted rather than shown against a guessed zero.\n if (record.contextWindow !== undefined) next.contextWindow = record.contextWindow > 0 ? record.contextWindow : undefined;\n return next;\n}\n\n/** Whether any measure was reported: a token line of nothing but blanks says nothing. */\nexport function isMeasured(totals: UsageTotals): boolean {\n return totals.inputTokens !== undefined || totals.outputTokens !== undefined || totals.cachedInputTokens !== undefined\n || Object.keys(totals.reportedCost ?? {}).length > 0;\n}\n\n/** What the token line shows of a ledger — live from its broadcast, or reloaded from the saved one. */\nexport interface UsageLine {\n byModel?: ModelUsage[];\n model?: string;\n totals: UsageTotals;\n bySubagent?: Record<string, UsageTotals>;\n contextFill?: { usedTokens: number; windowTokens: number };\n}\n\nexport function usageLine(usage: PlannerUsage): UsageLine {\n const contextFill = plannerContextFill(usage);\n return {\n totals: usage.totals,\n ...(usage.byModel ? { byModel: usage.byModel } : {}),\n ...(usage.model ? { model: usage.model } : {}),\n ...(usage.bySubagent ? { bySubagent: usage.bySubagent } : {}),\n ...(contextFill ? { contextFill } : {}),\n };\n}\n\n/**\n * The last planner prompt against its window, or undefined while either is\n * unknown. `usedTokens` is the prompt total as reported, cached tokens\n * included: a cached token still occupies the window, so subtracting the\n * cached share would understate how full the context is. A window of 0 is\n * treated as unknown — never guessed.\n */\nexport function plannerContextFill(usage: PlannerUsage): { usedTokens: number; windowTokens: number } | undefined {\n if (usage.lastPromptTokens === undefined || usage.contextWindow === undefined || usage.contextWindow <= 0) return undefined;\n return { usedTokens: usage.lastPromptTokens, windowTokens: usage.contextWindow };\n}\n\nexport interface ModelUsage {\n source: string;\n model?: string;\n totals: UsageTotals;\n}\n\nexport function addModelUsage(models: readonly ModelUsage[], record: UsageRecord): ModelUsage[] {\n const index = models.findIndex((m) => m.source === record.source && m.model === record.model);\n if (index < 0) return [...models, { source: record.source, ...(record.model ? { model: record.model } : {}), totals: addUsage({}, record) }];\n return models.map((m, i) => i === index ? { ...m, totals: addUsage(m.totals, record) } : m);\n}\n\n/**\n * What Ordewell has counted of a runner's own session that reports its cost\n * as a running total: that total and each model's share, in USD, as of its\n * last report. A resume of that session counts its first report's growth\n * over this; with no count kept for it, that report only sets the baseline.\n */\nexport interface RunnerSessionCost {\n sessionId: string;\n usd: number;\n modelUsd: Record<string, number>;\n}\n\nexport interface AttemptUsage extends PlannerUsage {\n attempt: number;\n runner: string;\n /** The runner session this attempt ran in, as its runner reported it: what a later Continue of it resumes. */\n sessionId?: string;\n startedAt: string;\n endedAt?: string;\n wallTimeMs: number;\n /** What was counted of its runner session's running cost as it ended: a continue of that session counts on from it. */\n runnerSessionCost?: RunnerSessionCost;\n}\n\nexport function startAttemptUsage(attempt: number, runner: string, startedAt: string): AttemptUsage {\n return { attempt, runner, startedAt, wallTimeMs: 0, totals: {}, byModel: [] };\n}\n\nexport function addAttemptUsage(usage: AttemptUsage, record: UsageRecord, now: string): AttemptUsage {\n const folded = addPlannerUsage(usage, record);\n return { ...usage, ...folded, lastPromptTokens: folded.lastPromptTokens, contextWindow: folded.contextWindow, wallTimeMs: Math.max(0, Date.parse(now) - Date.parse(usage.startedAt)) };\n}\n\nexport function endAttemptUsage(usage: AttemptUsage, now: string, runnerSessionCost?: RunnerSessionCost, sessionId?: string): AttemptUsage {\n return {\n ...usage,\n endedAt: now,\n wallTimeMs: Math.max(0, Date.parse(now) - Date.parse(usage.startedAt)),\n ...(sessionId ? { sessionId } : {}),\n ...(runnerSessionCost ? { runnerSessionCost } : {}),\n };\n}\n\n/** The count a continue of `sessionId` starts from: the one its latest attempt in that session ended with. */\nexport function countedSessionCost(attempts: readonly AttemptUsage[] | undefined, sessionId: string): RunnerSessionCost | undefined {\n return [...attempts ?? []].reverse().find((usage) => usage.runnerSessionCost?.sessionId === sessionId)?.runnerSessionCost;\n}\n\n/**\n * The model a continue's session last ran on and the window it was measured\n * against: the latest earlier attempt of that same runner session that\n * reported one. An attempt that measured nothing is skipped — a continuation\n * does not undo what its session was last measured against — and a window is\n * never borrowed from another session: a fresh attempt starts one.\n */\nexport function resumedSessionWindow(attempts: readonly AttemptUsage[] | undefined, runner: string, attempt: number, sessionId: string): Pick<PlannerUsage, 'source' | 'model' | 'contextWindow'> | undefined {\n const last = [...attempts ?? []].reverse().find((usage) => usage.attempt !== attempt && usage.runner === runner && usage.sessionId === sessionId && usage.contextWindow !== undefined);\n return last ? { source: last.source, model: last.model, contextWindow: last.contextWindow } : undefined;\n}\n\nexport interface PlanUsage {\n totals: UsageTotals;\n byModel: ModelUsage[];\n wallTimeMs: number;\n attempts: number;\n}\n\nexport function addUsageTotals(totals: UsageTotals, addition: UsageTotals): UsageTotals {\n let next = addUsage(totals, { source: '', inputTokens: addition.inputTokens, outputTokens: addition.outputTokens, cachedInputTokens: addition.cachedInputTokens });\n for (const [currency, amount] of Object.entries(addition.reportedCost ?? {})) next = addUsage(next, { source: '', reportedCost: { currency, amount } });\n return next;\n}\n\ninterface UsageTask { attemptUsage?: readonly AttemptUsage[]; subtasks?: readonly UsageTask[] }\n\nexport function planUsage(tasks: readonly UsageTask[]): PlanUsage {\n const result: PlanUsage = { totals: {}, byModel: [], wallTimeMs: 0, attempts: 0 };\n for (const task of tasks) {\n const child = planUsage(task.subtasks ?? []);\n result.totals = addUsageTotals(result.totals, child.totals);\n result.wallTimeMs += child.wallTimeMs;\n result.attempts += child.attempts;\n const models = [...child.byModel];\n for (const usage of task.attemptUsage ?? []) {\n result.totals = addUsageTotals(result.totals, usage.totals);\n result.wallTimeMs += usage.wallTimeMs;\n result.attempts++;\n models.push(...usage.byModel ?? []);\n }\n for (const model of models) {\n const existing = result.byModel.find((m) => m.source === model.source && m.model === model.model);\n if (existing) existing.totals = addUsageTotals(existing.totals, model.totals);\n else result.byModel.push({ ...model, totals: addUsageTotals({}, model.totals) });\n }\n }\n return result;\n}\n\n/**\n * What one task spent across every attempt and every model it ran on, so a\n * stop, a model change and a continue never makes the earlier spend vanish. The\n * context meter is the exception: it reads the latest attempt, because only the\n * current model's window says how full the next prompt is.\n */\nexport interface TaskUsageSummary {\n totals: UsageTotals;\n attempts: number;\n contextFill?: { usedTokens: number; windowTokens: number };\n}\n\nexport function taskUsageSummary(task: Pick<UsageTask, 'attemptUsage'>): TaskUsageSummary {\n const attempts = task.attemptUsage ?? [];\n const latest = attempts.at(-1);\n const contextFill = latest ? plannerContextFill(latest) : undefined;\n return {\n totals: attempts.reduce((sum, attempt) => addUsageTotals(sum, attempt.totals), {} as UsageTotals),\n attempts: attempts.length,\n ...(contextFill ? { contextFill } : {}),\n };\n}\n","import type { UsageLine } from '../models/Usage';\nimport type { DisplayBlock, SubagentBlock, SubagentChild, SubagentStatus } from './blocks';\nimport { subagentBlock, usageBlock } from './records';\n\n/*\n * The block-list operations both reducers are built from — the planner\n * conversation (`reduce.ts`) and a structured task's log (`taskLog.ts`) — so\n * a subagent, a streaming run of text or the usage line behaves the same in\n * either view.\n */\n\n/** What every view over display blocks holds; each view adds its own state beside it. */\nexport interface BlockList {\n readonly blocks: readonly DisplayBlock[];\n readonly nextId: number;\n}\n\n/** The top level of the view (`null`), or the index of the subagent whose children are meant. */\nexport type Lane = number | null;\n\nexport function findLastIndex<T>(items: readonly T[], match: (item: T) => boolean): number {\n for (let i = items.length - 1; i >= 0; i--) if (match(items[i])) return i;\n return -1;\n}\n\nexport function replaceAt<T>(items: readonly T[], index: number, item: T): T[] {\n const next = items.slice();\n next[index] = item;\n return next;\n}\n\n// The usage line always sits last, so everything else lands above it.\nfunction insertTop(blocks: readonly DisplayBlock[], block: DisplayBlock): DisplayBlock[] {\n const last = blocks[blocks.length - 1];\n return last?.type === 'usage' ? [...blocks.slice(0, -1), block, last] : [...blocks, block];\n}\n\nexport function append<V extends BlockList>(view: V, make: (id: string) => DisplayBlock): V {\n return { ...view, blocks: insertTop(view.blocks, make(`b${view.nextId}`)), nextId: view.nextId + 1 };\n}\n\nexport function subagentAt(view: BlockList, lane: number): SubagentBlock {\n const block = view.blocks[lane];\n if (block.type !== 'subagent') throw new Error(`block ${lane} is not a subagent`);\n return block;\n}\n\nexport function laneBlocks(view: BlockList, lane: Lane): readonly DisplayBlock[] {\n return lane === null ? view.blocks : subagentAt(view, lane).children;\n}\n\nfunction setChildren<V extends BlockList>(view: V, lane: number, children: readonly SubagentChild[]): V {\n return { ...view, blocks: replaceAt(view.blocks, lane, { ...subagentAt(view, lane), children }) };\n}\n\nexport function laneReplace<V extends BlockList>(view: V, lane: Lane, index: number, block: SubagentChild): V {\n if (lane === null) return { ...view, blocks: replaceAt(view.blocks, index, block) };\n return setChildren(view, lane, replaceAt(subagentAt(view, lane).children, index, block));\n}\n\nexport function laneAppend<V extends BlockList>(view: V, lane: Lane, make: (id: string) => SubagentChild): V {\n if (lane === null) return append(view, make);\n const children = [...subagentAt(view, lane).children, make(`b${view.nextId}`)];\n return { ...setChildren(view, lane, children), nextId: view.nextId + 1 };\n}\n\nfunction isStreaming(block: DisplayBlock): boolean {\n return (block.type === 'message' || block.type === 'thinking') && block.streaming;\n}\n\nexport function sealed<B extends DisplayBlock>(block: B): B {\n return isStreaming(block) ? { ...block, streaming: false } : block;\n}\n\n/**\n * Output landed at `keep` in the lane, so nothing else there is still\n * streaming: one lane has one voice at a time, and a block left marked as\n * streaming would keep its cursor after its text had moved on.\n */\nexport function sealLane<V extends BlockList>(view: V, lane: Lane, keep: number): V {\n const blocks = laneBlocks(view, lane);\n if (!blocks.some((b, i) => i !== keep && isStreaming(b))) return view;\n if (lane === null) return { ...view, blocks: view.blocks.map((b, i) => (i === keep ? b : sealed(b))) };\n return setChildren(view, lane, subagentAt(view, lane).children.map((b, i) => (i === keep ? b : sealed(b))));\n}\n\n/** Append output to the lane, which then speaks through it alone. */\nexport function appendOutput<V extends BlockList>(view: V, lane: Lane, make: (id: string) => SubagentChild): V {\n const next = laneAppend(view, lane, make);\n return sealLane(next, lane, findLastIndex(laneBlocks(next, lane), (b) => b.type !== 'usage'));\n}\n\n/**\n * The subagent's block, created on first sighting: its activity can arrive\n * before (or without) its start. The call that spawns it becomes the block,\n * keeping the call's id and position — the call and the subagent are one\n * thing on screen.\n */\nexport function subagentLane<V extends BlockList>(view: V, subagentId: string, turnId?: string): [V, number] {\n const existing = findLastIndex(view.blocks, (b) => b.type === 'subagent' && b.subagentId === subagentId);\n if (existing >= 0) return [view, existing];\n const spawn = findLastIndex(view.blocks, (b) => b.type === 'tool' && (b.spawns === subagentId || b.toolCallId === subagentId));\n const call = view.blocks[spawn];\n if (call?.type === 'tool') {\n const block = subagentBlock(call.id, {\n subagentId, brief: call.headline.keyArg, status: 'running', children: [], digest: '', toolCallId: call.toolCallId, turnId: call.turnId,\n });\n return [{ ...view, blocks: replaceAt(view.blocks, spawn, block) }, spawn];\n }\n const next = append(view, (id) => subagentBlock(id, { subagentId, brief: '', status: 'running', children: [], digest: '', turnId }));\n return [next, findLastIndex(next.blocks, (b) => b.type === 'subagent' && b.subagentId === subagentId)];\n}\n\nexport function updateSubagent<V extends BlockList>(view: V, subagentId: string, turnId: string | undefined, update: (block: SubagentBlock) => SubagentBlock): V {\n const [next, lane] = subagentLane(view, subagentId, turnId);\n return { ...next, blocks: replaceAt(next.blocks, lane, update(subagentAt(next, lane))) };\n}\n\n/** The lane a subagent's activity lands in: its own block's children, or the top level. */\nexport function laneOf<V extends BlockList>(view: V, subagentId: string | undefined, turnId?: string): [V, Lane] {\n return subagentId ? subagentLane(view, subagentId, turnId) : [view, null];\n}\n\nexport function think<V extends BlockList>(view: V, text: string, turnId?: string, segmentId?: string, subagentId?: string): V {\n const [placed, lane] = laneOf(view, subagentId, turnId);\n const blocks = laneBlocks(placed, lane);\n const lastIndex = findLastIndex(blocks, (b) => b.type !== 'usage');\n const last = blocks[lastIndex];\n if (last?.type === 'thinking' && last.streaming && last.segmentId === segmentId) {\n return laneReplace(placed, lane, lastIndex, { ...last, text: last.text + text });\n }\n return appendOutput(placed, lane, (id) => ({\n type: 'thinking', id, text, streaming: true,\n ...(turnId ? { turnId } : {}),\n ...(segmentId ? { segmentId } : {}),\n ...(subagentId ? { subagentId } : {}),\n }));\n}\n\n/** The one usage line, replaced in place or added as the last block. */\nexport function setUsageLine<V extends BlockList>(view: V, line: UsageLine): V {\n const last = view.blocks[view.blocks.length - 1];\n const block = usageBlock(last?.type === 'usage' ? last.id : `b${view.nextId}`, line);\n if (last?.type === 'usage') return { ...view, blocks: replaceAt(view.blocks, view.blocks.length - 1, block) };\n return { ...view, blocks: [...view.blocks, block], nextId: view.nextId + 1 };\n}\n\nfunction closeBlock<B extends DisplayBlock>(block: B, interrupted: boolean): B {\n return interrupted && block.type === 'tool' && block.status === 'pending' ? { ...block, status: 'interrupted' } : sealed(block);\n}\n\nfunction closeSubagent(block: SubagentBlock, cut: SubagentStatus | null): SubagentBlock {\n const children = block.children.map((c) => closeBlock(c, cut !== null));\n const status = cut && block.status === 'running' ? cut : block.status;\n return status === block.status && children.every((c, i) => c === block.children[i]) ? block : { ...block, status, children };\n}\n\n/**\n * A turn is over, so whatever it left open is closed: streaming stops, and\n * when the turn was cut short (`cut`), its unanswered calls and running\n * subagents say so.\n */\nexport function closeOpenBlocks<V extends BlockList>(view: V, cut: SubagentStatus | null): V {\n const blocks = view.blocks.map((b) => (b.type === 'subagent' ? closeSubagent(b, cut) : closeBlock(b, cut !== null)));\n return blocks.every((b, i) => b === view.blocks[i]) ? view : { ...view, blocks };\n}\n","import type { ReplyRun, ResearchStep } from '../models/Task';\nimport type { SerializedPendingTurn, SessionMessage } from '../services/SessionMessage';\nimport { isMeasured } from '../models/Usage';\nimport type { DisplayBlock, MessageBlock, MessageRole, PlanBlock, ToolBlock } from './blocks';\nimport { pendingTool, planMarker, settledMessage, settledTool, skillLoadBlock, toolFromStep, userMessage } from './records';\nimport {\n append, appendOutput, closeOpenBlocks, findLastIndex, laneBlocks, laneOf, laneAppend, laneReplace, replaceAt, sealLane, sealed, setUsageLine,\n think, updateSubagent, type BlockList,\n} from './lanes';\n\n/**\n * A line a surface adds to the conversation itself rather than receiving from\n * the session: the user's prompt as it is sent, a notice, an error.\n */\nexport interface LocalEntry {\n type: 'local_entry';\n role: 'user' | 'system' | 'error';\n text: string;\n}\n\nexport type ConversationInput = SessionMessage | LocalEntry;\n\nexport interface ConversationView extends BlockList {\n /**\n * The newest transcript entry the view accounts for. Plan markers and system\n * notes reach a surface only inside the transcript a `plan_generated`\n * carries, so entries after this one are what is new in it.\n */\n readonly transcriptAt?: string;\n /** Reloaded arrivals, keyed by pending turn id until the live turn or transcript accounts for them. */\n readonly pendingInputs?: readonly { input: SerializedPendingTurn; blockIds: readonly string[] }[];\n}\n\nexport const EMPTY_CONVERSATION: ConversationView = { blocks: [], nextId: 1 };\n\ntype Message<T extends SessionMessage['type']> = Extract<SessionMessage, { type: T }>;\n\nfunction isUnsettledSegment(block: DisplayBlock, turnId: string): block is MessageBlock & { segmentId: string } {\n return block.type === 'message' && block.turnId === turnId && block.segmentId !== undefined;\n}\n\nfunction isBuildingPlan(block: DisplayBlock, turnId: string | undefined): block is PlanBlock {\n return block.type === 'plan' && block.status === 'building' && block.turnId === turnId;\n}\n\n/**\n * Where the turn's final segment is, if its text streamed: the turn's latest\n * block, when that is streamed text. Anything the turn did after a segment —\n * a tool call, a plan envelope — means a later segment follows it, and a later\n * segment never rewrites an earlier one. `pastPlan` looks past the turn's plan\n * block, for a plan that settled after its own text.\n */\nfunction finalSegmentIndex(blocks: readonly DisplayBlock[], turnId: string, pastPlan = false): number {\n for (let i = blocks.length - 1; i >= 0; i--) {\n const block = blocks[i];\n if (block.type === 'usage' || block.type === 'thinking' || block.type === 'approval' || (pastPlan && block.type === 'plan')) continue;\n // A task log's own blocks; a planner turn never has one.\n if (block.type === 'command' || block.type === 'compaction' || block.type === 'runner_loaded') continue;\n if (block.turnId !== turnId) continue;\n return isUnsettledSegment(block, turnId) ? i : -1;\n }\n return -1;\n}\n\nfunction openTurn(view: ConversationView, { turnId, prompt = '', skills = [], wakeUps = [], forced }: Message<'planner_turn_started'>): ConversationView {\n const adopted = takePendingInputs(view, prompt, wakeUps, turnId);\n view = adopted.view;\n wakeUps = wakeUps.slice(adopted.wakeUps);\n if (wakeUps.length === 0) return adopted.prompt || (prompt === '' && adopted.wakeUps > 0) ? view : promptLine(view, turnId, prompt, skills, forced);\n // A wake-up turn has no message; otherwise the run updates go ahead of the\n // message they were delivered with, where the transcript keeps them.\n const said = prompt === '' || adopted.prompt ? view : promptLine(view, turnId, prompt, skills, forced);\n const at = prompt === '' ? said.blocks.length : findLastIndex(said.blocks, (b) => b.type === 'message' && b.role === 'user' && b.turnId === turnId);\n const updates = wakeUps.map((text, n) => settledMessage(`b${said.nextId + n}`, 'wake_up', text, turnId));\n return { ...said, blocks: [...said.blocks.slice(0, at), ...updates, ...said.blocks.slice(at)], nextId: said.nextId + updates.length };\n}\n\nfunction takePendingInputs(view: ConversationView, prompt: string | undefined, wakeUps: readonly string[], turnId?: string): { view: ConversationView; prompt: boolean; wakeUps: number } {\n const pending = view.pendingInputs ?? [];\n const users = pending.filter(({ input }) => input.source === 'user');\n const updates = pending.filter(({ input }) => input.source === 'supervisor');\n const taken = new Set<string>();\n let matchedPrompt = false;\n // PlanTurns joins a batch's user messages, but reload draws each arrival.\n for (let n = 1; prompt !== undefined && n <= users.length; n++) {\n if (users.slice(0, n).map(({ input }) => input.text).join('\\n\\n') !== prompt) continue;\n for (const { input } of users.slice(0, n)) taken.add(input.id);\n matchedPrompt = true;\n break;\n }\n let matchedUpdates = 0;\n while (matchedUpdates < wakeUps.length && updates[matchedUpdates]?.input.text === wakeUps[matchedUpdates]) {\n taken.add(updates[matchedUpdates++].input.id);\n }\n if (taken.size === 0) return { view, prompt: false, wakeUps: 0 };\n const blockIds = new Set(pending.filter(({ input }) => taken.has(input.id)).flatMap(({ blockIds }) => blockIds));\n return {\n view: {\n ...view,\n blocks: turnId === undefined ? view.blocks : view.blocks.map((block) => blockIds.has(block.id) ? { ...block, turnId } : block),\n pendingInputs: pending.filter(({ input }) => !taken.has(input.id)),\n },\n prompt: matchedPrompt,\n wakeUps: matchedUpdates,\n };\n}\n\nfunction promptLine(view: ConversationView, turnId: string, prompt: string, skills: NonNullable<Message<'planner_turn_started'>['skills']>, forced?: boolean): ConversationView {\n // A surface shows its user's prompt the moment it is sent; the turn that\n // answers it adopts that line rather than repeating it.\n const i = findLastIndex(view.blocks, (b) => b.type === 'message' && b.role === 'user');\n const sent = view.blocks[i];\n const adopted = sent?.type === 'message' && sent.turnId === undefined && sent.text === prompt;\n const said: ConversationView = adopted\n ? { ...view, blocks: replaceAt(view.blocks, i, userMessage(sent.id, prompt, skills, { turnId, forced })) }\n : append(view, (id) => userMessage(id, prompt, skills, { turnId, forced }));\n if (skills.length === 0) return said;\n // Directly under the message that loaded them, wherever that line sits.\n const at = adopted ? i + 1 : findLastIndex(said.blocks, (b) => b.type === 'message' && b.role === 'user') + 1;\n const loads = skills.map((skill, n) => skillLoadBlock(`b${said.nextId + n}`, skill, turnId));\n return { ...said, blocks: [...said.blocks.slice(0, at), ...loads, ...said.blocks.slice(at)], nextId: said.nextId + loads.length };\n}\n\nfunction streamText(view: ConversationView, { turnId, segmentId, text }: Message<'planner_text_delta'>): ConversationView {\n const i = findLastIndex(view.blocks, (b) => isUnsettledSegment(b, turnId) && b.segmentId === segmentId);\n const segment = view.blocks[i];\n if (segment?.type === 'message') {\n return sealLane(laneReplace(view, null, i, { ...segment, text: segment.text + text, streaming: true }), null, i);\n }\n return appendOutput(view, null, (id) => ({ type: 'message', id, role: 'planner', text, streaming: true, turnId, segmentId }));\n}\n\n/**\n * Drop the turn's plan display while it is still building: whatever streamed\n * there did not become a plan — a task-ops or task-query envelope, or, from a\n * daemon older than turns, the reply's prose.\n */\nfunction dropBuildingPlan(view: ConversationView, turnId: string | undefined, segmentId?: string): ConversationView {\n const blocks = view.blocks.filter((b) => !(isBuildingPlan(b, turnId) && (segmentId === undefined || b.segmentId === segmentId)));\n return blocks.length === view.blocks.length ? view : { ...view, blocks };\n}\n\nfunction settleReply(view: ConversationView, { content, turnId, supervisor, runs }: Message<'planner_message'>): ConversationView {\n const role = supervisor ? 'supervisor' : 'planner';\n if (runs) return settleRuns(view, runs, role, turnId);\n if (turnId !== undefined) {\n const i = finalSegmentIndex(view.blocks, turnId);\n if (i >= 0) {\n return dropBuildingPlan({ ...view, blocks: replaceAt(view.blocks, i, settledMessage(view.blocks[i].id, role, content, turnId)) }, turnId);\n }\n }\n return append(dropBuildingPlan(view, turnId), (id) => settledMessage(id, role, content, turnId));\n}\n\n/**\n * Settle a reply run by run (ADR-0017 A1): each run's text takes its segment's\n * place, wherever in the turn it streamed, and only a run that never streamed\n * goes last. A segment of the turn the reply no longer contains did not\n * become part of it. Without a turn id (a reply a surface backfilled from the\n * transcript) the turn is the one the runs' segments streamed in.\n */\nfunction settleRuns(view: ConversationView, runs: readonly ReplyRun[], role: MessageRole, turnId: string | undefined): ConversationView {\n const settled = new Map<number, ReplyRun>();\n let turn = turnId;\n for (const run of runs) {\n const i = view.blocks.findIndex((b) => b.type === 'message' && b.segmentId === run.segmentId && b.turnId !== undefined && (turnId === undefined || b.turnId === turnId));\n const segment = view.blocks[i];\n if (segment?.type !== 'message') continue;\n settled.set(i, run);\n turn ??= segment.turnId;\n }\n const contained = new Set(runs.map((run) => run.segmentId));\n const blocks = view.blocks.flatMap((block, i) => {\n const run = settled.get(i);\n if (run) return [settledMessage(block.id, role, run.text, turn)];\n return turn !== undefined && isUnsettledSegment(block, turn) && !contained.has(block.segmentId) ? [] : [block];\n });\n const streamed = new Set(settled.values());\n return runs\n .filter((run) => !streamed.has(run))\n .reduce((next, run) => append(next, (id) => settledMessage(id, role, run.text, turn)), dropBuildingPlan({ ...view, blocks }, turn));\n}\n\n// A retracted envelope takes the turn's plan display with it, or its retry\n// would build on the botched JSON and the partial-plan rows read both.\nfunction retractText(view: ConversationView, { turnId, segmentId }: Message<'planner_text_retracted'>): ConversationView {\n const blocks = view.blocks.filter((b) => !(isUnsettledSegment(b, turnId) && (segmentId === undefined || b.segmentId === segmentId)));\n return dropBuildingPlan(blocks.length === view.blocks.length ? view : { ...view, blocks }, turnId, segmentId);\n}\n\nfunction startSubagent(view: ConversationView, { subagentId, brief, model, turnId }: Message<'subagent_started'>): ConversationView {\n return updateSubagent(view, subagentId, turnId, (block) => ({ ...block, ...(brief ? { brief } : {}), ...(model ? { model } : {}) }));\n}\n\nfunction finishSubagent(view: ConversationView, { subagentId, outcome, digest, usage, turnId }: Message<'subagent_finished'>): ConversationView {\n return updateSubagent(view, subagentId, turnId, (block) => ({\n ...block, status: outcome, digest, children: block.children.map(sealed), ...(usage ? { usage } : {}),\n }));\n}\n\nfunction announceTool(view: ConversationView, call: Message<'research_step'>): ConversationView {\n // A spawn call names the subagent it starts; any other call tagged with a\n // subagent is that subagent's own.\n const spawns = call.tool === 'spawn_research_agent' ? call.subagentId : undefined;\n const [placed, lane] = laneOf(view, spawns ? undefined : call.subagentId, call.turnId);\n return appendOutput(placed, lane, (id) => ({ ...pendingTool(id, call), ...(spawns ? { spawns } : {}) }));\n}\n\n// By the call's id: results of a parallel round return in any order, and a\n// name match would put one call's output on another's row (ADR-0008). The\n// name scan survives only for calls that announced no id.\nfunction isPendingCallOf(block: DisplayBlock, step: ResearchStep): block is ToolBlock {\n if (block.type !== 'tool' || block.status !== 'pending') return false;\n return step.toolCallId ? block.toolCallId === step.toolCallId : block.toolCallId === undefined && block.tool === step.tool;\n}\n\nfunction settleTool(view: ConversationView, { step, turnId }: Message<'research_step_done'>): ConversationView {\n const [placed, lane] = laneOf(view, step.subagentId, turnId);\n const blocks = laneBlocks(placed, lane);\n const i = findLastIndex(blocks, (b) => isPendingCallOf(b, step));\n const pending = blocks[i];\n if (pending?.type === 'tool') return laneReplace(placed, lane, i, settledTool(pending, step));\n // The call that spawned a subagent is shown by the subagent's block, and\n // only the subagent's own finish settles it: a backgrounded agent's call\n // returns at launch, long before the work ends.\n if (lane === null && step.toolCallId && blocks.some((b) => b.type === 'subagent' && b.toolCallId === step.toolCallId)) return view;\n return laneAppend(placed, lane, (id) => toolFromStep(id, step, turnId));\n}\n\n/**\n * The building display shows one envelope: the segment streaming now. A turn's\n * later envelope (a plan after a read it asked for) starts it over, below\n * whatever the turn did in between, rather than running on from the last one.\n */\nfunction streamPlan(view: ConversationView, { token, turnId, segmentId }: Message<'plan_token'>): ConversationView {\n const i = findLastIndex(view.blocks, (b) => isBuildingPlan(b, turnId));\n const building = view.blocks[i];\n if (building?.type === 'plan' && building.segmentId === segmentId) {\n return { ...view, blocks: replaceAt(view.blocks, i, { ...building, text: building.text + token }) };\n }\n return append(dropBuildingPlan(view, turnId), (id) => ({\n type: 'plan', id, status: 'building', text: token, ...(turnId ? { turnId } : {}), ...(segmentId ? { segmentId } : {}),\n }));\n}\n\n/** A plan landed: the building display of the turn that committed it becomes its marker. */\nfunction markPlan(view: ConversationView, content: string, turnId: string | undefined): ConversationView {\n const marker = planMarker(content);\n const i = findLastIndex(view.blocks, (b) => isBuildingPlan(b, turnId));\n const building = view.blocks[i];\n if (building?.type === 'plan') {\n const settled: PlanBlock = { type: 'plan', id: building.id, ...marker, text: '', ...(building.turnId ? { turnId: building.turnId } : {}) };\n return { ...view, blocks: replaceAt(view.blocks, i, settled) };\n }\n return append(view, (id) => ({ type: 'plan', id, text: '', ...marker }));\n}\n\nfunction requestApproval(view: ConversationView, { id: approvalId, kind, subject, scope, detail, turnId }: Message<'approval_request'>): ConversationView {\n return append(view, (id) => ({\n type: 'approval', id, approvalId, kind, subject, scope, status: 'pending',\n ...(detail ? { detail } : {}),\n ...(turnId ? { turnId } : {}),\n }));\n}\n\nfunction settleApproval(view: ConversationView, { id, granted }: Message<'approval_settled'>): ConversationView {\n const i = findLastIndex(view.blocks, (b) => b.type === 'approval' && b.approvalId === id);\n const request = view.blocks[i];\n if (request?.type !== 'approval') return view;\n return { ...view, blocks: replaceAt(view.blocks, i, { ...request, status: granted ? 'granted' : 'denied', decidedBy: 'asked' }) };\n}\n\nfunction decideApproval(view: ConversationView, { kind, subject, scope, detail, granted, source }: Message<'approval_decided'>): ConversationView {\n return append(view, (id) => ({\n type: 'approval', id, kind, subject, scope, status: granted ? 'granted' : 'denied', decidedBy: source,\n ...(detail ? { detail } : {}),\n }));\n}\n\nfunction reportUsage(view: ConversationView, message: Message<'planner_usage'>): ConversationView {\n return isMeasured(message.totals) ? setUsageLine(view, message) : view;\n}\n\n/**\n * Nothing carries the turn's id after this, so whatever it left open is closed:\n * streaming stops, and on a stop or failure its unanswered calls and running\n * subagents say they were cut short. A plan reply that streamed as text (a\n * prose preamble decides a segment's route) gives way to its plan block, as a\n * settled message would have replaced it.\n */\nfunction endTurn(view: ConversationView, { turnId, outcome }: Message<'planner_turn_ended'>): ConversationView {\n let next = dropBuildingPlan(view, turnId);\n const planText = outcome === 'plan' ? finalSegmentIndex(next.blocks, turnId, true) : -1;\n if (planText >= 0) next = { ...next, blocks: next.blocks.filter((_, i) => i !== planText) };\n return closeOpenBlocks(next, outcome === 'stopped' ? 'stopped' : outcome === 'error' ? 'failed' : null);\n}\n\n// The summary is announced as a planner message before the transcript it now\n// heads arrives; the transcript records it as a notice, and so does the view.\nfunction markCompaction(view: ConversationView, summary: string): ConversationView {\n const i = findLastIndex(view.blocks, (b) => b.type === 'message' && b.role === 'planner' && b.turnId === undefined && b.text === summary);\n const announced = view.blocks[i];\n if (announced?.type === 'message') return { ...view, blocks: replaceAt(view.blocks, i, { ...announced, role: 'system' }) };\n return append(view, (id) => settledMessage(id, 'system', summary));\n}\n\nfunction syncTranscript(view: ConversationView, { plan, turnId }: Message<'plan_generated'>): ConversationView {\n const history = plan.conversationHistory ?? [];\n // Only the newest marker can be the committing turn's; older ones a surface\n // is only now catching up on belong to turns long over.\n const committed = findLastIndex(history, (e) => e.kind === 'plan_generated');\n let next = view;\n let latest = view.transcriptAt;\n for (const [i, entry] of history.entries()) {\n const isNew = view.transcriptAt === undefined || entry.timestamp > view.transcriptAt;\n if (isNew && entry.role === 'user' && !entry.kind) next = takePendingInputs(next, entry.content, []).view;\n if (isNew && entry.kind === 'wake_up') next = takePendingInputs(next, undefined, [entry.content]).view;\n if (isNew && entry.kind === 'plan_generated') next = markPlan(next, entry.content, i === committed ? turnId : undefined);\n if (isNew && entry.kind === 'system') next = append(next, (id) => settledMessage(id, 'system', entry.content));\n if (isNew && entry.kind === 'error') next = append(next, (id) => settledMessage(id, 'error', entry.content));\n if (isNew && entry.kind === 'compaction') next = markCompaction(next, entry.content);\n if (latest === undefined || entry.timestamp > latest) latest = entry.timestamp;\n }\n return next === view && latest === view.transcriptAt ? view : { ...next, transcriptAt: latest };\n}\n\n/**\n * Bring the view's approval cards in line with the planner's requests the\n * session says are still waiting — for a surface that was not listening the\n * whole time: one that reconnected, reloaded, or just attached. A pending card\n * the session no longer has was answered or expired meanwhile; this surface\n * never heard how, so the card goes rather than guessing an answer. A waiting\n * request with no card gets one, answerable as the live one would have been.\n */\nexport function reconcileApprovals(view: ConversationView, waiting: readonly Message<'approval_request'>[]): ConversationView {\n const ids = new Set(waiting.map((request) => request.id));\n const answered = (block: DisplayBlock): boolean =>\n block.type === 'approval' && block.status === 'pending' && block.approvalId !== undefined && !ids.has(block.approvalId);\n const kept = view.blocks.some(answered) ? { ...view, blocks: view.blocks.filter((block) => !answered(block)) } : view;\n const carded = new Set(kept.blocks.flatMap((block) => (block.type === 'approval' && block.approvalId ? [block.approvalId] : [])));\n return waiting.filter((request) => !carded.has(request.id)).reduce(requestApproval, kept);\n}\n\n/**\n * Fold one input into the view. Pure and incremental: blocks the input does\n * not touch keep their identity, and an input that changes nothing returns\n * `view` itself — surfaces memoize their drawing on that, and text deltas\n * arrive quickly.\n */\nexport function reduceConversation(view: ConversationView, input: ConversationInput): ConversationView {\n switch (input.type) {\n case 'local_entry':\n return append(view, (id) => settledMessage(id, input.role, input.text));\n case 'planner_turn_started':\n return input.prompt === undefined ? view : openTurn(view, input);\n case 'planner_skill_loaded':\n return append(sealLane(view, null, -1), (id) => skillLoadBlock(id, input.skill, input.turnId));\n case 'planner_text_delta':\n return streamText(view, input);\n case 'planner_message':\n return settleReply(view, input);\n case 'planner_text_retracted':\n return retractText(view, input);\n case 'planner_thinking_delta':\n return think(view, input.text, input.turnId, input.segmentId, input.subagentId);\n case 'research_step':\n return announceTool(view, input);\n case 'research_step_done':\n return settleTool(view, input);\n case 'subagent_started':\n return startSubagent(view, input);\n case 'subagent_finished':\n return finishSubagent(view, input);\n case 'plan_token':\n return streamPlan(view, input);\n case 'plan_generated':\n return syncTranscript(view, input);\n case 'planner_turn_ended':\n return endTurn(view, input);\n case 'approval_request':\n return requestApproval(view, input);\n case 'approval_settled':\n return settleApproval(view, input);\n case 'approval_decided':\n return decideApproval(view, input);\n case 'execution_action':\n return append(view, (id) => settledMessage(id, 'system', input.text));\n case 'planner_usage':\n return reportUsage(view, input);\n default:\n return view;\n }\n}\n","import type { ResearchLogEntry, ResearchStep, SkillLoadNotice, SubagentLogEntry } from '../models/Task';\nimport type { SerializedConversationMessage, SerializedPendingTurn } from '../services/SessionMessage';\nimport { isMeasured, usageLine, type PlannerUsage } from '../models/Usage';\nimport type { DisplayBlock, MessageRole } from './blocks';\nimport { planMarker, settledMessage, skillLoadBlock, skillLoadNotice, subagentBlock, toolFromStep, usageBlock, userMessage } from './records';\nimport type { ConversationView } from './reduce';\n\n/** One top-level block before it has an id, and where it falls in time. */\ninterface Placed {\n at: string;\n /** Breaks a tie in `at`: a user's message, then the research it caused, then what the turn settled on. */\n rank: number;\n build: (nextId: () => string) => DisplayBlock;\n}\n\nconst USER = 0;\nconst RESEARCH = 1;\nconst SETTLED = 2;\n\n/** `loaded`: the skills the entries after a user's message say it loaded. */\nfunction fromEntry(entry: SerializedConversationMessage, loaded: readonly SkillLoadNotice[] = []): Placed['build'] {\n if (entry.kind === 'plan_generated') return (id) => ({ type: 'plan', id: id(), text: '', ...planMarker(entry.content) });\n if (entry.kind === 'skill_load' && entry.skill) {\n const { skill } = entry;\n return (id) => skillLoadBlock(id(), skillLoadNotice(skill));\n }\n if (entry.role === 'user' && !entry.kind) return (id) => userMessage(id(), entry.content, loaded.map(skillLoadNotice), { forced: entry.forced });\n return (id) => settledMessage(id(), roleOf(entry), entry.content);\n}\n\nfunction roleOf(entry: SerializedConversationMessage): MessageRole {\n switch (entry.kind) {\n case 'system': case 'compaction': case 'execution': return 'system';\n case 'wake_up': return 'wake_up';\n case 'supervisor': return 'supervisor';\n case 'error': return 'error';\n default: return entry.role === 'user' ? 'user' : 'planner';\n }\n}\n\nfunction loadsAfter(entries: readonly SerializedConversationMessage[], index: number): SkillLoadNotice[] {\n const loads: SkillLoadNotice[] = [];\n for (let i = index + 1; i < entries.length && entries[i].kind === 'skill_load'; i++) {\n const { skill } = entries[i];\n if (skill?.invokedBy === 'user') loads.push(skill);\n }\n return loads;\n}\n\n// A skill load ranks with the message that caused it: same time, same rank,\n// and the stable sort keeps it right under the message. A run update is a\n// turn's input too, ahead of the research it caused.\nfunction rankOf(entry: SerializedConversationMessage): number {\n return entry.role === 'user' && (!entry.kind || entry.kind === 'skill_load' || entry.kind === 'wake_up') ? USER : SETTLED;\n}\n\nfunction spawnBrief(step: ResearchStep): string | undefined {\n try {\n const args: unknown = JSON.parse(step.args);\n const prompt = args && typeof args === 'object' ? (args as Record<string, unknown>).prompt : undefined;\n return typeof prompt === 'string' ? prompt.trim() : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Which subagent a planner step started, if it did. The log keeps no link: a\n * harness planner's subagent takes its call's id, and an ADR-0005 research\n * agent is briefed with its spawn call's prompt, trimmed.\n */\nfunction spawnedBy(step: ResearchStep, unclaimed: SubagentLogEntry[]): SubagentLogEntry | undefined {\n const byId = unclaimed.find((e) => e.subagentId === step.toolCallId);\n if (byId) return byId;\n if (step.tool !== 'spawn_research_agent') return undefined;\n const brief = spawnBrief(step);\n return brief === undefined ? undefined : unclaimed.find((e) => e.brief === brief);\n}\n\nfunction research(log: readonly ResearchLogEntry[]): Placed[] {\n const subagents = log.filter((e): e is SubagentLogEntry => 'type' in e && e.type === 'subagent');\n const ownSubagent = new Set(subagents.map((e) => e.subagentId));\n const unclaimed = [...subagents];\n const spawnCall = new Map<string, string | undefined>();\n const placed: Placed[] = [];\n\n for (const entry of log) {\n if ('type' in entry) {\n if (entry.type === 'system') placed.push({ at: entry.timestamp, rank: RESEARCH, build: (id) => settledMessage(id(), 'system', entry.content) });\n continue;\n }\n if (entry.subagentId && ownSubagent.has(entry.subagentId)) continue;\n const spawned = spawnedBy(entry, unclaimed);\n if (spawned) {\n unclaimed.splice(unclaimed.indexOf(spawned), 1);\n spawnCall.set(spawned.subagentId, entry.toolCallId);\n continue;\n }\n placed.push({ at: entry.timestamp, rank: RESEARCH, build: (id) => toolFromStep(id(), entry) });\n }\n\n // A subagent stands where it started, which is where its spawn call was\n // announced; the call's own record is written only once the subagent is done.\n for (const entry of subagents) {\n const toolCallId = spawnCall.get(entry.subagentId);\n const steps = log.filter((e): e is ResearchStep => !('type' in e) && e.subagentId === entry.subagentId);\n placed.push({\n at: entry.timestamp,\n rank: RESEARCH,\n build: (id) => subagentBlock(id(), {\n subagentId: entry.subagentId, brief: entry.brief, status: entry.outcome, digest: entry.digest,\n children: steps.map((step) => toolFromStep(id(), step)),\n toolCallId, model: entry.model, usage: entry.usage,\n }),\n });\n }\n return placed;\n}\n\n/**\n * The view a saved session reopens with: what its transcript and research log\n * kept, in the order it happened — messages, each reply run by run where it\n * began, notices and the compaction summary, plan markers, tool calls with\n * each subagent's calls nested under it, and the token line. Reasoning and\n * streamed text that never settled were never saved, so a reload has none.\n *\n * The research log interleaves with the transcript by time. Entries older than\n * a compaction's first kept message went with the turns it condensed.\n * Pending inputs follow the landed records in arrival order; they are not\n * transcript entries until their turn lands.\n */\nexport function fromTranscript(\n conversationHistory: readonly SerializedConversationMessage[] | undefined,\n researchLog: readonly ResearchLogEntry[] | undefined,\n plannerUsage?: PlannerUsage,\n pendingTurns: readonly SerializedPendingTurn[] = [],\n): ConversationView {\n const history = conversationHistory ?? [];\n const compacted = history[0]?.kind === 'compaction' ? history[0] : undefined;\n const kept = compacted ? history.slice(1) : history;\n const cutoff = compacted ? (kept[0]?.timestamp ?? compacted.timestamp) : '';\n\n const placed: Placed[] = [\n ...kept.flatMap((entry, i): Placed[] => (entry.runs\n // ADR-0017 A1: each run of a reply where it streamed, among the research.\n ? entry.runs.map((run) => ({ at: run.startedAt, rank: SETTLED, build: (id) => settledMessage(id(), roleOf(entry), run.text) }))\n : [{ at: entry.timestamp, rank: rankOf(entry), build: fromEntry(entry, loadsAfter(kept, i)) }])),\n ...research(researchLog ?? []).filter((item) => item.at >= cutoff),\n ];\n placed.sort((a, b) => (a.at < b.at ? -1 : a.at > b.at ? 1 : a.rank - b.rank));\n // The summary stands where the condensed turns were, ahead of everything kept.\n if (compacted) placed.unshift({ at: '', rank: SETTLED, build: fromEntry(compacted) });\n\n let nextId = 1;\n const id = () => `b${nextId++}`;\n const blocks = placed.map((item) => item.build(id));\n const pendingInputs: NonNullable<ConversationView['pendingInputs']>[number][] = [];\n\n for (const input of pendingTurns) {\n const start = blocks.length;\n if (input.source === 'supervisor') {\n blocks.push(settledMessage(id(), 'wake_up', input.text));\n } else {\n const skills = (input.skills ?? []).map(skillLoadNotice);\n blocks.push(userMessage(id(), input.text, skills, { forced: input.forced }));\n blocks.push(...skills.map((skill) => skillLoadBlock(id(), skill)));\n }\n pendingInputs.push({ input: { ...input, skills: input.skills?.map(skillLoadNotice) }, blockIds: blocks.slice(start).map((block) => block.id) });\n }\n\n if (plannerUsage && isMeasured(plannerUsage.totals)) blocks.push(usageBlock(id(), usageLine(plannerUsage)));\n\n const transcriptAt = history.reduce<string | undefined>((latest, e) => (latest === undefined || e.timestamp > latest ? e.timestamp : latest), undefined);\n return { blocks, nextId, ...(transcriptAt ? { transcriptAt } : {}), ...(pendingInputs.length > 0 ? { pendingInputs } : {}) };\n}\n","/**\n * Whether two messages say the same thing. Claude Code words a usage limit\n * alike in its assistant message and in the `result` of the failed turn, but\n * for whitespace and a final period.\n */\nexport function sameMessage(a: string, b: string): boolean {\n const bare = (value: string) => value.trim().replace(/\\.+$/, '').trimEnd();\n return bare(a) !== '' && bare(a) === bare(b);\n}\n","import type { QueuedTaskMessage, StructuredTurnEnd, TaskMessageFrom } from '../interfaces/IRunner';\nimport type { ApprovalDecision } from '../interfaces/IApproval';\nimport type { TaskLogEvent } from '../models/TaskLog';\nimport { addPlannerUsage, isMeasured, usageLine, type PlannerUsage } from '../models/Usage';\nimport { sameMessage } from '../utils/sameMessage';\nimport { mapAgentTool, normalizeAgentArgs } from '../services/harness/agentTools';\nimport type { ApprovalBlock, CommandStatus, DisplayBlock, MessageBlock, SubagentChild, SubagentStatus, ThinkingDisplayBlock } from './blocks';\nimport { toolHeadline } from './format';\nimport {\n append, appendOutput, replaceAt, closeOpenBlocks, findLastIndex, laneAppend, laneBlocks, laneOf, laneReplace, setUsageLine, updateSubagent, sealed, sealLane,\n type BlockList, type Lane,\n} from './lanes';\nimport { finishedTool, pendingTool, settledMessage } from './records';\n\n/**\n * What a surface draws for one attempt of a structured task (ADR-0018, O1b):\n * the same display blocks as the planner conversation, built from the task's\n * {@link TaskLogEvent}s. No planner turn ids — a task's turns are its own,\n * one at a time.\n */\nexport interface TaskLogView extends BlockList {\n /** Messages not yet delivered, oldest first; `handedOver` marks the ones the runner already has. */\n readonly queued: readonly QueuedTaskMessage[];\n /** A turn is running. */\n readonly working: boolean;\n /** How the last turn ended; absent before the first one does. */\n readonly lastTurnEnd?: StructuredTurnEnd;\n /** What the runner reported over the attempt, subagents included. */\n readonly usage?: PlannerUsage;\n /**\n * The block each stream of deltas writes into — a run of text by its id,\n * thinking by whose it is — so the stream's authoritative copy replaces it\n * instead of repeating it below.\n */\n readonly streams: Readonly<Record<string, string>>;\n /** The turn's latest agent text block, which a failure that repeats it takes the place of. */\n readonly latestText?: string;\n}\n\nexport const EMPTY_TASK_LOG: TaskLogView = { blocks: [], nextId: 1, queued: [], working: false, streams: {} };\n\ntype Event<T extends TaskLogEvent['type']> = Extract<TaskLogEvent, { type: T }>;\n\n/** A log saved before runs of text carried an id streams every run through one key. */\nconst textStream = (runId: string | undefined) => (runId === undefined ? 'text' : `text:${runId}`);\nconst thinkingStream = (subagentId: string | undefined) => `thinking:${subagentId ?? ''}`;\n\nfunction withoutStream(view: TaskLogView, key: string): TaskLogView {\n if (!(key in view.streams)) return view;\n return { ...view, streams: Object.fromEntries(Object.entries(view.streams).filter(([k]) => k !== key)) };\n}\n\n// A later run of a turn in a log saved before runs carried an id opens with\n// the paragraph break that joined it; as a block of its own it needs none.\nfunction blockText(text: string): string {\n return text.replace(/^\\n+/, '');\n}\n\ntype Streamed = MessageBlock | ThinkingDisplayBlock;\n\n/** The lane's streaming block for `key`, while it is still the lane's latest output and still streaming. */\nfunction openStream(view: TaskLogView, lane: Lane, key: string): number {\n const id = view.streams[key];\n if (id === undefined) return -1;\n const blocks = laneBlocks(view, lane);\n const i = findLastIndex(blocks, (b) => b.type !== 'usage');\n const block = blocks[i];\n return block?.id === id && (block.type === 'message' || block.type === 'thinking') && block.streaming ? i : -1;\n}\n\n/** The lane's block for `key`, wherever it now sits. */\nfunction streamBlock(view: TaskLogView, lane: Lane, key: string): number {\n const id = view.streams[key];\n return id === undefined ? -1 : findLastIndex(laneBlocks(view, lane), (b) => b.id === id);\n}\n\n/**\n * One delta of `key`, into its block: the one it has wherever that sits when\n * `anywhere`, else only while that is still the lane's latest output.\n * Otherwise it opens a block of its own.\n */\nfunction streamDelta(view: TaskLogView, lane: Lane, key: string, text: string, make: (id: string, text: string) => Streamed, anywhere = false): TaskLogView {\n const i = anywhere ? streamBlock(view, lane, key) : openStream(view, lane, key);\n const open = laneBlocks(view, lane)[i];\n if (open?.type === 'message' || open?.type === 'thinking') return laneReplace(view, lane, i, { ...open, text: open.text + text });\n const next = appendOutput(view, lane, (id) => make(id, blockText(text)));\n return { ...next, streams: { ...next.streams, [key]: `b${view.nextId}` } };\n}\n\n/**\n * A run's authoritative copy: it replaces the text its deltas built, wherever\n * that block now sits in the lane, and is added whole when nothing streamed.\n */\nfunction streamWhole(view: TaskLogView, lane: Lane, key: string, text: string, make: (id: string) => SubagentChild): TaskLogView {\n const i = streamBlock(view, lane, key);\n const streamed = laneBlocks(view, lane)[i];\n const next = withoutStream(view, key);\n if (streamed?.type === 'message' || streamed?.type === 'thinking') {\n return laneReplace(next, lane, i, { ...streamed, text: blockText(text), streaming: false });\n }\n return appendOutput(next, lane, make);\n}\n\n/** The turn's latest text block is the one a run opened last; a run settling elsewhere leaves it be. */\nfunction openedText(view: TaskLogView, next: TaskLogView): TaskLogView {\n return next.nextId > view.nextId ? { ...next, latestText: `b${view.nextId}` } : next;\n}\n\nfunction agentText(view: TaskLogView, { runId, text }: Event<'text'>): TaskLogView {\n return openedText(view, streamWhole(view, null, textStream(runId), text, (id) => settledMessage(id, 'agent', blockText(text))));\n}\n\n/**\n * A run with an id streams into its own block wherever that now sits, so a\n * note or another run landing in the middle of it splits nothing. A log saved\n * without ids has one stream for every run, which streams into the latest\n * output only.\n */\nfunction agentTextDelta(view: TaskLogView, { runId, text }: Event<'text_delta'>): TaskLogView {\n const make = (id: string, t: string): Streamed => ({ type: 'message', id, role: 'agent', text: t, streaming: true });\n return openedText(view, streamDelta(view, null, textStream(runId), text, make, runId !== undefined));\n}\n\n/**\n * Claude Code says a usage limit twice — as an assistant message and as the\n * `result` of the failed turn. The log keeps both; the view shows the failure\n * alone when the turn's latest agent text only repeats it. Text before that\n * block is a real reply, and text that merely mentions the failure is not a\n * repeat.\n */\nfunction failTurn(view: TaskLogView, message: string): TaskLogView {\n const repeated = view.blocks.find((b) => b.id === view.latestText);\n const settled = repeated?.type === 'message' && repeated.role === 'agent' && sameMessage(repeated.text, message)\n ? {\n ...view,\n blocks: view.blocks.filter((b) => b !== repeated),\n streams: Object.fromEntries(Object.entries(view.streams).filter(([, id]) => id !== repeated.id)),\n }\n : view;\n return appendOutput({ ...settled, latestText: undefined }, null, (id) => settledMessage(id, 'error', message));\n}\n\nfunction thinkingBlock(id: string, text: string, streaming: boolean, subagentId: string | undefined): ThinkingDisplayBlock {\n return { type: 'thinking', id, text, streaming, ...(subagentId ? { subagentId } : {}) };\n}\n\nfunction thinkingDelta(view: TaskLogView, { text, subagentId }: Event<'thinking_delta'>): TaskLogView {\n const [placed, lane] = laneOf(view, subagentId);\n return streamDelta(placed, lane, thinkingStream(subagentId), text, (id, t) => thinkingBlock(id, t, true, subagentId));\n}\n\nfunction thinkingWhole(view: TaskLogView, { text, subagentId }: Event<'thinking'>): TaskLogView {\n const [placed, lane] = laneOf(view, subagentId);\n return streamWhole(placed, lane, thinkingStream(subagentId), text, (id) => thinkingBlock(id, blockText(text), false, subagentId));\n}\n\nfunction announceTool(view: TaskLogView, { id: toolCallId, name, args, subagentId }: Event<'tool_call'>): TaskLogView {\n const { tool, toolLabel } = mapAgentTool(name);\n const [placed, lane] = laneOf(view, subagentId);\n return appendOutput(placed, lane, (id) => {\n const call = pendingTool(id, { tool, toolLabel, args, toolCallId });\n const parsed = parseArgs(args);\n // Headline from the normalized arguments, as the harness planner's rows\n // are, so a `Read` or a Codex argv reads the same in both views.\n return parsed ? { ...call, headline: toolHeadline(tool, JSON.stringify(normalizeAgentArgs(tool, parsed)), toolLabel) } : call;\n });\n}\n\nfunction parseArgs(args: string): Record<string, unknown> | null {\n try {\n const parsed: unknown = JSON.parse(args);\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed as Record<string, unknown> : null;\n } catch {\n return null;\n }\n}\n\nfunction settleTool(view: TaskLogView, { id: toolCallId, output, success, subagentId }: Event<'tool_result'>): TaskLogView {\n const [placed, lane] = laneOf(view, subagentId);\n const blocks = laneBlocks(placed, lane);\n const i = findLastIndex(blocks, (b) => b.type === 'tool' && b.status === 'pending' && b.toolCallId === toolCallId);\n const pending = blocks[i];\n const outcome = success ? 'success' : 'failure';\n if (pending?.type === 'tool') return laneReplace(placed, lane, i, finishedTool(pending, output, outcome));\n // The call that spawned a subagent is shown by the subagent's block, and\n // only the subagent's own finish settles it: a backgrounded agent's call\n // returns at launch, long before the work ends.\n if (lane === null && blocks.some((b) => b.type === 'subagent' && b.toolCallId === toolCallId)) return view;\n return laneAppend(placed, lane, (id) => finishedTool(pendingTool(id, { tool: 'agent_tool', toolLabel: 'Tool', args: '', toolCallId }), output, outcome));\n}\n\nfunction startSubagent(view: TaskLogView, { subagentId, brief, model }: Event<'subagent_started'>): TaskLogView {\n return updateSubagent(view, subagentId, undefined, (block) => ({ ...block, ...(brief ? { brief } : {}), ...(model ? { model } : {}) }));\n}\n\nfunction finishSubagent(view: TaskLogView, { subagentId, outcome, digest }: Event<'subagent_finished'>): TaskLogView {\n const usage = view.usage?.bySubagent?.[subagentId];\n const next = updateSubagent(view, subagentId, undefined, (block) => ({\n ...block, status: outcome, digest, children: block.children.map(sealed), ...(usage ? { usage } : {}),\n }));\n return withoutStream(next, thinkingStream(subagentId));\n}\n\nfunction reportUsage(view: TaskLogView, { record }: Event<'usage'>): TaskLogView {\n const usage = addPlannerUsage(view.usage ?? { totals: {} }, record);\n const next = { ...view, usage };\n return isMeasured(usage.totals) ? setUsageLine(next, usageLine(usage)) : next;\n}\n\n/** A runner's tool request, read the way its call's row reads: `Bash(npm test)`. */\nexport function runnerToolSubject(tool: string, args: string): string {\n const { tool: mapped, toolLabel } = mapAgentTool(tool);\n const parsed = parseArgs(args);\n const headline = toolHeadline(mapped, parsed ? JSON.stringify(normalizeAgentArgs(mapped, parsed)) : args, toolLabel);\n return headline.keyArg ? `${headline.name}(${headline.keyArg})` : headline.name;\n}\n\nfunction requestApproval(view: TaskLogView, { approvalId, tool, args, allowForTask, toolCallId, decided }: Event<'approval_requested'>): TaskLogView {\n if (view.blocks.some((b) => b.type === 'approval' && b.approvalId === approvalId)) return view;\n return append(view, (id) => {\n const block: ApprovalBlock = {\n type: 'approval', id, approvalId, kind: 'runner_tool',\n subject: runnerToolSubject(tool, args),\n scope: tool,\n status: 'pending',\n ...(allowForTask ? { allowForTask } : {}),\n ...(toolCallId ? { toolCallId } : {}),\n };\n // Already answered at the source (an Ordewell tool, an auto-approving\n // mode): shown settled rather than as something still waiting on a person.\n return decided ? answered(block, decided) : block;\n });\n}\n\nfunction settleApproval(view: TaskLogView, approvalId: string, settle: (block: ApprovalBlock) => ApprovalBlock): TaskLogView {\n const i = findLastIndex(view.blocks, (b) => b.type === 'approval' && b.approvalId === approvalId);\n const block = view.blocks[i];\n if (block?.type !== 'approval' || block.status !== 'pending') return view;\n return { ...view, blocks: replaceAt(view.blocks, i, settle(block)) };\n}\n\nfunction answered(block: ApprovalBlock, decision: ApprovalDecision['decision'], note?: string): ApprovalBlock {\n return {\n ...block,\n status: decision === 'deny' ? 'denied' : 'granted',\n decidedBy: 'asked',\n ...(decision === 'allowForTask' ? { forTask: true } : {}),\n ...(note ? { note } : {}),\n };\n}\n\nfunction decideApproval(view: TaskLogView, { approvalId, decision, note }: Event<'approval_decided'>): TaskLogView {\n return settleApproval(view, approvalId, (block) => answered(block, decision, note));\n}\n\nfunction startTurn(view: TaskLogView, { message, messageId, from, forced }: Event<'turn_start'>): TaskLogView {\n const queued = messageId ? view.queued.filter((m) => m.id !== messageId) : view.queued;\n const working = { ...view, queued, working: true, latestText: undefined };\n // A turn the runner opened itself has no user message to show.\n return message ? append(working, (id) => ({ ...sentMessage(id, message, from), ...(forced ? { forced: true } : {}) })) : working;\n}\n\n/** A message to the runner, drawn as the user's unless Ordewell sent it (ADR-0018, W1). */\nfunction sentMessage(id: string, text: string, from: TaskMessageFrom | undefined): MessageBlock {\n return from === 'ordewell' ? settledMessage(id, 'system', `Ordewell: ${text}`) : settledMessage(id, 'user', text);\n}\n\n/** A runner command opens its turn as a message would, shown as the command it runs (#66). */\nfunction startCommand(view: TaskLogView, { name, args, messageId }: Event<'command'>): TaskLogView {\n const queued = messageId ? view.queued.filter((m) => m.id !== messageId) : view.queued;\n return append({ ...view, queued, working: true, latestText: undefined }, (id) => ({\n type: 'command', id, name, ...(args ? { args } : {}), status: 'running', output: '',\n }));\n}\n\nfunction runningCommand(view: TaskLogView): number {\n return findLastIndex(view.blocks, (b) => b.type === 'command' && b.status === 'running');\n}\n\nfunction commandOutput(view: TaskLogView, { text }: Event<'command_output'>): TaskLogView {\n const i = runningCommand(view);\n const block = view.blocks[i];\n if (block?.type !== 'command') return append(view, (id) => settledMessage(id, 'system', text));\n return { ...view, blocks: replaceAt(view.blocks, i, { ...block, output: block.output ? `${block.output}\\n${text}` : text }) };\n}\n\nfunction modelSwitchNotice({ from, to, plan, kept }: Event<'model_switched'>): string {\n if (!plan) return `Model changed in the runner: ${from.label ?? from.model} → ${to.label ?? to.model}${kept ? ` (${kept})` : ''}`;\n const planned = plan.model ? `${plan.model.label ?? plan.model.model}${plan.effort ? `, ${plan.effort}` : ''}` : undefined;\n if (!kept) return `Model changed in the runner: ${from.label ?? from.model} → ${to.label ?? to.model}; the plan now says ${planned ?? to.label ?? to.model}`;\n return `The runner now answers on ${to.label ?? to.model}; ${planned ? `the plan still says ${planned}` : 'the plan names no model'} (${kept})`;\n}\n\n/** Among the turn's steps, as a tool call is: what streamed before it is settled. */\nfunction appendStep(view: TaskLogView, make: (id: string) => DisplayBlock): TaskLogView {\n const next = append(view, make);\n return sealLane(next, null, findLastIndex(next.blocks, (b) => b.type !== 'usage'));\n}\n\nconst CUT: Record<StructuredTurnEnd, SubagentStatus | null> = { completed: null, interrupted: 'stopped', failed: 'failed' };\nconst COMMAND_END: Record<StructuredTurnEnd, CommandStatus> = { completed: 'done', interrupted: 'stopped', failed: 'failed' };\n\nfunction endTurn(view: TaskLogView, { reason }: Event<'turn_end'>): TaskLogView {\n const i = runningCommand(view);\n const command = view.blocks[i];\n const settled = command?.type === 'command' ? { ...view, blocks: replaceAt(view.blocks, i, { ...command, status: COMMAND_END[reason] }) } : view;\n const closed = closeOpenBlocks({ ...settled, working: false, lastTurnEnd: reason, streams: {}, latestText: undefined }, CUT[reason]);\n return reason === 'interrupted' ? append(closed, (id) => settledMessage(id, 'system', 'Interrupted.')) : closed;\n}\n\nfunction queueMessage(view: TaskLogView, { messageId, text, forced, from }: Event<'message_queued'>): TaskLogView {\n const listed = view.queued.find((m) => m.id === messageId);\n const sender = from ? { from } : {};\n if (forced) {\n // The session's own order (ADR-0023, F2): behind earlier forced messages, ahead of the rest.\n // Forcing one the runner already has moves it without taking it back.\n const rest = view.queued.filter((m) => m !== listed);\n const at = rest.findIndex((m) => !m.forced);\n const placed = at < 0 ? rest.length : at;\n const handedOver = listed?.handedOver ? { handedOver: true } : {};\n return { ...view, queued: [...rest.slice(0, placed), { id: messageId, text, forced: true, ...handedOver, ...sender }, ...rest.slice(placed)] };\n }\n if (!listed) return { ...view, queued: [...view.queued, { id: messageId, text, ...sender }] };\n if (!listed.handedOver) return view;\n return { ...view, queued: view.queued.map((m) => (m === listed ? { id: m.id, text: m.text, ...(m.forced ? { forced: true } : {}), ...sender } : m)) };\n}\n\nfunction handOver(view: TaskLogView, { messageId }: Event<'message_handed_over'>): TaskLogView {\n const listed = view.queued.find((m) => m.id === messageId);\n if (!listed || listed.handedOver) return view;\n return { ...view, queued: view.queued.map((m) => (m === listed ? { ...m, handedOver: true } : m)) };\n}\n\n/** The message joins the transcript where the runner read it, between the steps around it. */\nfunction deliverMidTurn(view: TaskLogView, event: Event<'message_delivered'>): TaskLogView {\n return appendOutput(unqueueMessage(view, event), null, (id) => sentMessage(id, event.text, event.from));\n}\n\nfunction unqueueMessage(view: TaskLogView, { messageId }: { messageId: string }): TaskLogView {\n const queued = view.queued.filter((m) => m.id !== messageId);\n return queued.length === view.queued.length ? view : { ...view, queued };\n}\n\nfunction endCall<B extends SubagentChild>(block: B): B {\n return block.type === 'tool' && block.status === 'pending' ? finishedTool(block, '', 'not_executed') as B : block;\n}\n\n/** Whatever the runner left without a result ended with it. */\nfunction endOpenCalls(view: TaskLogView): TaskLogView {\n let changed = false;\n const blocks = view.blocks.map((block) => {\n const ended = block.type === 'subagent'\n ? (block.children.some((c) => c.type === 'tool' && c.status === 'pending') ? { ...block, children: block.children.map(endCall) } : block)\n : block.type === 'tool' ? endCall(block)\n : block.type === 'command' && block.status === 'running' ? { ...block, status: 'stopped' as const } : block;\n if (ended !== block) changed = true;\n return ended;\n });\n return changed ? { ...view, blocks } : view;\n}\n\n/**\n * Fold one task-log event into the view. Pure and incremental, like\n * `reduceConversation`: an event that changes nothing returns `view` itself,\n * and an event of a type this build does not know is skipped — a log written\n * by a newer Ordewell still reads.\n */\nexport function reduceTaskLog(view: TaskLogView, event: TaskLogEvent): TaskLogView {\n switch (event.type) {\n case 'task_skills': return append(view, (id) => settledMessage(id, 'system', `Skills: ${event.skills.map((s) => `${s.name} (${s.path})`).join(', ')}`));\n case 'turn_start': return startTurn(view, event);\n case 'command': return startCommand(view, event);\n case 'command_output': return commandOutput(view, event);\n case 'model_switched': return append(view, (id) => settledMessage(id, 'system', modelSwitchNotice(event)));\n case 'compaction': return appendStep(view, (id) => ({\n type: 'compaction', id, trigger: event.trigger,\n ...(event.preTokens !== undefined ? { preTokens: event.preTokens } : {}), ...(event.postTokens !== undefined ? { postTokens: event.postTokens } : {}),\n }));\n case 'runner_loaded': return append(view, (id) => ({ type: 'runner_loaded', id, commands: event.commands, mcpServers: event.mcpServers }));\n case 'turn_end': return endTurn(view, event);\n case 'text_delta': return agentTextDelta(view, event);\n case 'text': return agentText(view, event);\n case 'thinking_delta': return thinkingDelta(view, event);\n case 'thinking': return thinkingWhole(view, event);\n case 'tool_call': return announceTool(view, event);\n case 'tool_result': return settleTool(view, event);\n case 'subagent_started': return startSubagent(view, event);\n case 'subagent_finished': return finishSubagent(view, event);\n case 'usage': return reportUsage(view, event);\n case 'message_queued': return queueMessage(view, event);\n case 'message_removed': return unqueueMessage(view, event);\n case 'message_handed_over': return handOver(view, event);\n case 'message_delivered': return deliverMidTurn(view, event);\n case 'message_undelivered': return append(unqueueMessage(view, event), (id) => settledMessage(id, 'system', `${event.text} · not delivered`));\n case 'error': return failTurn(view, event.message);\n case 'approval_requested': return requestApproval(view, event);\n case 'approval_decided': return decideApproval(view, event);\n case 'approval_withdrawn': return settleApproval(view, event.approvalId, (block) => ({ ...block, status: 'withdrawn' }));\n case 'runner_ended': return closeOpenBlocks({ ...endOpenCalls(view), working: false, streams: {}, latestText: undefined }, 'stopped');\n default: return view;\n }\n}\n\n/** A whole attempt's events, folded from the start — what a reload shows. */\nexport function replayTaskLog(events: readonly TaskLogEvent[], from: TaskLogView = EMPTY_TASK_LOG): TaskLogView {\n return events.reduce(reduceTaskLog, from);\n}\n","/**\n * Prompts the user sent while a planner turn was in flight, waiting to be the\n * next turn's input. The hold is a plain immutable list, oldest first, so a\n * pure reducer can keep it in state and a host can keep it in a field — and\n * either can draw it as is.\n */\nexport type PromptHold = readonly string[];\n\nexport const EMPTY_HOLD: PromptHold = [];\n\n/** One prompt taken out of the hold, and what is left behind. */\nexport interface TakenPrompt {\n text: string;\n rest: PromptHold;\n}\n\nexport function holdPrompt(hold: PromptHold, text: string): PromptHold {\n return [...hold, text];\n}\n\n/** The prompt a settled turn sends next: the oldest, so they go in the order typed. */\nexport function drainNext(hold: PromptHold): TakenPrompt | undefined {\n const [text, ...rest] = hold;\n return text === undefined ? undefined : { text, rest };\n}\n\n/**\n * Takes back the newest prompt — the one the user most likely just regretted —\n * while the older ones stay queued behind the turn.\n */\nexport function unsendLatest(hold: PromptHold): TakenPrompt | undefined {\n if (hold.length === 0) return undefined;\n return { text: hold[hold.length - 1], rest: hold.slice(0, -1) };\n}\n\n/**\n * Takes one prompt out by position — a \"Send now\" on that held row — leaving\n * every other prompt in the order it was typed.\n */\nexport function takeAt(hold: PromptHold, index: number): TakenPrompt | undefined {\n if (index < 0 || index >= hold.length) return undefined;\n return { text: hold[index], rest: [...hold.slice(0, index), ...hold.slice(index + 1)] };\n}\n\n/**\n * A stopped turn takes its queue with it: the prompts were written against a\n * turn that no longer exists, so they come back as one draft to edit and\n * resend rather than firing off after the stop.\n */\nexport function unsendAll(hold: PromptHold): TakenPrompt | undefined {\n if (hold.length === 0) return undefined;\n return { text: hold.join('\\n'), rest: EMPTY_HOLD };\n}\n\n/** Where an unsent prompt lands in the drafting input: above what is being typed, never replacing it. */\nexport function aheadOfDraft(text: string, draft: string): string {\n return draft ? `${text}\\n${draft}` : text;\n}\n","import type { SessionMessage } from '../services/SessionMessage';\nimport { reduceConversation, type ConversationInput, type ConversationView } from './reduce';\n\n/**\n * The planner turn a surface has open, and the one its user stopped. Kept\n * beside the view rather than in it: the view is what a turn drew, this is\n * whether the surface still wants to hear from it.\n */\nexport interface TurnGate {\n readonly open: string | null;\n readonly stopped: string | null;\n}\n\nexport const NO_TURN: TurnGate = { open: null, stopped: null };\n\nexport interface GatedConversation {\n view: ConversationView;\n gate: TurnGate;\n}\n\n/** What a turn streams — everything a stop cuts off. Usage, approvals and transcript markers are facts and still land. */\nconst TURN_STREAM = new Set<SessionMessage['type']>([\n 'planner_text_delta', 'planner_thinking_delta', 'planner_text_retracted', 'planner_message', 'plan_token',\n 'research_step', 'research_step_done', 'subagent_started', 'subagent_finished', 'planner_turn_ended',\n 'planner_skill_loaded',\n]);\n\n// A message with no turn id while a stop stands can only be the stopped\n// turn's: a new turn announces itself first, and that lifts the stop.\nfunction cutOff(gate: TurnGate, input: ConversationInput): boolean {\n if (gate.stopped === null || !TURN_STREAM.has(input.type as SessionMessage['type'])) return false;\n const turnId = 'turnId' in input ? input.turnId : undefined;\n return turnId === undefined || turnId === gate.stopped;\n}\n\nfunction withGate(live: GatedConversation, gate: TurnGate): GatedConversation {\n return gate.open === live.gate.open && gate.stopped === live.gate.stopped ? live : { ...live, gate };\n}\n\n/**\n * One input into the view, the stop rule applied: a turn the user stopped is\n * over on screen, and whatever it streams until the backend notices is\n * dropped. An input that changes nothing hands back the same view and gate.\n */\nexport function followTurn(view: ConversationView, gate: TurnGate, input: ConversationInput): GatedConversation {\n const live = { view, gate };\n if (input.type === 'planner_turn_started') {\n return withGate({ view: reduceConversation(view, input), gate }, { open: input.turnId, stopped: null });\n }\n if (cutOff(gate, input)) {\n return input.type === 'planner_turn_ended' ? withGate(live, { ...gate, stopped: null }) : live;\n }\n const next = { view: reduceConversation(view, input), gate };\n return input.type === 'planner_turn_ended' && input.turnId === gate.open ? withGate(next, { ...gate, open: null }) : next;\n}\n\n/**\n * The user stopped the planner. The turn ends on screen now rather than when\n * the backend notices the abort, so the surface is free at once and the\n * turn's late output never lands. Nothing changes when no turn is open.\n */\nexport function stopTurn(view: ConversationView, gate: TurnGate): GatedConversation {\n if (gate.open === null) return { view, gate };\n return {\n view: reduceConversation(view, { type: 'planner_turn_ended', turnId: gate.open, outcome: 'stopped' }),\n gate: { open: null, stopped: gate.open },\n };\n}\n","import type { DisplayBlock } from './blocks';\n\n/**\n * Whether the conversation holds anything the collapsed view hides — thinking,\n * a command row's arguments and output, a subagent's children and digest,\n * what a task's runner loaded. The\n * detail toggle is the only expansion control (ADR-0017, X1), so a surface\n * offers it only when it would do something.\n */\nexport function hasHiddenDetail(blocks: readonly DisplayBlock[]): boolean {\n return blocks.some((b) => b.type === 'thinking' || b.type === 'tool' || b.type === 'subagent' || b.type === 'runner_loaded');\n}\n","/** The conversation line for a task starting, worded the same on every surface. */\nexport function taskStartedNotice(title: string, runner?: string): string {\n return runner ? `Started \"${title}\" · ${runner}` : `Started \"${title}\"`;\n}\n","import MarkdownIt from 'markdown-it';\n\n/*\n * The one Markdown parser every surface draws a model's text from. The text\n * can be steered by what the model read, so what it may turn into — no raw\n * HTML, no image, no link but a web one — is settled here, where no surface\n * can loosen it.\n */\n\n// `breaks`: a chat reply's single newline is a line break, as it reads in the\n// raw text the model wrote, not a space as in a CommonMark document.\nconst md = new MarkdownIt({ html: false, linkify: true, breaks: true });\n\n// Only a URL written with its scheme is linked. Fuzzy matching would turn file\n// names into links (.md, .rs, .py and .sh are all country domains).\nmd.linkify.set({ fuzzyLink: false, fuzzyEmail: false });\n\n// Every link passes here, linkify's and autolinks' included. An allowlist, not\n// markdown-it's javascript/vbscript/file/data denylist: a vscode: or command:\n// URI would act inside the editor, and a relative URL resolves against the\n// webview's own origin.\nmd.validateLink = (url) => /^https?:/i.test(url);\n\n// A remote image would make the webview fetch a URL the model chose. It is\n// replaced in the tokens rather than at render time, so no surface gets one.\nmd.core.ruler.after('linkify', 'image_as_text', (state) => {\n for (const block of state.tokens) {\n if (!block.children) continue;\n block.children = block.children.map((token) => {\n if (token.type !== 'image') return token;\n const text = new state.Token('text', '', 0);\n text.content = token.content || (token.attrGet('src') ?? '');\n return text;\n });\n }\n});\n\nmd.renderer.rules.link_open = (tokens, idx, options, _env, self) => {\n tokens[idx].attrSet('target', '_blank');\n tokens[idx].attrSet('rel', 'noopener');\n return self.renderToken(tokens, idx, options);\n};\n\n// A table made its own scroll container is still fitted to its parent's width,\n// squashing every column; a box around it scrolls and the table keeps its own.\nmd.renderer.rules.table_open = (tokens, idx, options, _env, self) => `<div class=\"md-table\">${self.renderToken(tokens, idx, options)}`;\nmd.renderer.rules.table_close = () => '</table></div>\\n';\n\n/**\n * One markdown-it token, as far as a surface reads it. Declared here rather\n * than re-exporting markdown-it's class so a surface depends on core alone.\n */\nexport interface MarkdownToken {\n readonly type: string;\n readonly tag: string;\n readonly nesting: 1 | 0 | -1;\n readonly level: number;\n readonly content: string;\n readonly markup: string;\n readonly info: string;\n readonly block: boolean;\n readonly hidden: boolean;\n readonly map: readonly [number, number] | null;\n readonly attrs: readonly (readonly [string, string])[] | null;\n readonly children: readonly MarkdownToken[] | null;\n}\n\n/** The parsed blocks of a model's text, for a surface that paints them itself (the TUI). */\nexport function markdownTokens(text: string): readonly MarkdownToken[] {\n return md.parse(text, {});\n}\n\n/** A model's text as HTML, safe to set as a webview element's innerHTML. */\nexport function markdownHtml(text: string): string {\n return md.render(text);\n}\n","import type { StreamStamp } from '../daemonContract';\nimport type { TaskLogEvent } from '../models/TaskLog';\nimport { EMPTY_TASK_LOG, reduceTaskLog, replayTaskLog, type TaskLogView } from './taskLog';\n\nexport interface TaskLogBatch {\n attempt: number;\n events: TaskLogEvent[];\n position?: StreamStamp;\n}\n\n/** A saved attempt and the live batches that follow it (ADR-0018 P1). */\nexport interface TaskLogFollow {\n view: TaskLogView;\n attempts: number[];\n attempt: number;\n pending: TaskLogBatch[];\n loaded: boolean;\n followLatest: boolean;\n /** The outstanding pick; an older attempt read cannot replace it. */\n loadingAttempt?: number;\n /** The saved read's cutoff, also rejecting socket copies delivered after the read. */\n position?: StreamStamp;\n}\n\nexport type TaskLogFollowInput =\n | { type: 'opened' }\n | ({ type: 'loaded'; attempts?: number[]; abandoned?: boolean } & TaskLogBatch)\n | ({ type: 'live' } & TaskLogBatch)\n | { type: 'picked'; attempt: number };\n\nexport const EMPTY_TASK_LOG_FOLLOW: TaskLogFollow = {\n view: EMPTY_TASK_LOG, attempts: [], attempt: 0, pending: [], loaded: false, followLatest: true,\n};\n\nfunction covered(position: StreamStamp | undefined, batch: TaskLogBatch): boolean {\n return !!position && !!batch.position && position.stream === batch.position.stream && batch.position.seq <= position.seq;\n}\n\nfunction live(state: TaskLogFollow, batch: TaskLogBatch): TaskLogFollow {\n if (batch.attempt <= 0 || batch.attempt < state.attempt) return state;\n const attempts = state.attempts.includes(batch.attempt) ? state.attempts : [...state.attempts, batch.attempt].sort((a, b) => a - b);\n if (batch.attempt > state.attempt) {\n if (!state.followLatest) return attempts === state.attempts ? state : { ...state, attempts };\n return { ...state, attempts, attempt: batch.attempt, position: undefined, view: batch.events.reduce(reduceTaskLog, EMPTY_TASK_LOG) };\n }\n if (covered(state.position, batch)) return state;\n return { ...state, attempts, view: batch.events.reduce(reduceTaskLog, state.view) };\n}\n\n/** Join by stream position, never by event content or socket arrival time. */\nexport function followTaskLog(state: TaskLogFollow, input: TaskLogFollowInput): TaskLogFollow {\n switch (input.type) {\n case 'opened': return EMPTY_TASK_LOG_FOLLOW;\n case 'picked': return { ...state, loaded: false, loadingAttempt: input.attempt, followLatest: input.attempt === state.attempts.at(-1) };\n case 'live':\n return state.loaded ? live(state, input) : { ...state, pending: [...state.pending, input] };\n case 'loaded': {\n if (state.loaded) return state;\n if (!input.abandoned && state.loadingAttempt !== undefined && input.attempt !== state.loadingAttempt) return state;\n const attempts = [...new Set([...(input.attempts ?? state.attempts), ...state.pending.map((batch) => batch.attempt)])].filter((attempt) => attempt > 0).sort((a, b) => a - b);\n let next: TaskLogFollow = {\n ...state, attempts, loaded: true, pending: [], loadingAttempt: undefined,\n ...(input.abandoned ? {} : { attempt: input.attempt, view: replayTaskLog(input.events), position: input.position }),\n };\n for (const batch of state.pending) {\n // A read of one attempt does not account for another attempt's file.\n if (!input.abandoned && batch.attempt === input.attempt) {\n if (covered(input.position, batch)) continue;\n // An older daemon supplies no position; preserve its replay behaviour.\n if (!input.position && !batch.position) continue;\n }\n next = live(next, batch);\n }\n return next;\n }\n }\n}\n","import { NOT_STARTED } from './status';\n\n/**\n * What a user can do to one task from its row. For a task paused on a usage\n * limit, `resume-now` resumes it in its saved session once the user says the\n * limit has reset, and `cancel-resume` keeps it from resuming on its own.\n */\nexport type TaskRowAction = 'cancel' | 'resume-now' | 'cancel-resume' | 'skip' | 'force-start' | 'complete' | 'uncomplete';\n\n/** A subtask runs with its parent, so its row offers a different set than a top-level task's. */\nexport type TaskRowPlacement = 'task' | 'subtask';\n\ninterface ActionSubject {\n status: string;\n type: 'ai' | 'user';\n awaitingReason?: string;\n resumeAt?: string | null;\n /** Its last attempt left a runner session to continue (ADR-0018, K1). */\n continuable?: boolean;\n}\n\ntype Rule = readonly [TaskRowAction, (task: ActionSubject) => boolean];\n\nconst UNSTARTED_AI = (t: ActionSubject): boolean => t.type === 'ai' && NOT_STARTED.has(t.status);\nconst QUEUED = (t: ActionSubject): boolean => t.status === 'pending' || t.status === 'approved';\nconst PAUSED = (t: ActionSubject): boolean => t.status === 'awaiting_user' && t.awaitingReason === 'usage-limit';\nconst RESUMES = (t: ActionSubject): boolean => PAUSED(t) && !!t.resumeAt;\nconst RESUMABLE = (t: ActionSubject): boolean => PAUSED(t) && t.continuable === true;\n/** Work that holds up what depends on it until someone acts: Skip lets the run go on without it. */\nconst HOLDS_UP = (t: ActionSubject): boolean => t.status === 'failed' || t.status === 'blocked' || t.status === 'awaiting_user';\n\n// Order is the order a surface lays the actions out in.\nconst TASK_RULES: readonly Rule[] = [\n ['cancel', (t) => t.status === 'in_progress'],\n ['resume-now', RESUMABLE],\n ['cancel-resume', RESUMES],\n ['skip', HOLDS_UP],\n ['force-start', UNSTARTED_AI],\n // A manual task has no runner to report it done, so it can always be marked;\n // a skipped one's kept work can still be vouched for.\n ['complete', (t) => t.status === 'awaiting_user' || t.status === 'skipped' || t.type === 'user'],\n ['uncomplete', (t) => t.status === 'completed'],\n];\n\nconst SUBTASK_RULES: readonly Rule[] = [\n ['cancel', (t) => t.status === 'in_progress'],\n ['resume-now', RESUMABLE],\n ['cancel-resume', RESUMES],\n ['complete', (t) => t.status === 'in_progress' && t.type === 'ai'],\n ['force-start', (t) => t.type === 'ai' && QUEUED(t)],\n ['skip', (t) => QUEUED(t) || t.status === 'failed'],\n ['complete', (t) => t.status === 'awaiting_user' || t.status === 'skipped'],\n ['uncomplete', (t) => t.status === 'completed'],\n];\n\n/** The actions a task's row offers while a plan runs, in the order they are laid out. */\nexport function taskRowActions(task: ActionSubject, placement: TaskRowPlacement = 'task'): TaskRowAction[] {\n const rules = placement === 'subtask' ? SUBTASK_RULES : TASK_RULES;\n return rules.filter(([, applies]) => applies(task)).map(([action]) => action);\n}\n\n/**\n * One toggle in both directions: a done task is taken back, anything else is\n * marked done. A second control for the reverse is one nobody remembers.\n */\nexport function markAction(task: { status: string }): 'complete' | 'uncomplete' {\n return task.status === 'completed' ? 'uncomplete' : 'complete';\n}\n\n/**\n * The mark an action asks the session for, or null when it is not a mark.\n * Skip is not one: it ends the task without vouching for its work, which\n * only Mark complete does.\n */\nexport function markRequestFor(action: string): 'complete' | 'uncomplete' | null {\n if (action === 'complete') return 'complete';\n if (action === 'uncomplete') return 'uncomplete';\n return null;\n}\n\n/** Change versus ops can still be flipped (ADR-0020): an AI task that has not started. */\nexport function opsEditable(task: ActionSubject): boolean {\n return UNSTARTED_AI(task);\n}\n","import type { AwaitingReason, DiscoveredModel, RunnerId } from '../models/Task';\nimport { effectiveAllowlist } from './ModelAllowlistResolver';\n\n/**\n * What the user allows the plan to be built from right now: the enabled\n * runners and each runner's model allowlist. Structural, so a surface that\n * only holds the two lists can ask without a session.\n */\nexport interface AssignmentScope {\n enabledRunners: readonly string[];\n allowlist: Readonly<Record<string, readonly string[] | undefined>>;\n /**\n * The models discovery has found per runner, where the holder has them. An\n * allowlist is read against them exactly as the planner's catalog reads it\n * (ids only another runner lists limit nothing), so a flag never says a\n * model is off a list the planner sees as no limit.\n */\n models?: Readonly<Partial<Record<RunnerId, readonly DiscoveredModel[]>>>;\n}\n\n/** The part of a task an assignment is read from. */\nexport interface AssignedTask {\n type: string;\n status: string;\n assignedRunner: string;\n assignedModel?: { modelId: string; modelLabel?: string };\n}\n\nexport type AssignmentIssue =\n | { kind: 'runner-off'; runner: string }\n | { kind: 'model-off-list'; runner: string; modelId: string; modelLabel: string };\n\n/** A finished task has nothing left to run, so where it ran is history, not a choice to revisit. */\nconst OVER = new Set(['completed', 'skipped']);\n\n/**\n * Whether a task sits outside the scope it is read against. This only names\n * the mismatch: such a task still runs (ADR-0003, P1) — the allowlist and the\n * enabled runners shape what is planned, not what is started — and the user or\n * the planner may move it. A runner that is off settles the matter before its\n * model is looked at.\n */\nexport function assignmentIssue(task: AssignedTask, scope: AssignmentScope): AssignmentIssue | null {\n if (task.type !== 'ai' || OVER.has(task.status)) return null;\n if (!scope.enabledRunners.includes(task.assignedRunner)) return { kind: 'runner-off', runner: task.assignedRunner };\n const model = task.assignedModel;\n const allowed = effectiveAllowlist(scope.allowlist[task.assignedRunner] as string[] | undefined, task.assignedRunner, scope.models as Partial<Record<RunnerId, DiscoveredModel[]>> | undefined);\n if (model && allowed && !allowed.includes(model.modelId)) {\n return { kind: 'model-off-list', runner: task.assignedRunner, modelId: model.modelId, modelLabel: model.modelLabel || model.modelId };\n }\n return null;\n}\n\nexport function assignmentIssueText(issue: AssignmentIssue): string {\n return issue.kind === 'runner-off' ? `${issue.runner} is switched off` : `${issue.modelLabel} is not in the allowlist`;\n}\n\n/** Where a flagged task stands, which decides what its assignment means. */\nexport interface AssignmentStanding {\n status?: string;\n awaitingReason?: AwaitingReason;\n resumeAt?: string | null;\n}\n\n/**\n * What happens to a flagged task as assigned, which depends on where it stands:\n * a failed one only runs again if retried, and a pause whose attempt ended (a\n * usage limit, work that did not land) has nothing running, whatever its\n * status says. The planner's note and every surface's flag read this one text.\n */\nexport function assignmentConsequence({ status, awaitingReason, resumeAt }: AssignmentStanding): string {\n if (status === 'failed') return 'failed; a retry would run it there unless moved';\n if (status === 'awaiting_user' && awaitingReason === 'usage-limit') {\n return resumeAt ? 'paused on a usage limit; resumes there at the reset unless moved' : 'paused on a usage limit; a retry would run it there unless moved';\n }\n if (status === 'awaiting_user' && (awaitingReason === 'conflict' || awaitingReason === 'files-changed')) return 'waiting for the user; what runs next runs there unless moved';\n if (status === 'in_progress' || status === 'awaiting_user') return 'already running as assigned';\n return 'runs as assigned unless moved';\n}\n","import { taskUsageSummary, type AttemptUsage, type TaskUsageSummary } from '../models/Usage';\nimport type { AwaitingReason } from '../models/Task';\nimport type { TaskIsolationState } from '../interfaces/IWorktreeIsolation';\nimport { taskOrderLabel, taskRefOf } from '../services/TaskRefs';\nimport { capConflictFiles } from '../services/conflictFiles';\nimport { blockingFailures, type BlockingSubject } from '../services/blocking';\nimport { assignmentConsequence, assignmentIssue, assignmentIssueText, type AssignmentScope } from '../services/AssignmentScope';\nimport { approvalLabel, awaitingLabel, isTaskRunning, NOT_STARTED, resumeLabel, taskStatusKind, WAITS_FOR_APPROVAL_LABEL, type TaskStatusKind } from './status';\nimport { markAction, opsEditable, taskRowActions, type TaskRowAction, type TaskRowPlacement } from './actions';\n\n/**\n * A task as both surfaces hold it, with the live state each tracks beside it\n * (silence, approvals, isolation, the merge gate). Structural, because the TUI\n * projects tasks into its own shape.\n */\nexport interface TaskRowSubject {\n id: string;\n order: number;\n type: 'ai' | 'user';\n status: string;\n dependencies: readonly string[];\n taskMode?: string;\n ops?: boolean;\n idleSince?: string | null;\n awaitingReason?: AwaitingReason;\n skipReason?: string;\n /** When a task paused on a usage limit resumes on its own (ISO time). */\n resumeAt?: string | null;\n /** Its last attempt left a runner session to continue (ADR-0018, K1). */\n continuable?: boolean;\n awaitingApproval?: number;\n /** Added after the user approved the plan, and not approved since (ADR-0035). */\n waitsForApproval?: boolean;\n isolation?: TaskRowIsolation | null;\n mergeGate?: readonly string[];\n forcedPastGate?: readonly string[];\n attemptUsage?: readonly AttemptUsage[];\n assignedRunner?: string;\n assignedModel?: { modelId: string; modelLabel?: string };\n}\n\nexport interface TaskRowIsolation {\n state: TaskIsolationState;\n repos?: string[];\n conflictRepo?: string;\n conflictFiles?: string[];\n repair?: { attempt: number; limit: number };\n repairedFiles?: string[];\n}\n\n/**\n * The plan a row labels its references against: the tree, so a subtask's\n * dependency reads dotted (\"#2.1\") rather than by its parent-scoped order.\n * With statuses and dependencies it also tells which tasks a failure blocks.\n */\ninterface PlanRefTask {\n id: string;\n order: number;\n title: string;\n status?: string;\n dependencies?: readonly string[];\n subtasks?: readonly PlanRefTask[];\n}\n\nexport interface TaskRowContext {\n /** Set for a subtask: it is labelled by its dotted order. */\n parent?: { order: number } | null;\n /** Which action set the row offers; a row with a parent is a subtask's unless told otherwise. */\n placement?: TaskRowPlacement;\n /** The plan tree a dependency, gate or block is labelled against; one it does not hold is shown by id. */\n tasks?: readonly PlanRefTask[];\n /** The modes the task's runner declares; autonomy is a tag on one of them (ADR-0001). */\n modes?: readonly { id: string; autonomous?: boolean }[];\n /** What a resume time is read against; the clock when absent. */\n now?: Date;\n /** The enabled runners and allowlist an assignment is read against; without it no assignment is flagged. */\n runnerScope?: AssignmentScope;\n}\n\n/** Whether the row stands for an AI task, a manual one, or an ops task (ADR-0020). */\nexport type TaskRowKind = 'ai' | 'user' | 'ops';\n\n/** The task's whole spend (see `taskUsageSummary`); `attempt` is the latest one, 0 before any reported. */\nexport interface TaskRowUsage extends Pick<TaskUsageSummary, 'totals' | 'contextFill'> {\n attempt: number;\n}\n\nexport interface TaskRowView {\n usage: TaskRowUsage | null;\n /** \"2\", or \"2.1\" for a subtask. */\n orderLabel: string;\n kind: TaskRowKind;\n status: TaskStatusKind;\n /** A runner is live behind it — `quiet` included. */\n running: boolean;\n /** What an awaiting task waits on, in sentence case; null when nothing was saved. */\n awaiting: string | null;\n /** \"Resumes at 8:10pm\" while a task paused on a usage limit resumes on its own; null otherwise. */\n resumes: string | null;\n /** Runner requests waiting on the user, in sentence case; null when none do. */\n approvals: string | null;\n /** That it waits for the user's approval to start, in sentence case; null once it started, or when it needs none. */\n waitsForApproval: string | null;\n /** Why the task's runner or model is one the user has since moved away from, in sentence case; null when it is not. The task still runs. */\n assignmentFlag: string | null;\n /** What the flag means for this task as it stands (a failed one runs again only if retried); set exactly when `assignmentFlag` is. */\n assignmentConsequence: string | null;\n /** The task's mode is tagged autonomous: it runs without permission prompts. */\n autonomous: boolean;\n /** The repos its isolated work changed, by path; empty for a group of one. */\n repos: string[];\n /** Integration stopped on a conflict: the one isolation state that needs the user. */\n conflict: { repo: string | null; files: string | null } | null;\n /** A conflict repair in flight (ADR-0015) — progress, not a blocker. */\n repairing: { files: string | null; attempt: { attempt: number; limit: number } | null } | null;\n /** The files a conflict repair was started for; `landed` once the task is integrated. */\n repaired: { files: string; landed: boolean } | null;\n /** The ancestors, by reference, whose work is not merged into the user's branch yet. */\n mergeGate: string[] | null;\n /** The failed tasks, by reference, a task not started waits on through its dependencies (ADR-0034); null when none. */\n blockedBy: string[] | null;\n /** Why a skipped task was skipped, as whoever skipped it put it; null for any other, or one skipped without a reason. */\n skipReason: string | null;\n /** An ops task changed tracked files in the user's checkout and nothing was committed. */\n opsChangedFiles: boolean;\n /** The ancestors, by title, a force start went past the merge gate of. */\n forcedPastGate: readonly string[] | null;\n /** The task's dependencies, by reference. */\n dependencies: string[];\n /** What the row offers while a plan runs. */\n actions: TaskRowAction[];\n /** The one mark its toggle sets. */\n mark: 'complete' | 'uncomplete';\n opsEditable: boolean;\n}\n\nconst refsOf = (ids: readonly string[], tasks: readonly PlanRefTask[] | undefined): string[] =>\n ids.map((id) => (tasks?.length ? taskRefOf(tasks, id) ?? id : id));\n\n/** A lone repository at the workspace root is not named: a group of one reads as it did before repo groups. */\nconst namedRepo = (repo: string | undefined): string | null => (repo && repo !== '.' ? repo : null);\n\n/** The repos a task changed, for a row that names them; none for a group of one. */\nexport const namedRepos = (repos: readonly string[] | undefined): string[] => (repos ?? []).filter((r) => r !== '.');\n\nconst filesOf = (files: string[] | undefined): string | null => (files?.length ? capConflictFiles(files) : null);\n\nconst asBlocking = (tasks: readonly PlanRefTask[]): BlockingSubject[] =>\n tasks.map((t) => ({ id: t.id, status: t.status ?? '', dependencies: t.dependencies ?? [], subtasks: asBlocking(t.subtasks ?? []) }));\n\n/** What blocks a task not started, read off the plan tree; empty without one that carries statuses. */\nfunction blockedBy(task: TaskRowSubject, tasks: readonly PlanRefTask[] | undefined): string[] {\n if (!tasks?.length || !NOT_STARTED.has(task.status)) return [];\n return blockingFailures(asBlocking(tasks)).get(task.id) ?? [];\n}\n\nfunction flagOf(task: TaskRowSubject, scope: AssignmentScope | undefined): Pick<TaskRowView, 'assignmentFlag' | 'assignmentConsequence'> {\n const issue = scope && task.assignedRunner !== undefined ? assignmentIssue({ ...task, assignedRunner: task.assignedRunner }, scope) : null;\n return issue\n ? { assignmentFlag: assignmentIssueText(issue), assignmentConsequence: assignmentConsequence(task) }\n : { assignmentFlag: null, assignmentConsequence: null };\n}\n\n/**\n * Everything a plan row says about one task, decided once: each surface picks\n * its own words, glyphs and casing for these facts, and derives none of them.\n */\nexport function taskRowView(task: TaskRowSubject, context: TaskRowContext = {}): TaskRowView {\n const parent = context.parent ?? undefined;\n const isolation = task.isolation && task.isolation.state !== 'none' ? task.isolation : null;\n const spend = taskUsageSummary(task);\n const latestAttempt = task.attemptUsage?.at(-1);\n const blocked = blockedBy(task, context.tasks);\n return {\n usage: latestAttempt ? { totals: spend.totals, ...(spend.contextFill ? { contextFill: spend.contextFill } : {}), attempt: latestAttempt.attempt } : task.type === 'ai' && ['completed', 'failed', 'in_progress', 'awaiting_user'].includes(task.status) ? { totals: {}, attempt: 0 } : null,\n orderLabel: taskOrderLabel(task, parent),\n kind: task.type === 'user' ? 'user' : task.ops ? 'ops' : 'ai',\n status: blocked.length > 0 ? 'blocked' : taskStatusKind(task),\n running: isTaskRunning(task),\n awaiting: awaitingLabel(task),\n resumes: resumeLabel(task, context.now),\n approvals: approvalLabel(task.awaitingApproval),\n waitsForApproval: task.waitsForApproval && NOT_STARTED.has(task.status) ? WAITS_FOR_APPROVAL_LABEL : null,\n ...flagOf(task, context.runnerScope),\n autonomous: task.type === 'ai' && context.modes?.find((m) => m.id === task.taskMode)?.autonomous === true,\n repos: namedRepos(isolation?.repos),\n conflict: isolation?.state === 'conflict'\n ? { repo: namedRepo(isolation.conflictRepo), files: filesOf(isolation.conflictFiles) }\n : null,\n repairing: isolation?.state === 'repairing'\n ? { files: filesOf(isolation.conflictFiles), attempt: isolation.repair ?? null }\n : null,\n repaired: isolation?.repairedFiles?.length\n ? { files: capConflictFiles(isolation.repairedFiles), landed: isolation.state === 'integrated' }\n : null,\n mergeGate: task.mergeGate?.length ? refsOf(task.mergeGate, context.tasks) : null,\n blockedBy: blocked.length > 0 ? refsOf(blocked, context.tasks) : null,\n skipReason: task.status === 'skipped' ? task.skipReason ?? null : null,\n opsChangedFiles: task.status === 'awaiting_user' && task.awaitingReason === 'files-changed',\n forcedPastGate: task.forcedPastGate?.length ? task.forcedPastGate : null,\n dependencies: refsOf(task.dependencies, context.tasks),\n // A block read off the plan offers what a stored one does: Skip among them.\n actions: taskRowActions(blocked.length > 0 ? { ...task, status: 'blocked' } : task, context.placement ?? (parent ? 'subtask' : 'task')),\n mark: markAction(task),\n opsEditable: opsEditable(task),\n };\n}\n","import { titledTaskRef, titledTaskRefOf } from '../services/TaskRefs';\n\ninterface Named {\n id: string;\n order: number;\n title: string;\n subtasks?: readonly Named[];\n}\n\n/** Each id as \"#N title\", subtasks dotted, by the plan's tree; one it no longer holds stays a bare id. */\nexport function titledRefs(ids: readonly string[], tasks: readonly Named[]): string[] {\n return ids.map((id) => titledTaskRefOf(tasks, id) ?? id);\n}\n\n/**\n * What removing a task does to the tasks that depend on it, or null when none\n * do. Named rather than counted: the removal rewrites their dependency lists,\n * and a bare \"Remove task?\" would hide that.\n */\nexport function dependentsNotice(dependents: readonly { id?: string; order: number; title: string }[], tasks: readonly Named[] = []): string | null {\n if (dependents.length === 0) return null;\n const subject = dependents.length === 1 ? '1 task depends' : `${dependents.length} tasks depend`;\n return `${subject} on it and will lose that dependency: ${dependents.map((t) => (t.id ? titledTaskRefOf(tasks, t.id) : undefined) ?? titledTaskRef(t)).join(', ')}.`;\n}\n\n/**\n * What a start past a merge gate is asked with (ADR-0020): the work the task\n * would act without, named. `subject` is how the asking surface refers to the\n * task — \"It\" under a title that already names it.\n */\nexport function pastGateConfirmation(unmerged: readonly string[], subject = 'This task'): string {\n return `${subject} waits for Merge all: the work of ${unmerged.join(', ')} is not merged into your branch yet, so it would act without it. Starting it now is kept on the task.`;\n}\n\nexport interface NewTaskFields {\n title: string;\n description: string;\n prompt: string;\n type: 'ai';\n}\n\n/**\n * What a hand-added task starts as: an AI task whose description is its title\n * and whose prompt, unless one was typed, is too. Null for a title with nothing\n * in it, rather than a nameless task. Assignments are left for the session to\n * derive from the runner's catalog.\n */\nexport function newTaskFields(title: string, prompt?: string): NewTaskFields | null {\n const name = title.trim();\n if (!name) return null;\n return { title: name, description: name, prompt: prompt?.trim() ? prompt : name, type: 'ai' };\n}\n","import { serializeTask, type RunInput, type RunMergeView, type RunTask, type RunTaskStatus, type RunView, type SerializedTask, type SerializedTaskStatus, type SurfacePlan, type SurfacePlanState, type SurfaceTask } from './SessionMessage';\nimport type { IsolationHandoff } from '../interfaces/IWorktreeIsolation';\nimport { rejoinPlanTree } from '../models/Task';\nimport { walkPlan } from './PlanTree';\n\nexport const EMPTY_RUN: RunView = { tasks: [], runMerge: null, handoff: null, mergeResult: null };\n\ntype PlanFields = Omit<RunTask, keyof RunTaskStatus>;\n\n/**\n * The one decision of which task fields are status-only: what is named here\n * no plan carries, so only a status update changes it and a plan refresh\n * keeps it. Everything else is the plan's.\n */\nfunction split({ verdict, idleSince, isolation, checkpoint, queued, continuable, awaitingApproval, mergeGate, forcedPastGate, waitsForApproval, ...plan }: RunTask): { plan: PlanFields; status: RunTaskStatus } {\n return { plan, status: { verdict, idleSince, isolation, checkpoint, queued, continuable, awaitingApproval, mergeGate, forcedPastGate, waitsForApproval } };\n}\n\n/**\n * The plan's tasks over what the view already holds: plan fields from the\n * plan, absent meaning none; status-only fields as the stream last said.\n */\nfunction refresh(previous: readonly RunTask[], tasks: readonly SerializedTask[]): RunTask[] {\n const held = new Map([...walkPlan(previous)].map(({ task }) => [task.id, task]));\n const fold = ({ subtasks, ...task }: SerializedTask): RunTask => {\n const was = held.get(task.id);\n const { checkpoint, ...status } = was ? split(was).status : {};\n // The question is answered once the plan says the task no longer waits at it.\n const waits = task.status === 'awaiting_user' && task.awaitingReason === 'checkpoint';\n return { ...task, ...status, ...(waits && checkpoint ? { checkpoint } : {}), subtasks: subtasks.map(fold) };\n };\n return tasks.map(fold);\n}\n\n/** A plan carries the task's wait and usage too, but a status update is the newer word on them. */\nfunction withStatus({ awaitingReason: _reason, resumeAt: _resumeAt, skipReason: _skipped, attemptUsage: _usage, ...plan }: PlanFields, { id: _id, ...status }: SerializedTaskStatus): Omit<RunTask, 'subtasks'> {\n return { ...plan, ...status };\n}\n\n/** A status update says everything about a task's status: what it leaves out, the task no longer has. */\nfunction applyStatus(tasks: readonly RunTask[], updates: ReadonlyMap<string, SerializedTaskStatus>): RunTask[] {\n return tasks.map((task) => {\n const subtasks = applyStatus(task.subtasks, updates);\n const update = updates.get(task.id);\n return update ? { ...withStatus(split(task).plan, update), subtasks } : { ...task, subtasks };\n });\n}\n\n/** `tasks` itself when `change` leaves the task named alone, or no task has that id. */\nfunction changeTask(tasks: RunTask[], taskId: string, change: (task: RunTask) => RunTask): RunTask[] {\n let changed = false;\n const next = tasks.map((task) => {\n const updated = task.id === taskId ? change(task) : task;\n const subtasks = changeTask(updated.subtasks, taskId, change);\n if (updated === task && subtasks === task.subtasks) return task;\n changed = true;\n return { ...updated, subtasks };\n });\n return changed ? next : tasks;\n}\n\nconst PATCHABLE: ReadonlySet<string> = new Set<keyof PlanFields>([\n 'order', 'title', 'type', 'status', 'description', 'dependencies', 'assignedRunner', 'assignedModel', 'taskMode', 'prompt',\n 'userSteps', 'autonomy', 'sliceType', 'userStoriesCovered', 'awaitingReason', 'resumeAt', 'skipReason', 'ops', 'skills', 'addedBy', 'attemptUsage',\n]);\n\nfunction patchTask(task: RunTask, changes: Record<string, unknown>): RunTask {\n const fields = Object.entries(changes).filter(([key]) => PATCHABLE.has(key));\n if (fields.length === 0) return task;\n // The patch is the `Partial<Task>` PlanEditor applied; past the filter, only plan fields remain.\n return { ...task, ...(Object.fromEntries(fields) as Partial<PlanFields>) };\n}\n\nfunction startTask(task: RunTask): RunTask {\n return task.status === 'in_progress' ? task : running(task);\n}\n\nfunction running({ awaitingReason: _reason, resumeAt: _resumeAt, skipReason: _skipped, checkpoint: _checkpoint, ...task }: RunTask): RunTask {\n return { ...task, status: 'in_progress' };\n}\n\nfunction withoutIsolation(tasks: readonly RunTask[]): RunTask[] {\n return tasks.map(({ isolation: _isolation, ...task }) => ({ ...task, subtasks: withoutIsolation(task.subtasks) }));\n}\n\nfunction handoffOf({ type: _type, ...handoff }: Extract<RunInput, { type: 'isolation_handoff' }>): IsolationHandoff {\n return handoff;\n}\n\n/**\n * A status update is the newer word on which landed work is still unmerged\n * (`runMerge`): git can find some of a handed-over run merged after all — a\n * reloaded session asks it — and a handoff offers only what is left, or goes\n * once nothing is. A handoff that landed nothing, offering only the clean-up\n * of what was kept, is not about merging and stays.\n */\nfunction stillToMerge(handoff: IsolationHandoff | null, runMerge: RunMergeView | undefined): IsolationHandoff | null {\n if (!handoff?.landed.length) return handoff;\n if (!runMerge) return null;\n const same = runMerge.landed.length === handoff.landed.length && runMerge.landed.every((t, i) => t.taskId === handoff.landed[i].taskId);\n return same ? handoff : { ...handoff, repos: runMerge.repos, landed: runMerge.landed };\n}\n\n/**\n * A saved plan keeps finished tasks in its execution log and the rest pending;\n * rejoined, the log wins for a task in both, being what actually happened.\n */\nfunction planTasks(plan: SurfacePlan | SurfacePlanState): SurfaceTask[] {\n if ('tasks' in plan) return plan.tasks;\n return rejoinPlanTree<SurfaceTask>(plan.pendingTasks, plan.phase === 'executing' ? plan.executionLog : []);\n}\n\nexport function reduceRun(view: RunView, input: RunInput): RunView {\n switch (input.type) {\n case 'plan_generated':\n return { ...view, tasks: refresh(view.tasks, input.plan.tasks), runSettings: input.plan.runSettings };\n case 'plan_snapshot':\n return {\n ...view,\n tasks: refresh(view.tasks, planTasks(input.plan).map(serializeTask)),\n // A saved plan's phase-tagged form has no run settings to say.\n runSettings: 'tasks' in input.plan ? input.plan.runSettings : view.runSettings,\n };\n case 'status_update':\n return {\n ...view,\n tasks: applyStatus(view.tasks, new Map(input.tasks.map((t) => [t.id, t]))),\n runMerge: input.runMerge ?? null,\n handoff: stillToMerge(view.handoff, input.runMerge),\n usage: input.usage,\n };\n case 'task_started':\n case 'task_updated': {\n const tasks = changeTask(view.tasks, input.taskId, (task) => (input.type === 'task_started' ? startTask(task) : patchTask(task, input.changes)));\n return tasks === view.tasks ? view : { ...view, tasks };\n }\n case 'plan_edit_held':\n return { ...view, heldEdit: input.held ?? undefined };\n case 'isolation_handoff':\n return { ...view, handoff: handoffOf(input) };\n case 'isolation_merge':\n return input.result.outcome === 'merged'\n ? { ...view, mergeResult: input.result, handoff: null, runMerge: null }\n : { ...view, mergeResult: input.result };\n case 'run_closed':\n return { ...view, tasks: withoutIsolation(view.tasks), handoff: null, runMerge: null, mergeResult: null };\n // A checkpoint's whole question and every status `review_needed` implies\n // arrive in the status update that follows; `review_needed`'s own list is\n // flat, so as a plan it would lift subtasks to the top level.\n case 'checkpoint':\n case 'review_needed':\n case 'review_approved':\n case 'execution_complete':\n case 'execution_stopped':\n case 'execution_action':\n case 'task_output':\n case 'task_log':\n case 'isolation_blocked':\n case 'planner_message':\n case 'planner_turn_started':\n case 'planner_skill_loaded':\n case 'planner_turn_ended':\n case 'planner_text_delta':\n case 'planner_thinking_delta':\n case 'planner_text_retracted':\n case 'planner_usage':\n case 'planner_liveness':\n case 'subagent_started':\n case 'subagent_finished':\n case 'research_step':\n case 'research_step_done':\n case 'plan_token':\n case 'approval_request':\n case 'approval_settled':\n case 'approval_decided':\n return view;\n default: {\n // Listed rather than defaulted, so a new message fails to compile until\n // someone decides what it does to a run.\n const unhandled: never = input;\n return unhandled;\n }\n }\n}\n"],"mappings":"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","names":["text","import_uuid","import_uuid","text","oneLine","text","lines","text","text","text","blockIds","answered","id","text","announceTool","parseArgs","settleTool","startSubagent","finishSubagent","reportUsage","requestApproval","settleApproval","decideApproval","endTurn","text","live","MarkdownIt","text"]}