@ordewell/core 0.4.22 → 0.4.23

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.
@@ -128,10 +128,10 @@ function checkModelAndModeValidity(runner, assignedModel, taskMode, catalog) {
128
128
  const models = catalog.modelsByRunner[runner];
129
129
  if (models) {
130
130
  const modelId = assignedModel.modelId;
131
- if (!models.some((m) => m.modelId === modelId)) {
131
+ const allowed = effectiveAllowlist(catalog.perRunnerAllowlist?.[runner], runner, catalog.modelsByRunner);
132
+ if (!models.some((m) => m.modelId === modelId) && !allowed?.includes(modelId)) {
132
133
  return { ok: false, error: `Runner "${runner}" does not offer model "${modelId}"` };
133
134
  }
134
- const allowed = effectiveAllowlist(catalog.perRunnerAllowlist?.[runner], runner, catalog.modelsByRunner);
135
135
  if (allowed && !allowed.includes(modelId)) {
136
136
  return { ok: false, error: `Model "${modelId}" is excluded by the allowlist for runner "${runner}"` };
137
137
  }
@@ -918,4 +918,4 @@ export {
918
918
  CHECKPOINT_TRUNCATE_LENGTH,
919
919
  truncateCheckpointSummary
920
920
  };
921
- //# sourceMappingURL=chunk-DV3YIKRA.mjs.map
921
+ //# sourceMappingURL=chunk-O2MFTRHA.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/services/ModelAllowlistResolver.ts","../src/services/TaskOps.ts","../src/services/TaskEditValidator.ts","../src/services/researchStepSummary.ts","../src/services/SessionMessage.ts"],"sourcesContent":["import type { DiscoveredModel, RunnerId, Task } 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, and a plugin runner may have 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 `coerceAssignments` and\n * `TaskRetarget` make);\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 * Clamp a planner/user-supplied thinking effort to what the model actually\n * offers. Invalid values map to the nearest rung the model supports (so a\n * Claude-style \"xhigh\" on a low/medium/high model becomes \"high\") and fall\n * back to undefined — the runner's own default — when no mapping exists.\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\nexport function coerceAssignments(\n tasks: Task[],\n perRunnerAllowlist: Partial<Record<RunnerId, string[]>>,\n allowedRunners?: RunnerId[],\n modelsByRunner?: Partial<Record<RunnerId, DiscoveredModel[]>>,\n): Task[] {\n // When the discovered catalog is available, snap each assignment's\n // thinkingEffort to a variant the model really has and stamp the model's\n // variant ids on the assignment (runners need them at spawn time); a model\n // we can't find in the catalog keeps its effort untouched (the runner\n // validates last).\n const clampVariant = (task: Task): Task => {\n if (!task.assignedModel || !modelsByRunner) return task;\n const model = modelsByRunner[task.assignedRunner]?.find(\n (m) => m.modelId === task.assignedModel!.modelId,\n );\n if (!model) return task;\n const clamped = clampThinkingEffort(task.assignedModel.thinkingEffort, model.variants);\n return {\n ...task,\n assignedModel: {\n ...task.assignedModel,\n thinkingEffort: clamped,\n availableVariants: model.variants.map((v) => v.id),\n },\n };\n };\n\n // One reading of the allowlist for the whole pass, so the models a task is\n // snapped to are the same ones the planner was shown (`filterModelsForPrompt`).\n const allowedFor = (runner: RunnerId): string[] | undefined =>\n effectiveAllowlist(perRunnerAllowlist[runner], runner, modelsByRunner);\n\n // A snapped-to model keeps the catalog's label and variant list where we have\n // one — an id alone reads as the model's name in every surface, and leaves the\n // effort picker with nothing to offer.\n const assignmentFor = (runner: RunnerId, modelId: string): NonNullable<Task['assignedModel']> => {\n const known = modelsByRunner?.[runner]?.find((m) => m.modelId === modelId);\n return {\n modelId,\n modelLabel: known?.modelLabel ?? modelId,\n thinkingEffort: undefined,\n ...(known ? { availableVariants: known.variants.map((v) => v.id) } : {}),\n };\n };\n\n return tasks.map((task) => {\n if (task.type === 'user') return task;\n\n if (allowedRunners && !allowedRunners.includes(task.assignedRunner)) {\n const fallbackRunner = allowedRunners[0];\n const fallbackModels = allowedFor(fallbackRunner);\n const fallbackModel = fallbackModels?.length\n ? assignmentFor(fallbackRunner, fallbackModels[0])\n : modelsByRunner?.[fallbackRunner]?.[0]\n ? assignmentFor(fallbackRunner, modelsByRunner[fallbackRunner]![0].modelId)\n : task.assignedModel;\n return clampVariant({\n ...task,\n assignedRunner: fallbackRunner,\n assignedModel: fallbackModel,\n });\n }\n\n const allowlist = allowedFor(task.assignedRunner);\n // No model assigned: fill in from the allowlist or discovered catalog so\n // merge/split/add outputs (which may omit assignedModel) always land with a\n // valid model for the task's runner.\n if (!task.assignedModel) {\n if (allowlist && allowlist.length > 0) {\n return clampVariant({ ...task, assignedModel: assignmentFor(task.assignedRunner, allowlist[0]) });\n }\n const discovered = modelsByRunner?.[task.assignedRunner]?.[0];\n if (discovered) {\n return clampVariant({ ...task, assignedModel: assignmentFor(task.assignedRunner, discovered.modelId) });\n }\n return task;\n }\n if (!allowlist || allowlist.length === 0) return clampVariant(task);\n if (allowlist.includes(task.assignedModel.modelId)) return clampVariant(task);\n return { ...task, assignedModel: assignmentFor(task.assignedRunner, allowlist[0]) };\n });\n}\n","import { v4 as uuidv4 } from 'uuid';\nimport {\n Task, RunnerId, flattenTasks,\n addTaskToPlan, removeTaskFromPlan, updateTaskInPlan, renumberTasks,\n createTask,\n} from '../models/Task';\nimport { extractObjectsWithKey, stripTrailingCommas, escapeControlCharsInStrings, PlanParseError, TASK_OPS_ENVELOPE_KEY } from './JsonExtractor';\nimport { validateTaskEdit, checkModelAndModeValidity, type EditCatalog } from './TaskEditValidator';\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 */\nexport type TaskOp =\n | { op: 'update'; taskId: string; changes: Partial<Task> }\n | { op: 'add'; task: Partial<Task>; handle?: string }\n | { op: 'remove'; taskId: string }\n | { op: 'reorder'; taskIds: string[] }\n | { op: 'merge'; taskIds: string[]; merged: Partial<Task>; handle?: string }\n | { op: 'split'; taskId: string; parts: Partial<Task>[]; handle?: string }\n | { op: 'rearm'; taskId: string; changes?: Partial<Task> };\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', 'thinkingEffort', 'type', 'userSteps', 'autonomy', 'sliceType',\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 a task reference (id, \"#3\", \"3\", or a batch handle) to a task id.\n *\n * `#order` and title matches are pinned to `originalScope` — 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 `liveScope` — 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 originalScope: Task[],\n liveScope: 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 later in this batch (op ${ownerIdx + 1}) 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 const byLiveId = liveScope.find((t) => t.id === s);\n if (byLiveId) return { id: byLiveId.id };\n const orderStr = s.startsWith('#') ? s.slice(1) : s;\n if (/^\\d+$/.test(orderStr)) {\n const order = Number(orderStr);\n const byOrder = originalScope.filter((t) => t.order === order);\n if (byOrder.length === 1) return { id: byOrder[0].id };\n }\n const byTitle = originalScope.find((t) => t.title === s);\n if (byTitle) return { id: byTitle.id };\n return { error: `task \"${s}\" not found` };\n}\n\n/** Whether `name` already denotes an existing task by id, `#order`, or title. */\nfunction refCollidesWithExisting(name: string, originalFlatAll: Task[]): boolean {\n if (originalFlatAll.some((t) => t.id === name)) return true;\n const orderStr = name.startsWith('#') ? name.slice(1) : name;\n if (/^\\d+$/.test(orderStr) && originalFlatAll.some((t) => t.order === Number(orderStr))) return true;\n return originalFlatAll.some((t) => t.title === name);\n}\n\nfunction findInTasks(tasks: Task[], id: string): Task | undefined {\n return flattenTasks(tasks).find((t) => t.id === id);\n}\n\nfunction findTopLevel(tasks: Task[], id: string): Task | undefined {\n return tasks.find((t) => t.id === id);\n}\n\nfunction detectCycle(tasks: Task[]): string | null {\n const byId = new Map(tasks.map((t) => [t.id, t]));\n const visiting = new Set<string>();\n const done = new Set<string>();\n const visit = (id: string): string | null => {\n if (done.has(id)) return null;\n if (visiting.has(id)) return id;\n visiting.add(id);\n for (const dep of byId.get(id)?.dependencies ?? []) {\n const hit = visit(dep);\n if (hit) return hit;\n }\n visiting.delete(id);\n done.add(id);\n return null;\n };\n for (const t of tasks) {\n const hit = visit(t.id);\n if (hit) return byId.get(hit)?.title ?? hit;\n }\n return null;\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/**\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: Task[];\n errors: string[];\n /** Human-readable summary of what changed, for the chat transcript. */\n summary: 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: 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\n/** The tasks listing `taskId` as a dependency — exactly what removing it detaches. */\nexport function dependentsOf<T extends Pick<TaskRef, 'id' | 'dependencies'>>(tasks: T[], taskId: string): T[] {\n return tasks.filter((t) => t.id !== taskId && t.dependencies.includes(taskId));\n}\n\n/**\n * The tasks that may become dependencies of `taskId`: those displayed before it.\n *\n * Offering only earlier tasks is what keeps a hand-edited graph valid without a\n * cycle check — dependencies then only ever point backwards in display order,\n * the same invariant `applyTaskOps` enforces. Omit `taskId` for a task that does\n * not exist yet: it lands last, so every current task is a candidate.\n */\nexport function dependencyCandidates<T extends Pick<TaskRef, 'id' | 'order'>>(tasks: T[], taskId?: string): T[] {\n if (!taskId) return [...tasks];\n const target = tasks.find((t) => t.id === taskId);\n return target ? tasks.filter((t) => t.order < target.order) : [];\n}\n\n/** Pre-flight check for a hand-edited dependency list: every id exists and comes earlier. */\nexport function canSetDependencies<T extends TaskRef>(\n tasks: T[],\n taskId: string,\n dependencies: string[],\n): { ok: boolean; error?: string } {\n const target = tasks.find((t) => t.id === taskId);\n if (!target) return { ok: false, error: 'Task not found' };\n const allowed = new Set(dependencyCandidates(tasks, taskId).map((t) => t.id));\n for (const dep of dependencies) {\n if (dep === taskId) return { ok: false, error: `\"${target.title}\" cannot depend on itself` };\n const found = tasks.find((t) => t.id === dep);\n if (!found) return { ok: false, error: `Unknown dependency \"${dep}\"` };\n if (!allowed.has(dep)) {\n return { ok: false, error: `\"${target.title}\" cannot depend on \"${found.title}\", which comes after it in the plan` };\n }\n }\n return { ok: true };\n}\n\n/** Pre-flight check for a split: the task exists and is not locked by execution. */\nexport function canSplitTask(tasks: 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/**\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(currentTasks: Task[], ops: TaskOp[], runners: RunnerId[], catalog?: EditCatalog): ApplyTaskOpsResult {\n let tasks: Task[] = JSON.parse(JSON.stringify(currentTasks));\n const errors: string[] = [];\n const summary: string[] = [];\n\n // Frozen snapshot every ref resolves `#order`/title matches against, so an\n // earlier op's renumbering can never shift what a later op's \"#N\" means.\n const originalFlatAll = flattenTasks(currentTasks);\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(`op ${i + 1} (${op.op}): handle must be a non-empty string`);\n continue;\n }\n if (handleOwner.has(handle)) {\n errors.push(`op ${i + 1} (${op.op}): handle \"${handle}\" is already used earlier in this batch`);\n continue;\n }\n if (refCollidesWithExisting(handle, originalFlatAll)) {\n errors.push(`op ${i + 1} (${op.op}): 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, originalFlatAll, liveFlat, 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 for (const [i, op] of ops.entries()) {\n const label = `op ${i + 1} (${op.op})`;\n switch (op.op) {\n case 'update': {\n const ref = resolveRef(op.taskId, originalFlatAll, flattenTasks(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 const changes: Partial<Task> = {};\n for (const key of UPDATABLE_FIELDS) {\n if (op.changes && key in op.changes) (changes as Record<string, unknown>)[key] = (op.changes as Record<string, unknown>)[key];\n }\n if (changes.assignedRunner && !runners.includes(changes.assignedRunner)) {\n errors.push(`${label}: runner \"${changes.assignedRunner}\" is not in this plan's runner set [${runners.join(', ')}]`);\n break;\n }\n // Dependency refs are still unresolved (e.g. \"#3\") at this point, so\n // this check runs on everything but them; resolveDeps below handles\n // dependency well-formedness once they're real ids.\n const changesForCheck: Partial<Task> = { ...changes };\n delete changesForCheck.dependencies;\n const check = validateTaskEdit('planner', flattenTasks(tasks), target.id, changesForCheck, catalog);\n if (!check.ok) { errors.push(`${label}: ${check.error}`); break; }\n for (const field of check.clear ?? []) (changes as Record<string, unknown>)[field] = undefined;\n if ('dependencies' in changes) {\n const { ids, bad } = resolveDeps(changes.dependencies, i);\n if (bad.length) { errors.push(`${label}: unknown dependencies: ${bad.join(', ')}`); break; }\n changes.dependencies = ids.filter((id) => id !== target.id);\n }\n if (Object.keys(changes).length === 0) { errors.push(`${label}: no valid changes provided`); break; }\n tasks = updateTaskInPlan(tasks, target.id, changes);\n const clearedNote = check.clear?.length ? `; cleared ${check.clear.join(', ')}` : '';\n summary.push(`Updated \"${target.title}\" (${Object.keys(changes).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 { ids, bad } = resolveDeps(spec.dependencies, i);\n if (bad.length) { errors.push(`${label}: unknown dependencies: ${bad.join(', ')}`); break; }\n const runner = spec.assignedRunner && runners.includes(spec.assignedRunner) ? spec.assignedRunner : runners[0];\n const validity = checkModelAndModeValidity(runner, spec.assignedModel, spec.taskMode, catalog);\n if (!validity.ok) { errors.push(`${label}: ${validity.error}`); break; }\n const newId = uuidv4();\n tasks = addTaskToPlan(tasks, {\n ...spec,\n id: newId,\n dependencies: ids,\n assignedRunner: runner,\n description: spec.description ?? spec.title,\n prompt: spec.prompt ?? spec.description ?? spec.title,\n });\n if (op.handle) handleId.set(op.handle, newId);\n summary.push(`Added \"${spec.title}\"`);\n break;\n }\n case 'remove': {\n const ref = resolveRef(op.taskId, originalFlatAll, flattenTasks(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 if (target.status === 'in_progress') { errors.push(`${label}: \"${target.title}\" is running and cannot be removed`); break; }\n if (target.status === 'completed') { errors.push(`${label}: \"${target.title}\" is completed and cannot be removed`); 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 = resolved.map((t) => t!).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.find((t) => t.status === 'in_progress' || t.status === 'completed');\n if (locked) {\n errors.push(`${label}: \"${locked.title}\" is ${locked.status === 'in_progress' ? 'running' : 'completed'} and cannot be merged`);\n break;\n }\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 const runner = spec.assignedRunner && runners.includes(spec.assignedRunner) ? spec.assignedRunner : toMerge[0].assignedRunner;\n const mergedTask = createTask({\n title: spec.title,\n description: spec.description ?? toMerge.map((t) => t.description).filter(Boolean).join('\\n\\n'),\n prompt: spec.prompt ?? (toMerge.map((t) => t.prompt).filter(Boolean).join('\\n\\n---\\n\\n') || undefined),\n type: spec.type ?? (toMerge.some((t) => t.type === 'user') ? 'user' : 'ai'),\n dependencies: ids,\n assignedRunner: runner,\n assignedModel: spec.assignedModel ?? toMerge.find((t) => t.assignedModel)?.assignedModel,\n thinkingEffort: spec.thinkingEffort ?? toMerge.find((t) => t.thinkingEffort)?.thinkingEffort,\n taskMode: spec.taskMode ?? toMerge[0].taskMode,\n autonomy: spec.autonomy ?? toMerge.find((t) => t.autonomy)?.autonomy,\n sliceType: spec.sliceType ?? toMerge.find((t) => t.sliceType)?.sliceType,\n userStoriesCovered: spec.userStoriesCovered ?? (toMerge.flatMap((t) => t.userStoriesCovered ?? []).length\n ? [...new Set(toMerge.flatMap((t) => t.userStoriesCovered ?? []))]\n : undefined),\n });\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 if (target.status === 'in_progress') { errors.push(`${label}: \"${target.title}\" is running and cannot be split`); break; }\n if (target.status === 'completed') { errors.push(`${label}: \"${target.title}\" is completed and cannot be split`); 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 runner = spec.assignedRunner && runners.includes(spec.assignedRunner) ? spec.assignedRunner : target.assignedRunner;\n const nt = createTask({\n title: spec.title,\n description: spec.description ?? spec.title,\n prompt: spec.prompt ?? spec.description ?? spec.title,\n type: spec.type ?? target.type,\n dependencies: deps,\n assignedRunner: runner,\n assignedModel: spec.assignedModel ?? target.assignedModel,\n taskMode: spec.taskMode ?? target.taskMode,\n autonomy: spec.autonomy ?? target.autonomy,\n sliceType: spec.sliceType ?? target.sliceType,\n userStoriesCovered: spec.userStoriesCovered ?? target.userStoriesCovered,\n });\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 const ref = resolveRef(op.taskId, originalFlatAll, flattenTasks(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 if (target.status === 'in_progress') { errors.push(`${label}: \"${target.title}\" is running and cannot be re-armed`); break; }\n const changes: Partial<Task> = {};\n for (const key of UPDATABLE_FIELDS) {\n if (op.changes && key in op.changes) (changes as Record<string, unknown>)[key] = (op.changes as Record<string, unknown>)[key];\n }\n if (changes.assignedRunner && !runners.includes(changes.assignedRunner)) {\n errors.push(`${label}: runner \"${changes.assignedRunner}\" is not in this plan's runner set [${runners.join(', ')}]`);\n break;\n }\n // Validated as a direct edit (not 'planner'): re-arming is the sanctioned\n // exception to the planner lock — its whole point is to touch a task the\n // lock would otherwise refuse. Well-formedness (type coherence, model/mode\n // validity, dependency shape) still applies, same as every other edit.\n const changesForCheck: Partial<Task> = { ...changes };\n delete changesForCheck.dependencies;\n const check = validateTaskEdit('direct', flattenTasks(tasks), target.id, changesForCheck, catalog);\n if (!check.ok) { errors.push(`${label}: ${check.error}`); break; }\n for (const field of check.clear ?? []) (changes as Record<string, unknown>)[field] = undefined;\n if ('dependencies' in changes) {\n const { ids, bad } = resolveDeps(changes.dependencies, i);\n if (bad.length) { errors.push(`${label}: unknown dependencies: ${bad.join(', ')}`); break; }\n changes.dependencies = ids.filter((id) => id !== target.id);\n }\n tasks = updateTaskInPlan(tasks, target.id, { ...changes, status: 'pending', verdict: undefined, outputSummary: undefined });\n // Dependents parked at 'blocked' by this task's earlier failure have\n // nothing else to release them — the scheduler reads `status` directly,\n // not a live recomputation of the dependency graph.\n for (const dep of flattenTasks(tasks)) {\n if (dep.status === 'blocked' && dep.dependencies.includes(target.id)) {\n tasks = updateTaskInPlan(tasks, dep.id, { status: 'pending' });\n }\n }\n const clearedNote = check.clear?.length ? `; cleared ${check.clear.join(', ')}` : '';\n const changedNote = Object.keys(changes).length ? ` (${Object.keys(changes).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 }\n\n if (!errors.length) {\n const flat = flattenTasks(tasks);\n const idSet = new Set(flat.map((t) => t.id));\n for (const t of flat) {\n for (const dep of t.dependencies) {\n if (!idSet.has(dep)) errors.push(`\"${t.title}\" depends on a task that no longer exists (${dep})`);\n }\n }\n const cycleAt = detectCycle(flat);\n if (cycleAt) errors.push(`Dependency cycle detected involving \"${cycleAt}\"`);\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\n return errors.length\n ? { ok: false, tasks: currentTasks, errors, summary: [] }\n : { ok: true, tasks, errors: [], summary };\n}\n","import { Task, RunnerId, DiscoveredModel, TaskModelAssignment, TaskMode } from '../models/Task';\nimport { canSetDependencies } from './TaskOps';\nimport { effectiveAllowlist } from './ModelAllowlistResolver';\nimport type { RunnerModeInfo } from './ModeResolver';\n\n/**\n * Who is making the edit. The planner (`applyTaskOps`) and the direct-edit\n * path (`Session.updateTask`/`setTaskDependencies`, reached by the TUI, the\n * webview task card, and `PUT /tasks/:taskId`) are deliberately asymmetric —\n * see CONTEXT.md, \"Direct edit vs planner edit\". The planner may not reach\n * into a task that is running or already finished; the direct path may,\n * because it is the user editing their own plan, and pays what that costs at\n * the call site (cancelling a live runner, releasing blocked dependents).\n */\nexport type TaskEditActor = 'planner' | 'direct';\n\nexport interface TaskEditCheck {\n ok: boolean;\n error?: string;\n /**\n * Fields a type flip strips of meaning, to be force-cleared by the caller\n * (set to `undefined` in the applied changes) and named in whatever summary\n * reaches the transcript. Only lists fields the target actually had a value\n * for — nothing to clear reads as nothing lost.\n */\n clear?: (keyof Task)[];\n}\n\nconst AI_ONLY_FIELDS = ['assignedModel', 'thinkingEffort', 'taskMode', 'autonomy'] as const satisfies readonly (keyof Task)[];\n\n/**\n * The catalog a model/task-mode edit is checked against — the same discovered\n * models and manifest modes the planner was shown in the per-turn catalog\n * block (`Session.catalogBlock`), so a refusal here can never name something\n * as invalid that the planner was never told about, or vice versa.\n */\nexport interface EditCatalog {\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>;\n runnerModes: Partial<Record<RunnerId, RunnerModeInfo[]>>;\n /** Raw (unfiltered) allowlist, keyed by runner — the same shape `coerceAssignments` takes. */\n perRunnerAllowlist?: Partial<Record<RunnerId, string[]>>;\n}\n\n/**\n * Whether an assigned model and task mode are things the target runner\n * actually offers. Invented ids are refused rather than silently substituted\n * downstream (`coerceAssignments` remains the safety net for paths that never\n * go through this validator) — the planner gets the refusal, with the runner\n * named, through the same repair loop as every other edit rejection.\n *\n * `catalog` is optional: callers with no discovered catalog on hand (most unit\n * tests, a runner with no manifest modes) skip these checks rather than\n * refusing everything sight-unseen.\n */\nexport function checkModelAndModeValidity(\n runner: RunnerId,\n assignedModel: TaskModelAssignment | undefined,\n taskMode: TaskMode | undefined,\n catalog: EditCatalog | undefined,\n): TaskEditCheck {\n if (!catalog) return { ok: true };\n\n if (assignedModel) {\n const models = catalog.modelsByRunner[runner];\n if (models) {\n const modelId = assignedModel.modelId;\n if (!models.some((m) => m.modelId === modelId)) {\n return { ok: false, error: `Runner \"${runner}\" does not offer model \"${modelId}\"` };\n }\n const allowed = effectiveAllowlist(catalog.perRunnerAllowlist?.[runner], runner, catalog.modelsByRunner);\n if (allowed && !allowed.includes(modelId)) {\n return { ok: false, error: `Model \"${modelId}\" is excluded by the allowlist for runner \"${runner}\"` };\n }\n }\n }\n\n if (taskMode !== undefined) {\n const modes = catalog.runnerModes[runner];\n if (modes && modes.length > 0 && !modes.some((m) => m.id === taskMode)) {\n return { ok: false, error: `Runner \"${runner}\" has no task mode \"${taskMode}\" — valid modes: ${modes.map((m) => m.id).join(', ')}` };\n }\n }\n\n return { ok: true };\n}\n\n/**\n * Coherence between `type` and the fields that only make sense for one side\n * of it. Deriving user steps from an AI prompt (or vice versa) would fabricate\n * instructions nobody wrote (ADR-0001: the plan is the source of truth), so a\n * flip that lacks the content the new type needs is refused rather than\n * silently patched — the planner gets that refusal back through the repair\n * loop; a direct edit gets it as a thrown reason. A flip that IS well-formed\n * clears the fields that stopped meaning anything, named for the caller.\n */\nfunction typeCoherenceCheck(target: Task, changes: Partial<Task>): TaskEditCheck | null {\n if (!changes.type || changes.type === target.type) return null;\n\n if (changes.type === 'user') {\n if (!Array.isArray(changes.userSteps) || changes.userSteps.length === 0) {\n return { ok: false, error: `\"${target.title}\" cannot become a manual task without user steps — include \"userSteps\" in this edit` };\n }\n return { ok: true, clear: AI_ONLY_FIELDS.filter((f) => target[f] !== undefined) };\n }\n\n // changes.type === 'ai'\n if (!changes.prompt || !changes.prompt.trim()) {\n return { ok: false, error: `\"${target.title}\" cannot become an AI task without a prompt — include \"prompt\" in this edit` };\n }\n return { ok: true, clear: target.userSteps && target.userSteps.length > 0 ? ['userSteps'] : [] };\n}\n\n/**\n * The rules governing one task edit, shared by both actors. Lock rules\n * (running/completed) apply to the planner only. Well-formedness rules — like\n * a hand-set dependency list, the one edit that can leave the plan\n * unschedulable, and type/content coherence on an AI↔MAN flip — describe the\n * task rather than who asked, so they run for both, through the same\n * {@link canSetDependencies} guard the pickers and the API read.\n */\nexport function validateTaskEdit(\n actor: TaskEditActor,\n tasks: Task[],\n taskId: string,\n changes: Partial<Task>,\n catalog?: EditCatalog,\n): TaskEditCheck {\n const target = tasks.find((t) => t.id === taskId);\n if (!target) return { ok: false, error: 'Task not found' };\n\n if (actor === 'planner') {\n if (target.status === 'in_progress') return { ok: false, error: `\"${target.title}\" is running and cannot be modified` };\n if (target.status === 'completed') return { ok: false, error: `\"${target.title}\" is completed and cannot be modified` };\n }\n\n if (changes.dependencies) {\n const depCheck = canSetDependencies(tasks, taskId, changes.dependencies);\n if (!depCheck.ok) return depCheck;\n }\n\n const coherence = typeCoherenceCheck(target, changes);\n if (coherence && !coherence.ok) return coherence;\n\n const runner = changes.assignedRunner ?? target.assignedRunner;\n const validity = checkModelAndModeValidity(runner, changes.assignedModel, changes.taskMode, catalog);\n if (!validity.ok) return validity;\n\n return coherence ?? { ok: true };\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 * and the research-subagent wrapper — keeping the matching here means the\n * signatures stay in one place alongside the human summary.\n */\nexport function classifyOutcome(success: boolean, output: string): ResearchStepOutcome {\n if (!success) {\n if (/^Command 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 { LegacyPlanState, QueuedMessage, ResearchStep, RunnerId, Task, Verdict } from '../models/Task';\nimport type { ApprovalKind } from '../interfaces/IApproval';\nimport type { ApprovalSource } from './ApprovalPolicy';\n\nexport type SerializedTaskStatus = {\n id: string;\n status: string;\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};\n\nexport type SerializedTask = {\n id: string;\n order: number;\n title: string;\n type: string;\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 thinkingEffort: Task['thinkingEffort'];\n autonomy: Task['autonomy'];\n sliceType: Task['sliceType'];\n userStoriesCovered: Task['userStoriesCovered'];\n};\n\nexport type SerializedPlan = {\n tasks: SerializedTask[];\n runners: RunnerId[];\n generatedAt: string;\n conversationHistory?: LegacyPlanState['conversationHistory'];\n prdMarkdown?: string;\n queuedMessages?: QueuedMessage[];\n};\n\nexport type SessionMessage =\n | { type: 'plan_generated'; plan: SerializedPlan; goal: string; runners: RunnerId[] }\n | { type: 'planner_message'; content: string; timestamp: string }\n | { type: 'status_update'; tasks: SerializedTaskStatus[] }\n | { type: 'review_needed'; tasks: SerializedTask[] }\n | { type: 'review_approved' }\n | { type: 'checkpoint'; taskId: string; taskTitle: string; summary: string }\n | { type: 'execution_complete'; summary: { total: number; completed: number; failed: number } }\n | { type: 'execution_stopped' }\n | { type: 'queue_ready' }\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 | { type: 'plan_thinking'; text: string }\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 }\n | { type: 'plan_token'; token: string }\n | { type: 'research_step_done'; step: ResearchStep; subagentId?: 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 }\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\nexport type SessionBroadcaster = (msg: SessionMessage) => void;\n\nexport function serializeTask(t: Task): SerializedTask {\n return {\n id: t.id,\n order: t.order,\n title: t.title,\n type: t.type,\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 thinkingEffort: t.thinkingEffort || undefined,\n autonomy: t.autonomy || undefined,\n sliceType: t.sliceType || undefined,\n userStoriesCovered: t.userStoriesCovered || undefined,\n };\n}\n\nexport function serializeTaskStatus(t: Task, idleSince: string | null = null): 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 };\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 conversationHistory: plan.conversationHistory,\n prdMarkdown: plan.prdMarkdown,\n queuedMessages: plan.queuedMessages,\n };\n}\n\nexport function executionSummary(tasks: Task[]): { total: number; completed: number; failed: number } {\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 };\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"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/services/ModelAllowlistResolver.ts","../src/services/TaskOps.ts","../src/services/TaskEditValidator.ts","../src/services/researchStepSummary.ts","../src/services/SessionMessage.ts"],"sourcesContent":["import type { DiscoveredModel, RunnerId, Task } 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, and a plugin runner may have 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 `coerceAssignments` and\n * `TaskRetarget` make);\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 * Clamp a planner/user-supplied thinking effort to what the model actually\n * offers. Invalid values map to the nearest rung the model supports (so a\n * Claude-style \"xhigh\" on a low/medium/high model becomes \"high\") and fall\n * back to undefined — the runner's own default — when no mapping exists.\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\nexport function coerceAssignments(\n tasks: Task[],\n perRunnerAllowlist: Partial<Record<RunnerId, string[]>>,\n allowedRunners?: RunnerId[],\n modelsByRunner?: Partial<Record<RunnerId, DiscoveredModel[]>>,\n): Task[] {\n // When the discovered catalog is available, snap each assignment's\n // thinkingEffort to a variant the model really has and stamp the model's\n // variant ids on the assignment (runners need them at spawn time); a model\n // we can't find in the catalog keeps its effort untouched (the runner\n // validates last).\n const clampVariant = (task: Task): Task => {\n if (!task.assignedModel || !modelsByRunner) return task;\n const model = modelsByRunner[task.assignedRunner]?.find(\n (m) => m.modelId === task.assignedModel!.modelId,\n );\n if (!model) return task;\n const clamped = clampThinkingEffort(task.assignedModel.thinkingEffort, model.variants);\n return {\n ...task,\n assignedModel: {\n ...task.assignedModel,\n thinkingEffort: clamped,\n availableVariants: model.variants.map((v) => v.id),\n },\n };\n };\n\n // One reading of the allowlist for the whole pass, so the models a task is\n // snapped to are the same ones the planner was shown (`filterModelsForPrompt`).\n const allowedFor = (runner: RunnerId): string[] | undefined =>\n effectiveAllowlist(perRunnerAllowlist[runner], runner, modelsByRunner);\n\n // A snapped-to model keeps the catalog's label and variant list where we have\n // one — an id alone reads as the model's name in every surface, and leaves the\n // effort picker with nothing to offer.\n const assignmentFor = (runner: RunnerId, modelId: string): NonNullable<Task['assignedModel']> => {\n const known = modelsByRunner?.[runner]?.find((m) => m.modelId === modelId);\n return {\n modelId,\n modelLabel: known?.modelLabel ?? modelId,\n thinkingEffort: undefined,\n ...(known ? { availableVariants: known.variants.map((v) => v.id) } : {}),\n };\n };\n\n return tasks.map((task) => {\n if (task.type === 'user') return task;\n\n if (allowedRunners && !allowedRunners.includes(task.assignedRunner)) {\n const fallbackRunner = allowedRunners[0];\n const fallbackModels = allowedFor(fallbackRunner);\n const fallbackModel = fallbackModels?.length\n ? assignmentFor(fallbackRunner, fallbackModels[0])\n : modelsByRunner?.[fallbackRunner]?.[0]\n ? assignmentFor(fallbackRunner, modelsByRunner[fallbackRunner]![0].modelId)\n : task.assignedModel;\n return clampVariant({\n ...task,\n assignedRunner: fallbackRunner,\n assignedModel: fallbackModel,\n });\n }\n\n const allowlist = allowedFor(task.assignedRunner);\n // No model assigned: fill in from the allowlist or discovered catalog so\n // merge/split/add outputs (which may omit assignedModel) always land with a\n // valid model for the task's runner.\n if (!task.assignedModel) {\n if (allowlist && allowlist.length > 0) {\n return clampVariant({ ...task, assignedModel: assignmentFor(task.assignedRunner, allowlist[0]) });\n }\n const discovered = modelsByRunner?.[task.assignedRunner]?.[0];\n if (discovered) {\n return clampVariant({ ...task, assignedModel: assignmentFor(task.assignedRunner, discovered.modelId) });\n }\n return task;\n }\n if (!allowlist || allowlist.length === 0) return clampVariant(task);\n if (allowlist.includes(task.assignedModel.modelId)) return clampVariant(task);\n return { ...task, assignedModel: assignmentFor(task.assignedRunner, allowlist[0]) };\n });\n}\n","import { v4 as uuidv4 } from 'uuid';\nimport {\n Task, RunnerId, flattenTasks,\n addTaskToPlan, removeTaskFromPlan, updateTaskInPlan, renumberTasks,\n createTask,\n} from '../models/Task';\nimport { extractObjectsWithKey, stripTrailingCommas, escapeControlCharsInStrings, PlanParseError, TASK_OPS_ENVELOPE_KEY } from './JsonExtractor';\nimport { validateTaskEdit, checkModelAndModeValidity, type EditCatalog } from './TaskEditValidator';\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 */\nexport type TaskOp =\n | { op: 'update'; taskId: string; changes: Partial<Task> }\n | { op: 'add'; task: Partial<Task>; handle?: string }\n | { op: 'remove'; taskId: string }\n | { op: 'reorder'; taskIds: string[] }\n | { op: 'merge'; taskIds: string[]; merged: Partial<Task>; handle?: string }\n | { op: 'split'; taskId: string; parts: Partial<Task>[]; handle?: string }\n | { op: 'rearm'; taskId: string; changes?: Partial<Task> };\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', 'thinkingEffort', 'type', 'userSteps', 'autonomy', 'sliceType',\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 a task reference (id, \"#3\", \"3\", or a batch handle) to a task id.\n *\n * `#order` and title matches are pinned to `originalScope` — 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 `liveScope` — 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 originalScope: Task[],\n liveScope: 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 later in this batch (op ${ownerIdx + 1}) 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 const byLiveId = liveScope.find((t) => t.id === s);\n if (byLiveId) return { id: byLiveId.id };\n const orderStr = s.startsWith('#') ? s.slice(1) : s;\n if (/^\\d+$/.test(orderStr)) {\n const order = Number(orderStr);\n const byOrder = originalScope.filter((t) => t.order === order);\n if (byOrder.length === 1) return { id: byOrder[0].id };\n }\n const byTitle = originalScope.find((t) => t.title === s);\n if (byTitle) return { id: byTitle.id };\n return { error: `task \"${s}\" not found` };\n}\n\n/** Whether `name` already denotes an existing task by id, `#order`, or title. */\nfunction refCollidesWithExisting(name: string, originalFlatAll: Task[]): boolean {\n if (originalFlatAll.some((t) => t.id === name)) return true;\n const orderStr = name.startsWith('#') ? name.slice(1) : name;\n if (/^\\d+$/.test(orderStr) && originalFlatAll.some((t) => t.order === Number(orderStr))) return true;\n return originalFlatAll.some((t) => t.title === name);\n}\n\nfunction findInTasks(tasks: Task[], id: string): Task | undefined {\n return flattenTasks(tasks).find((t) => t.id === id);\n}\n\nfunction findTopLevel(tasks: Task[], id: string): Task | undefined {\n return tasks.find((t) => t.id === id);\n}\n\nfunction detectCycle(tasks: Task[]): string | null {\n const byId = new Map(tasks.map((t) => [t.id, t]));\n const visiting = new Set<string>();\n const done = new Set<string>();\n const visit = (id: string): string | null => {\n if (done.has(id)) return null;\n if (visiting.has(id)) return id;\n visiting.add(id);\n for (const dep of byId.get(id)?.dependencies ?? []) {\n const hit = visit(dep);\n if (hit) return hit;\n }\n visiting.delete(id);\n done.add(id);\n return null;\n };\n for (const t of tasks) {\n const hit = visit(t.id);\n if (hit) return byId.get(hit)?.title ?? hit;\n }\n return null;\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/**\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: Task[];\n errors: string[];\n /** Human-readable summary of what changed, for the chat transcript. */\n summary: 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: 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\n/** The tasks listing `taskId` as a dependency — exactly what removing it detaches. */\nexport function dependentsOf<T extends Pick<TaskRef, 'id' | 'dependencies'>>(tasks: T[], taskId: string): T[] {\n return tasks.filter((t) => t.id !== taskId && t.dependencies.includes(taskId));\n}\n\n/**\n * The tasks that may become dependencies of `taskId`: those displayed before it.\n *\n * Offering only earlier tasks is what keeps a hand-edited graph valid without a\n * cycle check — dependencies then only ever point backwards in display order,\n * the same invariant `applyTaskOps` enforces. Omit `taskId` for a task that does\n * not exist yet: it lands last, so every current task is a candidate.\n */\nexport function dependencyCandidates<T extends Pick<TaskRef, 'id' | 'order'>>(tasks: T[], taskId?: string): T[] {\n if (!taskId) return [...tasks];\n const target = tasks.find((t) => t.id === taskId);\n return target ? tasks.filter((t) => t.order < target.order) : [];\n}\n\n/** Pre-flight check for a hand-edited dependency list: every id exists and comes earlier. */\nexport function canSetDependencies<T extends TaskRef>(\n tasks: T[],\n taskId: string,\n dependencies: string[],\n): { ok: boolean; error?: string } {\n const target = tasks.find((t) => t.id === taskId);\n if (!target) return { ok: false, error: 'Task not found' };\n const allowed = new Set(dependencyCandidates(tasks, taskId).map((t) => t.id));\n for (const dep of dependencies) {\n if (dep === taskId) return { ok: false, error: `\"${target.title}\" cannot depend on itself` };\n const found = tasks.find((t) => t.id === dep);\n if (!found) return { ok: false, error: `Unknown dependency \"${dep}\"` };\n if (!allowed.has(dep)) {\n return { ok: false, error: `\"${target.title}\" cannot depend on \"${found.title}\", which comes after it in the plan` };\n }\n }\n return { ok: true };\n}\n\n/** Pre-flight check for a split: the task exists and is not locked by execution. */\nexport function canSplitTask(tasks: 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/**\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(currentTasks: Task[], ops: TaskOp[], runners: RunnerId[], catalog?: EditCatalog): ApplyTaskOpsResult {\n let tasks: Task[] = JSON.parse(JSON.stringify(currentTasks));\n const errors: string[] = [];\n const summary: string[] = [];\n\n // Frozen snapshot every ref resolves `#order`/title matches against, so an\n // earlier op's renumbering can never shift what a later op's \"#N\" means.\n const originalFlatAll = flattenTasks(currentTasks);\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(`op ${i + 1} (${op.op}): handle must be a non-empty string`);\n continue;\n }\n if (handleOwner.has(handle)) {\n errors.push(`op ${i + 1} (${op.op}): handle \"${handle}\" is already used earlier in this batch`);\n continue;\n }\n if (refCollidesWithExisting(handle, originalFlatAll)) {\n errors.push(`op ${i + 1} (${op.op}): 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, originalFlatAll, liveFlat, 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 for (const [i, op] of ops.entries()) {\n const label = `op ${i + 1} (${op.op})`;\n switch (op.op) {\n case 'update': {\n const ref = resolveRef(op.taskId, originalFlatAll, flattenTasks(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 const changes: Partial<Task> = {};\n for (const key of UPDATABLE_FIELDS) {\n if (op.changes && key in op.changes) (changes as Record<string, unknown>)[key] = (op.changes as Record<string, unknown>)[key];\n }\n if (changes.assignedRunner && !runners.includes(changes.assignedRunner)) {\n errors.push(`${label}: runner \"${changes.assignedRunner}\" is not in this plan's runner set [${runners.join(', ')}]`);\n break;\n }\n // Dependency refs are still unresolved (e.g. \"#3\") at this point, so\n // this check runs on everything but them; resolveDeps below handles\n // dependency well-formedness once they're real ids.\n const changesForCheck: Partial<Task> = { ...changes };\n delete changesForCheck.dependencies;\n const check = validateTaskEdit('planner', flattenTasks(tasks), target.id, changesForCheck, catalog);\n if (!check.ok) { errors.push(`${label}: ${check.error}`); break; }\n for (const field of check.clear ?? []) (changes as Record<string, unknown>)[field] = undefined;\n if ('dependencies' in changes) {\n const { ids, bad } = resolveDeps(changes.dependencies, i);\n if (bad.length) { errors.push(`${label}: unknown dependencies: ${bad.join(', ')}`); break; }\n changes.dependencies = ids.filter((id) => id !== target.id);\n }\n if (Object.keys(changes).length === 0) { errors.push(`${label}: no valid changes provided`); break; }\n tasks = updateTaskInPlan(tasks, target.id, changes);\n const clearedNote = check.clear?.length ? `; cleared ${check.clear.join(', ')}` : '';\n summary.push(`Updated \"${target.title}\" (${Object.keys(changes).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 { ids, bad } = resolveDeps(spec.dependencies, i);\n if (bad.length) { errors.push(`${label}: unknown dependencies: ${bad.join(', ')}`); break; }\n const runner = spec.assignedRunner && runners.includes(spec.assignedRunner) ? spec.assignedRunner : runners[0];\n const validity = checkModelAndModeValidity(runner, spec.assignedModel, spec.taskMode, catalog);\n if (!validity.ok) { errors.push(`${label}: ${validity.error}`); break; }\n const newId = uuidv4();\n tasks = addTaskToPlan(tasks, {\n ...spec,\n id: newId,\n dependencies: ids,\n assignedRunner: runner,\n description: spec.description ?? spec.title,\n prompt: spec.prompt ?? spec.description ?? spec.title,\n });\n if (op.handle) handleId.set(op.handle, newId);\n summary.push(`Added \"${spec.title}\"`);\n break;\n }\n case 'remove': {\n const ref = resolveRef(op.taskId, originalFlatAll, flattenTasks(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 if (target.status === 'in_progress') { errors.push(`${label}: \"${target.title}\" is running and cannot be removed`); break; }\n if (target.status === 'completed') { errors.push(`${label}: \"${target.title}\" is completed and cannot be removed`); 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 = resolved.map((t) => t!).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.find((t) => t.status === 'in_progress' || t.status === 'completed');\n if (locked) {\n errors.push(`${label}: \"${locked.title}\" is ${locked.status === 'in_progress' ? 'running' : 'completed'} and cannot be merged`);\n break;\n }\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 const runner = spec.assignedRunner && runners.includes(spec.assignedRunner) ? spec.assignedRunner : toMerge[0].assignedRunner;\n const mergedTask = createTask({\n title: spec.title,\n description: spec.description ?? toMerge.map((t) => t.description).filter(Boolean).join('\\n\\n'),\n prompt: spec.prompt ?? (toMerge.map((t) => t.prompt).filter(Boolean).join('\\n\\n---\\n\\n') || undefined),\n type: spec.type ?? (toMerge.some((t) => t.type === 'user') ? 'user' : 'ai'),\n dependencies: ids,\n assignedRunner: runner,\n assignedModel: spec.assignedModel ?? toMerge.find((t) => t.assignedModel)?.assignedModel,\n thinkingEffort: spec.thinkingEffort ?? toMerge.find((t) => t.thinkingEffort)?.thinkingEffort,\n taskMode: spec.taskMode ?? toMerge[0].taskMode,\n autonomy: spec.autonomy ?? toMerge.find((t) => t.autonomy)?.autonomy,\n sliceType: spec.sliceType ?? toMerge.find((t) => t.sliceType)?.sliceType,\n userStoriesCovered: spec.userStoriesCovered ?? (toMerge.flatMap((t) => t.userStoriesCovered ?? []).length\n ? [...new Set(toMerge.flatMap((t) => t.userStoriesCovered ?? []))]\n : undefined),\n });\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 if (target.status === 'in_progress') { errors.push(`${label}: \"${target.title}\" is running and cannot be split`); break; }\n if (target.status === 'completed') { errors.push(`${label}: \"${target.title}\" is completed and cannot be split`); 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 runner = spec.assignedRunner && runners.includes(spec.assignedRunner) ? spec.assignedRunner : target.assignedRunner;\n const nt = createTask({\n title: spec.title,\n description: spec.description ?? spec.title,\n prompt: spec.prompt ?? spec.description ?? spec.title,\n type: spec.type ?? target.type,\n dependencies: deps,\n assignedRunner: runner,\n assignedModel: spec.assignedModel ?? target.assignedModel,\n taskMode: spec.taskMode ?? target.taskMode,\n autonomy: spec.autonomy ?? target.autonomy,\n sliceType: spec.sliceType ?? target.sliceType,\n userStoriesCovered: spec.userStoriesCovered ?? target.userStoriesCovered,\n });\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 const ref = resolveRef(op.taskId, originalFlatAll, flattenTasks(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 if (target.status === 'in_progress') { errors.push(`${label}: \"${target.title}\" is running and cannot be re-armed`); break; }\n const changes: Partial<Task> = {};\n for (const key of UPDATABLE_FIELDS) {\n if (op.changes && key in op.changes) (changes as Record<string, unknown>)[key] = (op.changes as Record<string, unknown>)[key];\n }\n if (changes.assignedRunner && !runners.includes(changes.assignedRunner)) {\n errors.push(`${label}: runner \"${changes.assignedRunner}\" is not in this plan's runner set [${runners.join(', ')}]`);\n break;\n }\n // Validated as a direct edit (not 'planner'): re-arming is the sanctioned\n // exception to the planner lock — its whole point is to touch a task the\n // lock would otherwise refuse. Well-formedness (type coherence, model/mode\n // validity, dependency shape) still applies, same as every other edit.\n const changesForCheck: Partial<Task> = { ...changes };\n delete changesForCheck.dependencies;\n const check = validateTaskEdit('direct', flattenTasks(tasks), target.id, changesForCheck, catalog);\n if (!check.ok) { errors.push(`${label}: ${check.error}`); break; }\n for (const field of check.clear ?? []) (changes as Record<string, unknown>)[field] = undefined;\n if ('dependencies' in changes) {\n const { ids, bad } = resolveDeps(changes.dependencies, i);\n if (bad.length) { errors.push(`${label}: unknown dependencies: ${bad.join(', ')}`); break; }\n changes.dependencies = ids.filter((id) => id !== target.id);\n }\n tasks = updateTaskInPlan(tasks, target.id, { ...changes, status: 'pending', verdict: undefined, outputSummary: undefined });\n // Dependents parked at 'blocked' by this task's earlier failure have\n // nothing else to release them — the scheduler reads `status` directly,\n // not a live recomputation of the dependency graph.\n for (const dep of flattenTasks(tasks)) {\n if (dep.status === 'blocked' && dep.dependencies.includes(target.id)) {\n tasks = updateTaskInPlan(tasks, dep.id, { status: 'pending' });\n }\n }\n const clearedNote = check.clear?.length ? `; cleared ${check.clear.join(', ')}` : '';\n const changedNote = Object.keys(changes).length ? ` (${Object.keys(changes).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 }\n\n if (!errors.length) {\n const flat = flattenTasks(tasks);\n const idSet = new Set(flat.map((t) => t.id));\n for (const t of flat) {\n for (const dep of t.dependencies) {\n if (!idSet.has(dep)) errors.push(`\"${t.title}\" depends on a task that no longer exists (${dep})`);\n }\n }\n const cycleAt = detectCycle(flat);\n if (cycleAt) errors.push(`Dependency cycle detected involving \"${cycleAt}\"`);\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\n return errors.length\n ? { ok: false, tasks: currentTasks, errors, summary: [] }\n : { ok: true, tasks, errors: [], summary };\n}\n","import { Task, RunnerId, DiscoveredModel, TaskModelAssignment, TaskMode } from '../models/Task';\nimport { canSetDependencies } from './TaskOps';\nimport { effectiveAllowlist } from './ModelAllowlistResolver';\nimport type { RunnerModeInfo } from './ModeResolver';\n\n/**\n * Who is making the edit. The planner (`applyTaskOps`) and the direct-edit\n * path (`Session.updateTask`/`setTaskDependencies`, reached by the TUI, the\n * webview task card, and `PUT /tasks/:taskId`) are deliberately asymmetric —\n * see CONTEXT.md, \"Direct edit vs planner edit\". The planner may not reach\n * into a task that is running or already finished; the direct path may,\n * because it is the user editing their own plan, and pays what that costs at\n * the call site (cancelling a live runner, releasing blocked dependents).\n */\nexport type TaskEditActor = 'planner' | 'direct';\n\nexport interface TaskEditCheck {\n ok: boolean;\n error?: string;\n /**\n * Fields a type flip strips of meaning, to be force-cleared by the caller\n * (set to `undefined` in the applied changes) and named in whatever summary\n * reaches the transcript. Only lists fields the target actually had a value\n * for — nothing to clear reads as nothing lost.\n */\n clear?: (keyof Task)[];\n}\n\nconst AI_ONLY_FIELDS = ['assignedModel', 'thinkingEffort', 'taskMode', 'autonomy'] as const satisfies readonly (keyof Task)[];\n\n/**\n * The catalog a model/task-mode edit is checked against — the same discovered\n * models and manifest modes the planner was shown in the per-turn catalog\n * block (`Session.catalogBlock`), so a refusal here can never name something\n * as invalid that the planner was never told about, or vice versa.\n */\nexport interface EditCatalog {\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>;\n runnerModes: Partial<Record<RunnerId, RunnerModeInfo[]>>;\n /** Raw (unfiltered) allowlist, keyed by runner — the same shape `coerceAssignments` takes. */\n perRunnerAllowlist?: Partial<Record<RunnerId, string[]>>;\n}\n\n/**\n * Whether an assigned model and task mode are things the target runner\n * actually offers. Invented ids are refused rather than silently substituted\n * downstream (`coerceAssignments` remains the safety net for paths that never\n * go through this validator) — the planner gets the refusal, with the runner\n * named, through the same repair loop as every other edit rejection.\n *\n * `catalog` is optional: callers with no discovered catalog on hand (most unit\n * tests, a runner with no manifest modes) skip these checks rather than\n * refusing everything sight-unseen.\n */\nexport function checkModelAndModeValidity(\n runner: RunnerId,\n assignedModel: TaskModelAssignment | undefined,\n taskMode: TaskMode | undefined,\n catalog: EditCatalog | undefined,\n): TaskEditCheck {\n if (!catalog) return { ok: true };\n\n if (assignedModel) {\n const models = catalog.modelsByRunner[runner];\n if (models) {\n const modelId = assignedModel.modelId;\n const allowed = effectiveAllowlist(catalog.perRunnerAllowlist?.[runner], runner, catalog.modelsByRunner);\n // An allowlisted id discovery doesn't list is one `filterModelsForPrompt`\n // shows the planner anyway — refusing it here would contradict the\n // catalog block; the runner validates it last.\n if (!models.some((m) => m.modelId === modelId) && !allowed?.includes(modelId)) {\n return { ok: false, error: `Runner \"${runner}\" does not offer model \"${modelId}\"` };\n }\n if (allowed && !allowed.includes(modelId)) {\n return { ok: false, error: `Model \"${modelId}\" is excluded by the allowlist for runner \"${runner}\"` };\n }\n }\n }\n\n if (taskMode !== undefined) {\n const modes = catalog.runnerModes[runner];\n if (modes && modes.length > 0 && !modes.some((m) => m.id === taskMode)) {\n return { ok: false, error: `Runner \"${runner}\" has no task mode \"${taskMode}\" — valid modes: ${modes.map((m) => m.id).join(', ')}` };\n }\n }\n\n return { ok: true };\n}\n\n/**\n * Coherence between `type` and the fields that only make sense for one side\n * of it. Deriving user steps from an AI prompt (or vice versa) would fabricate\n * instructions nobody wrote (ADR-0001: the plan is the source of truth), so a\n * flip that lacks the content the new type needs is refused rather than\n * silently patched — the planner gets that refusal back through the repair\n * loop; a direct edit gets it as a thrown reason. A flip that IS well-formed\n * clears the fields that stopped meaning anything, named for the caller.\n */\nfunction typeCoherenceCheck(target: Task, changes: Partial<Task>): TaskEditCheck | null {\n if (!changes.type || changes.type === target.type) return null;\n\n if (changes.type === 'user') {\n if (!Array.isArray(changes.userSteps) || changes.userSteps.length === 0) {\n return { ok: false, error: `\"${target.title}\" cannot become a manual task without user steps — include \"userSteps\" in this edit` };\n }\n return { ok: true, clear: AI_ONLY_FIELDS.filter((f) => target[f] !== undefined) };\n }\n\n // changes.type === 'ai'\n if (!changes.prompt || !changes.prompt.trim()) {\n return { ok: false, error: `\"${target.title}\" cannot become an AI task without a prompt — include \"prompt\" in this edit` };\n }\n return { ok: true, clear: target.userSteps && target.userSteps.length > 0 ? ['userSteps'] : [] };\n}\n\n/**\n * The rules governing one task edit, shared by both actors. Lock rules\n * (running/completed) apply to the planner only. Well-formedness rules — like\n * a hand-set dependency list, the one edit that can leave the plan\n * unschedulable, and type/content coherence on an AI↔MAN flip — describe the\n * task rather than who asked, so they run for both, through the same\n * {@link canSetDependencies} guard the pickers and the API read.\n */\nexport function validateTaskEdit(\n actor: TaskEditActor,\n tasks: Task[],\n taskId: string,\n changes: Partial<Task>,\n catalog?: EditCatalog,\n): TaskEditCheck {\n const target = tasks.find((t) => t.id === taskId);\n if (!target) return { ok: false, error: 'Task not found' };\n\n if (actor === 'planner') {\n if (target.status === 'in_progress') return { ok: false, error: `\"${target.title}\" is running and cannot be modified` };\n if (target.status === 'completed') return { ok: false, error: `\"${target.title}\" is completed and cannot be modified` };\n }\n\n if (changes.dependencies) {\n const depCheck = canSetDependencies(tasks, taskId, changes.dependencies);\n if (!depCheck.ok) return depCheck;\n }\n\n const coherence = typeCoherenceCheck(target, changes);\n if (coherence && !coherence.ok) return coherence;\n\n const runner = changes.assignedRunner ?? target.assignedRunner;\n const validity = checkModelAndModeValidity(runner, changes.assignedModel, changes.taskMode, catalog);\n if (!validity.ok) return validity;\n\n return coherence ?? { ok: true };\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 * and the research-subagent wrapper — keeping the matching here means the\n * signatures stay in one place alongside the human summary.\n */\nexport function classifyOutcome(success: boolean, output: string): ResearchStepOutcome {\n if (!success) {\n if (/^Command 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 { LegacyPlanState, QueuedMessage, ResearchStep, RunnerId, Task, Verdict } from '../models/Task';\nimport type { ApprovalKind } from '../interfaces/IApproval';\nimport type { ApprovalSource } from './ApprovalPolicy';\n\nexport type SerializedTaskStatus = {\n id: string;\n status: string;\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};\n\nexport type SerializedTask = {\n id: string;\n order: number;\n title: string;\n type: string;\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 thinkingEffort: Task['thinkingEffort'];\n autonomy: Task['autonomy'];\n sliceType: Task['sliceType'];\n userStoriesCovered: Task['userStoriesCovered'];\n};\n\nexport type SerializedPlan = {\n tasks: SerializedTask[];\n runners: RunnerId[];\n generatedAt: string;\n conversationHistory?: LegacyPlanState['conversationHistory'];\n prdMarkdown?: string;\n queuedMessages?: QueuedMessage[];\n};\n\nexport type SessionMessage =\n | { type: 'plan_generated'; plan: SerializedPlan; goal: string; runners: RunnerId[] }\n | { type: 'planner_message'; content: string; timestamp: string }\n | { type: 'status_update'; tasks: SerializedTaskStatus[] }\n | { type: 'review_needed'; tasks: SerializedTask[] }\n | { type: 'review_approved' }\n | { type: 'checkpoint'; taskId: string; taskTitle: string; summary: string }\n | { type: 'execution_complete'; summary: { total: number; completed: number; failed: number } }\n | { type: 'execution_stopped' }\n | { type: 'queue_ready' }\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 | { type: 'plan_thinking'; text: string }\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 }\n | { type: 'plan_token'; token: string }\n | { type: 'research_step_done'; step: ResearchStep; subagentId?: 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 }\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\nexport type SessionBroadcaster = (msg: SessionMessage) => void;\n\nexport function serializeTask(t: Task): SerializedTask {\n return {\n id: t.id,\n order: t.order,\n title: t.title,\n type: t.type,\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 thinkingEffort: t.thinkingEffort || undefined,\n autonomy: t.autonomy || undefined,\n sliceType: t.sliceType || undefined,\n userStoriesCovered: t.userStoriesCovered || undefined,\n };\n}\n\nexport function serializeTaskStatus(t: Task, idleSince: string | null = null): 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 };\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 conversationHistory: plan.conversationHistory,\n prdMarkdown: plan.prdMarkdown,\n queuedMessages: plan.queuedMessages,\n };\n}\n\nexport function executionSummary(tasks: Task[]): { total: number; completed: number; failed: number } {\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 };\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"],"mappings":"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","names":[]}
package/dist/index.d.mts CHANGED
@@ -2492,7 +2492,6 @@ declare class Session {
2492
2492
  private approvalPolicy;
2493
2493
  private fetcher;
2494
2494
  private settingsFn;
2495
- private currentAllowlist;
2496
2495
  /** Last discovered model catalog — lets sync plan commits clamp thinking efforts to real variants. */
2497
2496
  private modelsCache;
2498
2497
  private unsubObserver;
@@ -2559,11 +2558,26 @@ declare class Session {
2559
2558
  * The catalog a model/task-mode edit is checked against — the same
2560
2559
  * discovered models and manifest modes the per-turn catalog block shows the
2561
2560
  * planner, so a refusal here can never name something invalid that the
2562
- * planner was never told about. `modelsCache` is read live, not filtered by
2563
- * the allowlist here — {@link checkModelAndModeValidity} narrows by
2561
+ * planner was never told about. The catalog is not filtered by the
2562
+ * allowlist here — {@link checkModelAndModeValidity} narrows by
2564
2563
  * allowlist itself, the same way `coerceAssignments` does.
2565
2564
  */
2566
2565
  private editCatalog;
2566
+ /**
2567
+ * The allowlist in force right now. Unset means no restriction — falling
2568
+ * back to the one planning started under would keep a restriction the user
2569
+ * has since cleared.
2570
+ */
2571
+ private allowlist;
2572
+ /**
2573
+ * The discovered catalog as the resolver holds it now, per runner, with this
2574
+ * session's own discovery as the fallback where the resolver has nothing
2575
+ * cached. The resolver's cache outlives this session's snapshot in both
2576
+ * directions — an allowlist picker re-discovers into it mid-session — and a
2577
+ * model allowed after that must reach the planner with its real label and
2578
+ * variants, not as an id-only stub. Never triggers discovery itself.
2579
+ */
2580
+ private models;
2567
2581
  get planState(): LegacyPlanState | null;
2568
2582
  /**
2569
2583
  * The live plan in the shape a saved session is read back as. The disk
@@ -2643,7 +2657,7 @@ declare class Session {
2643
2657
  *
2644
2658
  * Built from the allowlist-filtered view (`filterModelsForPrompt`), the same
2645
2659
  * one the system prompt used — a restricted allowlist stays a hard bound on
2646
- * every turn, not just the first. `this.modelsCache` itself is never
2660
+ * every turn, not just the first. {@link models} itself is never
2647
2661
  * filtered: `coerceAssignments` needs the full discovered catalog alongside
2648
2662
  * the allowlist to resolve labels and clamp effort to real variants.
2649
2663
  *
package/dist/index.d.ts CHANGED
@@ -2492,7 +2492,6 @@ declare class Session {
2492
2492
  private approvalPolicy;
2493
2493
  private fetcher;
2494
2494
  private settingsFn;
2495
- private currentAllowlist;
2496
2495
  /** Last discovered model catalog — lets sync plan commits clamp thinking efforts to real variants. */
2497
2496
  private modelsCache;
2498
2497
  private unsubObserver;
@@ -2559,11 +2558,26 @@ declare class Session {
2559
2558
  * The catalog a model/task-mode edit is checked against — the same
2560
2559
  * discovered models and manifest modes the per-turn catalog block shows the
2561
2560
  * planner, so a refusal here can never name something invalid that the
2562
- * planner was never told about. `modelsCache` is read live, not filtered by
2563
- * the allowlist here — {@link checkModelAndModeValidity} narrows by
2561
+ * planner was never told about. The catalog is not filtered by the
2562
+ * allowlist here — {@link checkModelAndModeValidity} narrows by
2564
2563
  * allowlist itself, the same way `coerceAssignments` does.
2565
2564
  */
2566
2565
  private editCatalog;
2566
+ /**
2567
+ * The allowlist in force right now. Unset means no restriction — falling
2568
+ * back to the one planning started under would keep a restriction the user
2569
+ * has since cleared.
2570
+ */
2571
+ private allowlist;
2572
+ /**
2573
+ * The discovered catalog as the resolver holds it now, per runner, with this
2574
+ * session's own discovery as the fallback where the resolver has nothing
2575
+ * cached. The resolver's cache outlives this session's snapshot in both
2576
+ * directions — an allowlist picker re-discovers into it mid-session — and a
2577
+ * model allowed after that must reach the planner with its real label and
2578
+ * variants, not as an id-only stub. Never triggers discovery itself.
2579
+ */
2580
+ private models;
2567
2581
  get planState(): LegacyPlanState | null;
2568
2582
  /**
2569
2583
  * The live plan in the shape a saved session is read back as. The disk
@@ -2643,7 +2657,7 @@ declare class Session {
2643
2657
  *
2644
2658
  * Built from the allowlist-filtered view (`filterModelsForPrompt`), the same
2645
2659
  * one the system prompt used — a restricted allowlist stays a hard bound on
2646
- * every turn, not just the first. `this.modelsCache` itself is never
2660
+ * every turn, not just the first. {@link models} itself is never
2647
2661
  * filtered: `coerceAssignments` needs the full discovered catalog alongside
2648
2662
  * the allowlist to resolve labels and clamp effort to real variants.
2649
2663
  *