@ordewell/core 0.12.0 → 0.12.1
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.
- package/dist/{ModeResolver-CHsaoV7M.d.ts → ModeResolver-B64aUZXJ.d.ts} +1 -1
- package/dist/{ModeResolver-b_7bPlBS.d.mts → ModeResolver-CA2fUU9h.d.mts} +1 -1
- package/dist/{Task-BTEH-ztX.d.mts → Task-CxGgN6I0.d.mts} +503 -16
- package/dist/{Task-BTEH-ztX.d.ts → Task-CxGgN6I0.d.ts} +503 -16
- package/dist/{chunk-BKTDYGIP.mjs → chunk-2IFKPYPO.mjs} +441 -17
- package/dist/chunk-2IFKPYPO.mjs.map +1 -0
- package/dist/{chunk-BFLVOYNR.mjs → chunk-FX33UKAD.mjs} +8 -6
- package/dist/chunk-FX33UKAD.mjs.map +1 -0
- package/dist/{chunk-F6WS3JLQ.mjs → chunk-PKJTN2PD.mjs} +20 -11
- package/dist/chunk-PKJTN2PD.mjs.map +1 -0
- package/dist/{chunk-HP2LNKST.mjs → chunk-RZ23BMVR.mjs} +345 -134
- package/dist/chunk-RZ23BMVR.mjs.map +1 -0
- package/dist/chunk-UDUATSCJ.mjs +48 -0
- package/dist/chunk-UDUATSCJ.mjs.map +1 -0
- package/dist/{IRunner-BwzyUVIL.d.mts → eventStore-CTCSKS9E.d.ts} +916 -129
- package/dist/{IRunner-DjJkYwko.d.ts → eventStore-CcB8yELZ.d.mts} +916 -129
- package/dist/index.d.mts +677 -97
- package/dist/index.d.ts +677 -97
- package/dist/index.js +8233 -2450
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6951 -1772
- package/dist/index.mjs.map +1 -1
- package/dist/parsing.d.mts +2 -2
- package/dist/parsing.d.ts +2 -2
- package/dist/parsing.js +277 -21
- package/dist/parsing.js.map +1 -1
- package/dist/parsing.mjs +3 -3
- package/dist/plan-utils.d.mts +8 -5
- package/dist/plan-utils.d.ts +8 -5
- package/dist/plan-utils.js +129 -16
- package/dist/plan-utils.js.map +1 -1
- package/dist/plan-utils.mjs +17 -3
- package/dist/{runSettingsText-x-YML2ay.d.mts → runSettingsText-DFVpe6aU.d.mts} +1142 -934
- package/dist/{runSettingsText-CvZ40IPv.d.ts → runSettingsText-lKLDsyli.d.ts} +1142 -934
- package/dist/testing.d.mts +83 -4
- package/dist/testing.d.ts +83 -4
- package/dist/testing.js +142 -1
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +126 -2
- package/dist/testing.mjs.map +1 -1
- package/docker/task.Dockerfile +22 -0
- package/package.json +2 -1
- package/skills/diagnose/SKILL.md +2 -2
- package/skills/explore/SKILL.md +1 -1
- package/dist/chunk-BFLVOYNR.mjs.map +0 -1
- package/dist/chunk-BKTDYGIP.mjs.map +0 -1
- package/dist/chunk-F6WS3JLQ.mjs.map +0 -1
- package/dist/chunk-HP2LNKST.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/models/ScriptTask.ts","../src/models/Loop.ts","../src/models/lineBreaks.ts","../src/services/JsonExtractor.ts","../src/services/ModeResolver.ts","../src/services/ModelAllowlistResolver.ts","../src/services/Mandate.ts","../src/services/TaskAssignment.ts","../src/models/Delegation.ts","../src/services/PlannedTask.ts"],"sourcesContent":["import { flattenTasks, type Task } from './Task';\n\n/*\n * A script task (ADR-0035): an ops task whose body is a literal script\n * Ordewell runs with no model. What it runs is the body as the plan holds it,\n * and that body is what the user consents to.\n */\n\n/** A script task's time limit when it sets none. */\nexport const DEFAULT_SCRIPT_TIMEOUT_MS = 10 * 60_000;\n\n/**\n * The longest limit a script task may set. A timer past about 24.8 days fires\n * at once, and a day is already far past any exact effect.\n */\nexport const MAX_SCRIPT_TIMEOUT_MS = 24 * 60 * 60_000;\n\n/** What a script task runs, its time limit filled in. */\nexport type ScriptBody =\n /** Argument vectors run in order with no shell, stopping at the first that fails. */\n | { commands: string[][]; timeoutMs: number }\n /** One script, run by the research shell's interpreter. */\n | { script: string; timeoutMs: number };\n\n/** The fields that make up a script task's body: what consent is given to. */\nexport const SCRIPT_BODY_FIELDS = ['commands', 'script', 'timeoutMs'] as const satisfies readonly (keyof Task)[];\n\n/**\n * What a script task does not have: it runs no model, so it has no runner,\n * model, mode or prompt, no skills or steps, and it is an ops task by nature.\n */\nexport const NOT_A_SCRIPTS_FIELDS = ['assignedModel', 'taskMode', 'prompt', 'skills', 'userSteps', 'ops'] as const satisfies readonly (keyof Task)[];\n\ntype BodyFields = Pick<Task, 'type' | 'commands' | 'script' | 'timeoutMs'>;\n\n/** The body a script task runs; null for any other task, or one whose body the plan's rules refuse. */\nexport function scriptBodyOf(task: BodyFields): ScriptBody | null {\n if (task.type !== 'script' || scriptBodyErrors(task).length > 0) return null;\n const timeoutMs = task.timeoutMs ?? DEFAULT_SCRIPT_TIMEOUT_MS;\n return task.commands ? { commands: task.commands.map((argv) => [...argv]), timeoutMs } : { script: task.script ?? '', timeoutMs };\n}\n\n/** Whether two versions of a task run the same body under the same limit; a task that is no script task has none. */\nexport function sameScriptBody(a: BodyFields, b: BodyFields): boolean {\n return JSON.stringify(bodyKey(a)) === JSON.stringify(bodyKey(b));\n}\n\n/**\n * The tasks an edit gave another script body or limit, a script made another\n * type of task among them. Consent is to a body, so each leaves the approved\n * set: a yes to a literal script is no yes to a prompt a model interprets. A\n * task new to the plan was never in it.\n */\nexport function rewrittenScripts(before: readonly Task[], after: readonly Task[]): string[] {\n const prior = new Map(flattenTasks(before).map((t) => [t.id, t]));\n return flattenTasks(after).filter((t) => {\n const was = prior.get(t.id);\n return was !== undefined && (t.type === 'script' || was.type === 'script') && !sameScriptBody(was, t);\n }).map((t) => t.id);\n}\n\nfunction bodyKey(task: BodyFields): unknown {\n return task.type === 'script' ? [task.commands ?? null, task.script ?? null, task.timeoutMs ?? DEFAULT_SCRIPT_TIMEOUT_MS] : null;\n}\n\n/**\n * Why a task's body fields break the plan's rules, as values the planner's\n * JSON may have put there: a script task runs exactly one of `commands` or\n * `script`, every argument vector names a program, and the limit is a whole\n * number of milliseconds in range. A task of another type has none of them.\n * Read defensively, since an edit's fields arrive untyped.\n */\nexport function scriptBodyErrors(task: { type: unknown; commands?: unknown; script?: unknown; timeoutMs?: unknown }): { field: string; message: string }[] {\n if (task.type !== 'script') {\n return SCRIPT_BODY_FIELDS.filter((f) => task[f] !== undefined)\n .map((field) => ({ field, message: `has \"${field}\", which only a script task has: set \"type\": \"script\", or leave it out` }));\n }\n const errors: { field: string; message: string }[] = [];\n const { commands, script, timeoutMs } = task;\n if (commands !== undefined && script !== undefined) {\n errors.push({ field: 'commands', message: 'has both \"commands\" and \"script\": a script task runs exactly one of them' });\n } else if (commands === undefined && script === undefined) {\n errors.push({ field: 'commands', message: 'is a script task with neither \"commands\" nor \"script\": give it the argument vectors to run, or the script' });\n }\n if (commands !== undefined) errors.push(...commandsErrors(commands));\n if (script !== undefined && (typeof script !== 'string' || !script.trim())) {\n errors.push({ field: 'script', message: 'has an empty \"script\": write the script it runs' });\n }\n if (timeoutMs !== undefined && !(typeof timeoutMs === 'number' && Number.isInteger(timeoutMs) && timeoutMs > 0 && timeoutMs <= MAX_SCRIPT_TIMEOUT_MS)) {\n errors.push({ field: 'timeoutMs', message: `has \"timeoutMs\" ${JSON.stringify(timeoutMs)}: the time limit is a whole number of milliseconds from 1 to ${MAX_SCRIPT_TIMEOUT_MS}, or left out for ten minutes` });\n }\n return errors;\n}\n\nfunction commandsErrors(commands: unknown): { field: string; message: string }[] {\n const shape = 'a list of argument vectors, each a list of strings, like [[\"git\", \"push\", \"origin\", \"main\"]]';\n if (!Array.isArray(commands) || commands.length === 0) return [{ field: 'commands', message: `has \"commands\" that is not ${shape}` }];\n for (const [i, argv] of commands.entries()) {\n const n = i + 1;\n if (!Array.isArray(argv) || !argv.every((word) => typeof word === 'string')) {\n return [{ field: 'commands', message: `has command ${n} that is not an argument vector: \"commands\" is ${shape}` }];\n }\n if (argv.length === 0) return [{ field: 'commands', message: `has command ${n} as an empty argument vector: name the program it runs` }];\n if (!argv[0].trim()) return [{ field: 'commands', message: `has command ${n} naming no program: its first word is the program it runs` }];\n }\n return [];\n}\n\n/** The fields a script task has that it must not, by name. */\nexport function notAScriptsFields(task: Partial<Record<(typeof NOT_A_SCRIPTS_FIELDS)[number], unknown>>): string[] {\n return NOT_A_SCRIPTS_FIELDS.filter((f) => {\n const value = task[f];\n return value !== undefined && value !== false && !(Array.isArray(value) && value.length === 0);\n });\n}\n\n/** An edit's body fields, with a `null` the planner's JSON wrote to drop one read as leaving it out. */\nexport function clearedBodyFields(changes: Partial<Task>): Partial<Task> {\n for (const field of SCRIPT_BODY_FIELDS) if ((changes[field] as unknown) === null) changes[field] = undefined;\n return changes;\n}\n\nconst PLAIN_WORD = /^[A-Za-z0-9_@%+=:,./-]+$/;\n\n/**\n * A character a reader cannot see for what it is: a control or format\n * character (a bidirectional override among them), or a line or paragraph\n * separator. Shown as itself, it could make the text read as something other\n * than what runs.\n */\nconst UNSEEN = /[\\p{Cc}\\p{Cf}\\p{Zl}\\p{Zp}]/u;\n\n/**\n * An argument vector as a reader would type it in a shell: a word is quoted\n * only where it needs to be, and one holding a character a reader cannot see\n * is written with escapes (`$'…'`), so a command is always one line and reads\n * as what runs. For reading only; nothing runs it.\n */\nexport function commandLine(argv: readonly string[]): string {\n return argv.map(quotedWord).join(' ');\n}\n\nfunction quotedWord(word: string): string {\n if (PLAIN_WORD.test(word)) return word;\n if (!UNSEEN.test(word)) return `'${word.replace(/'/g, `'\\\\''`)}'`;\n return `$'${[...word].map(escaped).join('')}'`;\n}\n\nconst ESCAPES: Record<string, string> = { '\\\\': '\\\\\\\\', \"'\": \"\\\\'\", '\\n': '\\\\n', '\\r': '\\\\r', '\\t': '\\\\t' };\n\nfunction escaped(char: string): string {\n return ESCAPES[char] ?? (UNSEEN.test(char) ? codeOf(char) : char);\n}\n\nfunction codeOf(char: string): string {\n const code = char.codePointAt(0) ?? 0;\n const hex = code.toString(16).toUpperCase();\n return code <= 0xff ? `\\\\x${hex.padStart(2, '0')}` : code <= 0xffff ? `\\\\u${hex.padStart(4, '0')}` : `\\\\U${hex.padStart(8, '0')}`;\n}\n\n/**\n * A script task's body as the approval card shows it (ADR-0035), so the\n * consent is to what will run: each command on a line of its own, or the\n * script as written, then the time limit. A character a reader cannot see in\n * a script, but for its line breaks and tabs, is shown as its code.\n */\nexport function scriptBodyText(body: ScriptBody): string {\n const shown = 'commands' in body\n ? body.commands.map(commandLine)\n : [body.script.replace(/\\r\\n|[\\p{Cc}\\p{Cf}\\p{Zl}\\p{Zp}]/gu, (char) => (char === '\\r\\n' || char === '\\n' || char === '\\t'\n ? char\n : `<U+${(char.codePointAt(0) ?? 0).toString(16).toUpperCase().padStart(4, '0')}>`))];\n return [...shown, '', `Time limit: ${timeLimitText(body.timeoutMs)}.`].join('\\n');\n}\n\n/**\n * A script task as a row shows it: the body {@link scriptBodyText} gives the\n * approval card, so what the user read when consenting is what the plan lists.\n * A task whose body the plan's rules refuse says so rather than showing nothing.\n */\nexport function scriptTaskText(task: BodyFields): string {\n const body = scriptBodyOf(task);\n return body ? scriptBodyText(body) : 'This script task has no valid body, so it cannot run.';\n}\n\n/** A time limit in the largest units it is a whole number of: \"10 minutes\", \"90 seconds\". */\nexport function timeLimitText(ms: number): string {\n const units: [number, string][] = [[3_600_000, 'hour'], [60_000, 'minute'], [1_000, 'second'], [1, 'millisecond']];\n const [size, name] = units.find(([unit]) => ms % unit === 0) ?? units[units.length - 1];\n const n = ms / size;\n return `${n} ${name}${n === 1 ? '' : 's'}`;\n}\n","import { flattenTasksWithParents, type Task } from './Task';\n\n/*\n * A loop (ADR-0045): a check that repeats with its fix until it passes. The\n * loop is declared on its check, and its body is the top-level tasks that fix\n * what the check finds. Ordewell runs the rounds itself: the check, and while\n * it fails with rounds left, the body and then the check again. Nothing here\n * is stored but the loop and the round the check is in; whether a check is\n * between rounds is read from its status and verdict, as a block is.\n */\n\n/** How many times a loop's check runs when the loop sets no `maxRounds`. */\nexport const DEFAULT_LOOP_ROUNDS = 3;\n\n/** The most rounds a loop may set: past it, the fix is not converging, and a person should look. */\nexport const MAX_LOOP_ROUNDS = 10;\n\nexport interface TaskLoop {\n /** The top-level tasks, by id, that run to fix what the check found. */\n body: string[];\n /** The most times the check runs in one set of rounds. */\n maxRounds: number;\n}\n\n/** What the loop rules read of a task; structural, so a surface's own task shape answers them too. */\nexport interface LoopSubject {\n id: string;\n status: string;\n loop?: TaskLoop;\n /** The round of the check's latest run; absent is round 1. */\n loopRound?: number;\n verdict?: { outcome: string; reported?: string };\n}\n\n/** The round of a check's latest run, or the one it is running. */\nexport function loopRoundOf(check: Pick<LoopSubject, 'loopRound'>): number {\n return check.loopRound ?? 1;\n}\n\n/**\n * The check ran and found the work wanting (ADR-0045 L2): the runner reported\n * `failed`, or a script that ran exited non-zero or ran out of time. A check\n * that could not run — `blocked`, a runner that exited without reporting, a\n * script that never started — found nothing for a fix to answer.\n */\nfunction foundWanting(check: LoopSubject): boolean {\n return check.verdict?.outcome === 'fail' && check.verdict.reported === 'failed';\n}\n\n/**\n * A check between rounds (ADR-0045 L3): it found the work wanting with rounds\n * left, so its body is fixing what it found and it runs again once the fix\n * has landed. Its stored status stays `failed`; this is what keeps that from\n * counting as a failure.\n */\nexport function betweenRounds(check: LoopSubject): boolean {\n return !!check.loop && check.status === 'failed' && foundWanting(check) && loopRoundOf(check) < check.loop.maxRounds;\n}\n\n/** A check that found the work wanting in its last round: the loop is over, and the check failed. */\nexport function outOfRounds(check: LoopSubject): boolean {\n return !!check.loop && check.status === 'failed' && foundWanting(check) && loopRoundOf(check) >= check.loop.maxRounds;\n}\n\n/**\n * A check whose loop is over: it passed, it was skipped, or it found the work\n * wanting in its last round. Anything else — not run yet, at work, between\n * rounds, or a run that could not check — leaves its rounds to come.\n */\nexport function loopEnded(check: LoopSubject): boolean {\n return check.status === 'completed' || check.status === 'skipped' || outOfRounds(check);\n}\n\n/** The check whose loop has `taskId` in its body, if any. */\nexport function checkOf<T extends Pick<LoopSubject, 'loop'>>(tasks: readonly T[], taskId: string): T | undefined {\n return tasks.find((t) => t.loop?.body.includes(taskId));\n}\n\n/** {@link checkOf} for a whole plan at once: each body task's check, the first that holds it. */\nexport function checksOfBodies<T extends Pick<LoopSubject, 'loop'>>(tasks: readonly T[]): Map<string, T> {\n const checks = new Map<string, T>();\n for (const task of tasks) {\n for (const id of task.loop?.body ?? []) if (!checks.has(id)) checks.set(id, task);\n }\n return checks;\n}\n\n/** Whether a task is a loop's check or in a loop's body. */\nexport function inLoop(tasks: readonly Pick<LoopSubject, 'id' | 'loop'>[], task: Pick<LoopSubject, 'id' | 'loop'>): boolean {\n return !!task.loop || checkOf(tasks, task.id) !== undefined;\n}\n\nconst SHAPE = 'is not {\"body\": [\"<task id>\", ...], \"maxRounds\"?: <rounds>}';\n\nfunction roundsMessage(value: unknown): string {\n return `has \"maxRounds\" ${JSON.stringify(value)}: a loop runs its check from 1 to ${MAX_LOOP_ROUNDS} times, or ${DEFAULT_LOOP_ROUNDS} when it is left out`;\n}\n\nfunction isRoundCount(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value >= 1 && value <= MAX_LOOP_ROUNDS;\n}\n\n/**\n * A loop as a planner's or a surface's JSON wrote it, read defensively: an\n * absent or `null` loop is none, which is how an edit drops one, and an\n * absent `maxRounds` is {@link DEFAULT_LOOP_ROUNDS}. The body's entries are\n * references as written, for the caller to resolve. `error` completes a\n * sentence that names the task.\n */\nexport function loopSpec(value: unknown): { loop: TaskLoop | undefined } | { error: string } {\n if (value === undefined || value === null) return { loop: undefined };\n if (typeof value !== 'object' || Array.isArray(value)) return { error: `has a \"loop\" that ${SHAPE}` };\n const { body, maxRounds } = value as Record<string, unknown>;\n if (!Array.isArray(body) || !body.every((id) => typeof id === 'string' || typeof id === 'number')) return { error: `has a \"loop\" whose \"body\" ${SHAPE}` };\n if (body.length === 0) return { error: 'has a \"loop\" with an empty \"body\": name the tasks that fix what it finds' };\n if (maxRounds !== undefined && !isRoundCount(maxRounds)) return { error: roundsMessage(maxRounds) };\n return { loop: { body: body.map(String), maxRounds: maxRounds ?? DEFAULT_LOOP_ROUNDS } };\n}\n\n/** One rule a plan's loops break, pinned to the task it is about. */\nexport interface LoopError {\n taskId: string;\n field: 'loop' | 'dependencies';\n message: string;\n}\n\n/**\n * The rules a plan's loops are held to (ADR-0045 L1), whoever wrote them.\n * They keep the graph a loop runs on acyclic and its body for its check\n * alone: the check is a top-level AI or script task, the body is top-level\n * AI or script tasks of one loop only, none of them a check, each depending\n * on the check and otherwise only on what the check depends on or on each\n * other, and nothing outside the loop depends on the body. No task in a loop\n * has subtasks, since a round runs each task again whole.\n */\nexport function loopErrors(tasks: readonly Task[]): LoopError[] {\n const rows = flattenTasksWithParents(tasks);\n const byId = new Map(rows.map((row) => [row.task.id, row]));\n const errors: LoopError[] = [];\n const bodyOwner = new Map<string, Task>();\n\n for (const { task: check, parent } of rows) {\n const loop = check.loop;\n if (!loop) continue;\n const where = parent ? `subtask \"${check.title}\" of \"${parent.title}\"` : `Task \"${check.title}\"`;\n const fail = (message: string) => errors.push({ taskId: check.id, field: 'loop', message: `${where} ${message}` });\n if (parent) fail('has a \"loop\", but only a top-level task can be a loop\\'s check');\n if (check.type === 'user') fail('is a manual task, so it cannot be a loop\\'s check: a check is an AI task, which reports through task_complete, or a script task, whose exit status decides');\n if (check.type === 'delegated') fail('is a delegated task, so it cannot be a loop\\'s check: a round would start a new child on what is left of its budget. Add a check that depends on it, and put the loop on that');\n if (check.subtasks?.length) fail('is a loop\\'s check, which has no subtasks: each round runs it again whole');\n if (!isRoundCount(loop.maxRounds)) fail(roundsMessage(loop.maxRounds));\n if (!Array.isArray(loop.body) || loop.body.length === 0) fail('has a \"loop\" with an empty \"body\": name the tasks that fix what it finds');\n const named = new Set<string>();\n for (const id of loop.body ?? []) {\n const row = byId.get(id);\n if (named.has(id)) { fail(`names \"${row?.task.title ?? id}\" twice in its loop's \"body\"`); continue; }\n named.add(id);\n if (!row) { fail(`names \"${id}\" in its loop's \"body\", which is no task in the plan`); continue; }\n const body = row.task;\n if (body.id === check.id) { fail('names itself in its loop\\'s \"body\": the body is the tasks that fix what it finds'); continue; }\n if (row.parent) { fail(`names subtask \"${body.title}\" of \"${row.parent.title}\" in its loop's \"body\": only a top-level task can be in a loop's body`); continue; }\n const other = bodyOwner.get(id);\n if (other) { fail(`names \"${body.title}\" in its loop's \"body\", which is in the body of \"${other.title}\"'s loop too: a task belongs to one loop only`); continue; }\n bodyOwner.set(id, check);\n if (body.loop) fail(`names \"${body.title}\" in its loop's \"body\", which has a loop of its own: a loop has no loop inside its body`);\n if (body.type === 'user') fail(`names manual task \"${body.title}\" in its loop's \"body\": a body is AI or script tasks, which Ordewell runs again each round`);\n if (body.type === 'delegated') fail(`names delegated task \"${body.title}\" in its loop's \"body\": a round would start a new child on what is left of its budget`);\n if (body.subtasks?.length) fail(`names \"${body.title}\" in its loop's \"body\", which has subtasks: each round runs a body task again whole, so make each step a task of the body`);\n }\n }\n\n for (const [bodyId, check] of bodyOwner) {\n const body = byId.get(bodyId)!.task;\n const where = `Task \"${body.title}\" is in the body of \"${check.title}\"'s loop`;\n if (!body.dependencies.includes(check.id)) {\n errors.push({ taskId: body.id, field: 'dependencies', message: `${where}, so it depends on \"${check.title}\": the check's report is what it fixes. Add \"${check.title}\" to its dependencies` });\n }\n for (const dep of body.dependencies) {\n if (dep === check.id || check.dependencies.includes(dep) || bodyOwner.get(dep) === check) continue;\n errors.push({ taskId: body.id, field: 'dependencies', message: `${where}, so it depends only on \"${check.title}\", on what \"${check.title}\" depends on, or on other tasks of that body; \"${byId.get(dep)?.task.title ?? dep}\" is none of these` });\n }\n }\n\n for (const { task } of rows) {\n for (const dep of task.dependencies) {\n const check = bodyOwner.get(dep);\n if (!check || bodyOwner.get(task.id) === check) continue;\n const body = byId.get(dep)!.task;\n const message = task.id === check.id\n ? `Task \"${task.title}\" depends on \"${body.title}\" from its own loop's body: the body runs after the check, so the check cannot wait for it`\n : `Task \"${task.title}\" depends on \"${body.title}\", which is in the body of \"${check.title}\"'s loop and runs only if \"${check.title}\" fails: depend on \"${check.title}\" instead`;\n errors.push({ taskId: task.id, field: 'dependencies', message });\n }\n }\n return errors;\n}\n\n/**\n * Why a task may not be removed while it is a loop's check: its body would\n * be left as tasks that run whatever happens. Removing a body task takes it\n * out of its loop instead (ADR-0045 L8). Null when the removal may go ahead.\n */\nexport function loopRemovalRefusal(task: Pick<Task, 'title' | 'loop'>): string | null {\n return task.loop ? `\"${task.title}\" is a loop's check: remove its body tasks first, or drop its loop (\"loop\": null), so they do not run on their own` : null;\n}\n\n/** Why tasks in a loop may not be merged or split: a round runs its check and each body task again as they are (ADR-0045 L8). */\nexport function loopReshapeRefusal(tasks: readonly Pick<LoopSubject, 'id' | 'loop'>[], target: Pick<Task, 'id' | 'title' | 'loop' | 'type'>, action: 'merged' | 'split'): string | null {\n // A merge or a split makes tasks of another type, and that would lose its goal and budget (ADR-0055 D1).\n if (target.type === 'delegated') return `\"${target.title}\" is a delegated task and cannot be ${action}: remove it and add what should replace it`;\n if (target.loop) return `\"${target.title}\" is a loop's check and cannot be ${action}: drop its loop first (\"loop\": null)`;\n return checkOf(tasks, target.id) ? `\"${target.title}\" is in a loop's body and cannot be ${action}: take it out of the loop first` : null;\n}\n","/*\n * What counts as a line break wherever text an author or a branch chose meets\n * a line of Ordewell's (ADR-0057 R3): every one git or a terminal would honour,\n * not only `\\n`. One set, so what is split, quoted and refused cannot differ.\n */\nconst BREAKS = '\\\\n\\\\v\\\\f\\\\r\\\\u0085\\\\u2028\\\\u2029';\nconst LINE_BREAK = new RegExp(`\\\\r\\\\n|[${BREAKS}]`);\n\n/** Text of one line: what a schema refuses anything else by. */\nexport const ONE_LINE = new RegExp(`^[^${BREAKS}]*$`);\n\nexport function splitLines(text: string): string[] {\n return text.split(LINE_BREAK);\n}\n\n/** A quoted value, which stays one line: JSON leaves these three as they are. */\nexport function quotedLine(text: string): string {\n return JSON.stringify(text).replace(/[\\u0085\\u2028\\u2029]/g, (char) => `\\\\u${char.charCodeAt(0).toString(16).padStart(4, '0')}`);\n}\n\n/** A name or a path on a line of Ordewell's: as it stands, or quoted where it would break that line. */\nexport function onOneLine(text: string): string {\n return ONE_LINE.test(text) ? text : quotedLine(text);\n}\n","/** The envelope key a full plan reply is keyed by: `{\"tasks\":[...]}`. */\nexport const PLAN_ENVELOPE_KEY = 'tasks';\n/** The envelope key a targeted-edits reply is keyed by: `{\"taskOps\":[...]}`. */\nexport const TASK_OPS_ENVELOPE_KEY = 'taskOps';\n/** The envelope key a read-only detail request is keyed by: `{\"taskQuery\":{...}}`. */\nexport const TASK_QUERY_ENVELOPE_KEY = 'taskQuery';\n\n/** Thrown when an LLM plan response cannot be parsed into a valid plan. Carries the raw text so callers can log it or retry. */\nexport class PlanParseError extends Error {\n readonly raw: string;\n /**\n * True when the reply was cut off mid-object (output-token limit) rather\n * than malformed — the two need different repairs: a truncated emission will\n * be cut at the same point again unless the retry frees context or asks for\n * terser output.\n */\n readonly truncated: boolean;\n /**\n * True when the JSON parsed fine and a *shape* rule rejected it. The generic\n * \"could not be parsed as JSON\" corrective is a lie for these, so the model\n * re-sends the same object; a semantic rejection must be repaired by naming\n * the rule it broke.\n */\n readonly semantic: boolean;\n constructor(message: string, raw: string, opts?: { truncated?: boolean; semantic?: boolean }) {\n super(message);\n this.name = 'PlanParseError';\n this.raw = raw;\n this.truncated = opts?.truncated ?? false;\n this.semantic = opts?.semantic ?? false;\n }\n}\n/**\n * Strip the noise reasoning models wrap around their answer: markdown code\n * fences and `<think>…</think>` chain-of-thought blocks (which routinely contain\n * stray braces that would otherwise derail brace-balancing). Reasoning captured\n * out-of-band by the service never reaches here, but a model that inlines its\n * thinking in the content channel still must not corrupt parsing.\n */\nexport function stripModelNoise(raw: string): string {\n return raw\n .replace(/<think>[\\s\\S]*?<\\/think>/gi, '')\n .replace(/```json\\s*/gi, '')\n .replace(/```\\s*/g, '')\n .trim();\n}\n\nconst THINK_OPEN = '<think>';\nconst THINK_CLOSE = '</think>';\nconst FENCE = '```';\nconst FENCE_JSON_TAG = 'json';\n\n/**\n * Whether a reply that begins with `prefix` opens with a JSON object once the\n * noise {@link stripModelNoise} removes is skipped — the streaming counterpart\n * of it, answering from the start of a reply that has not finished arriving.\n * Undefined while the prefix cannot tell yet: blank, inside an unclosed think\n * block, or partway through a fence or a tag.\n */\nexport function opensWithJsonObject(prefix: string): boolean | undefined {\n let rest = prefix;\n for (;;) {\n rest = rest.trimStart();\n if (!rest) return undefined;\n const head = rest.slice(0, THINK_OPEN.length).toLowerCase();\n if (head === THINK_OPEN) {\n const close = rest.toLowerCase().indexOf(THINK_CLOSE);\n if (close < 0) return undefined;\n rest = rest.slice(close + THINK_CLOSE.length);\n continue;\n }\n if (rest.startsWith(FENCE)) {\n rest = rest.slice(FENCE.length);\n const tag = rest.slice(0, FENCE_JSON_TAG.length).toLowerCase();\n if (tag === FENCE_JSON_TAG) rest = rest.slice(FENCE_JSON_TAG.length);\n else if (tag === rest.toLowerCase() && FENCE_JSON_TAG.startsWith(tag)) return undefined;\n continue;\n }\n if (THINK_OPEN.startsWith(head) || FENCE.startsWith(rest)) return undefined;\n return rest.startsWith('{');\n }\n}\n\n/**\n * Scan from `start` (which must point at a `{`) for the matching balanced close,\n * ignoring braces inside strings. Returns the object substring and whether it was\n * balanced; an unbalanced result means the input was truncated mid-object.\n */\nfunction balancedObjectAt(text: string, start: number): { json: string; balanced: boolean } {\n let depth = 0;\n let inString = false;\n let escaped = false;\n for (let i = start; i < text.length; i++) {\n const ch = text[i];\n if (inString) {\n if (escaped) escaped = false;\n else if (ch === '\\\\') escaped = true;\n else if (ch === '\"') inString = false;\n continue;\n }\n if (ch === '\"') inString = true;\n else if (ch === '{') depth++;\n else if (ch === '}') {\n depth--;\n if (depth === 0) return { json: text.slice(start, i + 1), balanced: true };\n }\n }\n return { json: text.slice(start), balanced: false };\n}\n\n/**\n * Scan an LLM response for every balanced `{…}` object carrying a `\"<key>\":`\n * entry. Strips fences and `<think>` blocks first. A matching object is\n * skipped over wholesale, so its nested braces don't produce fragment\n * candidates; non-matching objects are descended into, so a match wrapped in\n * an unrelated outer object is still found. `fallback` preserves the legacy\n * behavior for callers with no keyed match: the first balanced object, else\n * the stripped text so a JSON.parse error still surfaces.\n */\nexport function extractObjectsWithKey(raw: string, key: string): {\n matches: string[];\n fallback: { json: string; balanced: boolean };\n sawBrace: boolean;\n /** An object ran to EOF unclosed — the classic signature of truncated output. */\n sawUnbalanced: boolean;\n} {\n const stripped = stripModelNoise(raw);\n const keyRe = new RegExp(`\"${key}\"\\\\s*:`);\n\n const matches: string[] = [];\n let firstObject: string | null = null;\n let sawBrace = false;\n let sawUnbalanced = false;\n let inString = false;\n let escaped = false;\n for (let i = 0; i < stripped.length; i++) {\n const ch = stripped[i];\n if (inString) {\n if (escaped) escaped = false;\n else if (ch === '\\\\') escaped = true;\n else if (ch === '\"') inString = false;\n continue;\n }\n if (ch === '\"') { inString = true; continue; }\n if (ch !== '{') continue;\n\n sawBrace = true;\n const obj = balancedObjectAt(stripped, i);\n // A stray brace in a reasoning preamble produces an unbalanced candidate,\n // which we skip so it can't swallow the real object that follows.\n if (obj.balanced && keyRe.test(obj.json)) {\n matches.push(obj.json);\n i += obj.json.length - 1;\n continue;\n }\n if (!obj.balanced) sawUnbalanced = true;\n if (!firstObject && obj.balanced) firstObject = obj.json;\n }\n\n return {\n matches,\n fallback: firstObject !== null ? { json: firstObject, balanced: true } : { json: stripped, balanced: false },\n sawBrace,\n sawUnbalanced,\n };\n}\n\n/**\n * Pull the JSON object out of an LLM response and report whether it was balanced.\n * Strips fences and `<think>` blocks, then walks every top-level `{…}` and\n * returns the FIRST one that contains a `\"tasks\"` key — so a brace appearing\n * earlier in reasoning (or an unrelated preamble object) can't make us parse the\n * wrong thing. Falls back to the first balanced object and, failing that, the\n * first `{` onwards so a genuine `JSON.parse` error still surfaces.\n */\nexport function extractObjectWithBalance(raw: string): { json: string; balanced: boolean; sawBrace: boolean } {\n const { matches, fallback, sawBrace } = extractObjectsWithKey(raw, PLAN_ENVELOPE_KEY);\n if (matches.length > 0) return { json: matches[0], balanced: true, sawBrace };\n return { ...fallback, sawBrace };\n}\n\n/**\n * Pull the JSON object out of an LLM response. Strips markdown code fences and\n * `<think>` blocks, prefers the object containing a `tasks` key, and tolerates a\n * prose preamble and trailing prose. Returns the fence-stripped text unchanged\n * if no `{` is present so the caller's JSON.parse produces a clear failure.\n */\nexport function extractJsonObject(raw: string): string {\n return extractObjectWithBalance(raw).json;\n}\n\n/** Drop trailing commas before a closing `}` or `]` — a common model quirk. */\nexport function stripTrailingCommas(json: string): string {\n return json.replace(/,(\\s*[}\\]])/g, '$1');\n}\n\n/**\n * Escape raw control characters that appear INSIDE string literals — budget\n * models routinely emit multi-line `prompt` strings with literal newlines,\n * which strict JSON.parse rejects (\"bad control character\"). Characters\n * outside strings (formatting whitespace) are left untouched.\n */\nexport function escapeControlCharsInStrings(json: string): string {\n let out = '';\n let inString = false;\n let escaped = false;\n for (const ch of json) {\n if (inString) {\n if (escaped) { out += ch; escaped = false; continue; }\n if (ch === '\\\\') { out += ch; escaped = true; continue; }\n if (ch === '\"') { out += ch; inString = false; continue; }\n if (ch === '\\n') { out += '\\\\n'; continue; }\n if (ch === '\\r') { out += '\\\\r'; continue; }\n if (ch === '\\t') { out += '\\\\t'; continue; }\n out += ch;\n continue;\n }\n if (ch === '\"') inString = true;\n out += ch;\n }\n return out;\n}\n","import { flattenTasks, type RunnerId, type Task } from '../models/Task';\n\nexport interface RunnerModeInfo {\n id: string;\n label: string;\n description: string;\n autonomous?: boolean;\n safe?: boolean;\n readOnly?: boolean;\n sandboxed?: boolean;\n /** Why this mode cannot be used on this host (a failed probe); such a mode is shown, never assigned. */\n unavailable?: string;\n}\n\n/** The slice of RunnerRegistry this module needs — structural, so nothing here depends on the manifest layer. */\nexport interface ManifestLookup {\n getManifest(runner: RunnerId): { modes?: RunnerModeInfo[] } | undefined;\n}\n\n/**\n * A runner's modes are declared only in its manifest, never through a service,\n * so every caller that needs them fuses registry and runner list by hand. This\n * is that fusion, in one place: the planner prompt, the mode pickers on each\n * surface, and the runner-change retarget all read modes the same way.\n *\n * A runner with no modes maps to `[]` rather than being dropped — callers\n * distinguish \"declares no modes\" from \"not asked about\".\n */\nexport function runnerModesFrom(registry: ManifestLookup, runners: RunnerId[]): Record<RunnerId, RunnerModeInfo[]> {\n return Object.fromEntries(runners.map((r) => [r, registry.getManifest(r)?.modes ?? []] as const));\n}\n\n/**\n * Find the mode ID a runner resolves to under the given toggle state.\n * Tag-based first (autonomous/safe); falls back to positional last non-plan\n * if no tag is present on any mode (degrades gracefully on untagged manifests).\n * Returns undefined if `modes` is empty or undefined.\n */\nexport function resolveDefaultMode(\n modes: readonly RunnerModeInfo[] | undefined,\n autonomousDefault = false,\n): string | undefined {\n if (!modes || modes.length === 0) return undefined;\n const tag: 'autonomous' | 'safe' = autonomousDefault ? 'autonomous' : 'safe';\n const tagged = modes.find((m) => m[tag]);\n if (tagged) return tagged.id;\n for (let i = modes.length - 1; i >= 0; i--) {\n if (!modes[i].readOnly && modes[i].id !== 'plan') return modes[i].id;\n }\n return undefined;\n}\n\n/** The user-facing name of the `autonomousMode` boolean's two states. */\nexport function autonomyLevelLabel(autonomous: boolean): 'Full' | 'Guarded' {\n return autonomous ? 'Full' : 'Guarded';\n}\n\n/** `full`/`guarded` name the levels; `on`/`off` and `auto` are older words for them. Null for anything else. */\nexport function parseAutonomyLevel(arg: string | undefined): boolean | null {\n switch (arg?.trim().toLowerCase()) {\n case 'full': case 'on': return true;\n case 'guarded': case 'auto': case 'off': return false;\n default: return null;\n }\n}\n\n/**\n * The level a flag or `ORDEWELL_AUTONOMOUS_MODE` names: the level names above,\n * plus the boolean spellings (`true`/`false`, `1`/`0`), case and surrounding\n * space aside. Undefined for anything else — a typo must never raise autonomy,\n * and the `.env` migration and the runtime override must read a value alike.\n */\nexport function parseAutonomyFlag(value: string | undefined): boolean | undefined {\n const normalized = value?.trim().toLowerCase();\n if (!normalized) return undefined;\n if (normalized === 'true' || normalized === '1') return true;\n if (normalized === 'false' || normalized === '0') return false;\n return parseAutonomyLevel(normalized) ?? undefined;\n}\n\n/**\n * The profile a manifest tags `readOnly` (ADR-0046) — never found by id, so a runner with no\n * tag has none. A mode this host cannot run is still the runner's read-only\n * mode: it is how a task already on it is recognized, and why a move of that\n * task is refused rather than made writable.\n */\nexport function taggedReadOnlyMode(modes: readonly RunnerModeInfo[] | undefined): string | undefined {\n return modes?.find((m) => m.readOnly)?.id;\n}\n\n/** The read-only profile a task can be given here; built-ins do not need the runner's native sandbox (ADR-0046). */\nexport function readOnlyMode(modes: readonly RunnerModeInfo[] | undefined): string | undefined {\n const mode = modes?.find((m) => m.readOnly);\n return mode && !mode.unavailable ? mode.id : undefined;\n}\n\n/** Why a mode cannot be used on this host, when it cannot. */\nexport function unavailableModeReason(modes: readonly RunnerModeInfo[] | undefined, id: string | undefined): string | undefined {\n return id === undefined ? undefined : modes?.find((m) => m.id === id)?.unavailable;\n}\n\nfunction unavailableModeError(runner: RunnerId, id: string, reason: string): string {\n return `Mode \"${id}\" of runner \"${runner}\" is unavailable on this host: ${reason}`;\n}\n\n/** What a task fails with at spawn when its planned mode is one this host cannot run; undefined when it can. */\nexport function unavailableTaskModeMessage(\n manifest: { displayName: string; modes?: readonly RunnerModeInfo[] },\n mode: string | undefined,\n): string | undefined {\n const reason = unavailableModeReason(manifest.modes, mode);\n return reason ? `Mode \"${mode}\" of ${manifest.displayName} is unavailable on this host: ${reason}` : undefined;\n}\n\n/** What the planner says about a task's mode (ADR-0031): read-only or not, and the mode the task has now, if any. */\nexport interface ModeRequest {\n readOnly?: boolean;\n current?: string;\n}\n\nexport type PlannedMode = { ok: true; mode: string | undefined } | { ok: false; error: string };\n\n/**\n * The mode a task the planner writes lands on (ADR-0031). The planner names no\n * mode: a read-only task gets its runner's read-only mode; any other keeps the\n * mode it has when the runner offers it — a mode the user picked survives an\n * edit that does not ask for a change — and otherwise gets the runner's mode\n * for the level. `readOnly: false` is the one request that moves a task off\n * its read-only mode. Undefined mode when the runner's modes are unknown.\n */\nexport function plannedMode(\n runner: RunnerId,\n runnerModes: Partial<Record<RunnerId, readonly RunnerModeInfo[]>> | undefined,\n { readOnly, current }: ModeRequest,\n autonomousDefault = false,\n): PlannedMode {\n if (!runnerModes) return { ok: true, mode: undefined };\n const modes = runnerModes[runner] ?? [];\n const readOnlyId = readOnlyMode(modes);\n if (readOnly === true) {\n if (readOnlyId) return { ok: true, mode: readOnlyId };\n const able = readOnlyRunners(runnerModes);\n const reason = unavailableModeReason(modes, taggedReadOnlyMode(modes));\n return {\n ok: false,\n error: `Runner \"${runner}\" has no read-only mode${reason ? ' available on this host' : ''}: assign a read-only task to ${able.length > 0 ? `one of: ${able.join(', ')}` : 'no runner: none of the enabled runners has one'}, or drop \"readOnly\"${reason ? `. ${reason}` : ''}`,\n };\n }\n const keep = current !== undefined && modes.some((m) => m.id === current) && !(readOnly === false && current === taggedReadOnlyMode(modes));\n const mode = keep ? current : resolveDefaultMode(modes, autonomousDefault);\n // Refused, never swapped for another mode: that would hand a task the\n // planner or user meant to be sandboxed a level of access nobody chose (ADR-0001).\n const reason = unavailableModeReason(modes, mode);\n if (mode !== undefined && reason) return { ok: false, error: unavailableModeError(runner, mode, reason) };\n return { ok: true, mode };\n}\n\n/**\n * A plan the planner restates over an existing one comes back with every mode\n * decided afresh. A restatement says read-only or not for each task, so that\n * answer stands; what it cannot say is a mode the user picked. So where a\n * task it names was planned before and is not read-only now, the earlier mode\n * is kept when its runner offers it — the rule an edit follows.\n */\nexport function carryPlannedModes(\n before: readonly Task[],\n rewrite: Task[],\n catalog: { runnerModes: Partial<Record<RunnerId, readonly RunnerModeInfo[]>>; autonomousDefault?: boolean },\n): Task[] {\n const prior = new Map(flattenTasks(before).map((t) => [t.id, t]));\n const carry = (t: Task): Task => {\n const subtasks = (t.subtasks ?? []).map(carry);\n const was = prior.get(t.id);\n if (t.type !== 'ai' || !was || was.type !== 'ai' || t.taskMode === taggedReadOnlyMode(catalog.runnerModes[t.assignedRunner])) return { ...t, subtasks };\n const mode = plannedMode(t.assignedRunner, catalog.runnerModes, { readOnly: false, current: was.taskMode }, catalog.autonomousDefault ?? false);\n return { ...t, subtasks, ...(mode.ok && mode.mode !== undefined ? { taskMode: mode.mode } : {}) };\n };\n return rewrite.map(carry);\n}\n\n/** The runners a read-only task may go to, as the planner's prompt names them. */\nexport function readOnlyRunners(runnerModes: Partial<Record<RunnerId, readonly RunnerModeInfo[]>>): RunnerId[] {\n return Object.entries(runnerModes).filter(([, ms]) => readOnlyMode(ms)).map(([id]) => id);\n}\n","import type { DiscoveredModel, RunnerId } from '../models/Task';\n\n/**\n * The ids a runner may actually run: the user's allowlist with the ids that\n * provably belong to a *different* runner dropped. `undefined` means no\n * restriction.\n *\n * Model ids are scoped to the agent that lists them, so an OpenRouter slug\n * allowlisted for Claude Code does not limit it — it points it at something it\n * cannot spawn, and the plan only dies once a task is already running. But\n * \"this runner didn't list it\" is not enough to call an id wrong: discovery can\n * be stale or return no list at all. What settles it is\n * whether *another* runner listed the id. So:\n *\n * - listed for this runner → keep;\n * - listed for no runner → unknown, and the user said it explicitly, so keep it\n * and let the runner validate last (the same call `resolveAssignment` makes);\n * - listed only for other runners → provably not this runner's, so drop it.\n *\n * When that leaves nothing, the whole allowlist was about some other runner\n * (a settings file written before a surface scoped its picker to one). No\n * restriction is the only safe reading — the alternative is handing the planner\n * a list of models that cannot run.\n */\nexport function effectiveAllowlist(\n allowlist: string[] | undefined,\n runner: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>> | undefined,\n): string[] | undefined {\n if (!allowlist || allowlist.length === 0) return undefined;\n if (!modelsByRunner) return allowlist;\n\n const own = new Set((modelsByRunner[runner] ?? []).map((m) => m.modelId));\n const elsewhere = new Set<string>();\n for (const [other, models] of Object.entries(modelsByRunner)) {\n if (other === runner) continue;\n for (const m of models ?? []) elsewhere.add(m.modelId);\n }\n\n const kept = allowlist.filter((id) => own.has(id) || !elsewhere.has(id));\n return kept.length > 0 ? kept : undefined;\n}\n\nexport function filterModelsForPrompt(\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n perRunnerAllowlist: Partial<Record<RunnerId, string[]>>,\n): Partial<Record<RunnerId, DiscoveredModel[]>> {\n const result: Partial<Record<RunnerId, DiscoveredModel[]>> = {};\n for (const [runner, models] of Object.entries(modelsByRunner)) {\n if (!models) continue;\n const allowed = effectiveAllowlist(perRunnerAllowlist[runner], runner, modelsByRunner);\n if (!allowed) {\n result[runner] = models;\n continue;\n }\n const allowedSet = new Set(allowed);\n const intersection = models.filter((m) => allowedSet.has(m.modelId));\n // A set allowlist is a hard constraint: the planner must never see models\n // outside it. An allowed id no runner has listed is one discovery doesn't\n // cover, so synthesize an entry rather than leaking the full list.\n const covered = new Set(intersection.map((m) => m.modelId));\n const missing = allowed\n .filter((id) => !covered.has(id))\n .map((id) => ({ modelId: id, modelLabel: id.split('/').pop() || id, variants: [] }));\n result[runner] = [...intersection, ...missing];\n }\n return result;\n}\n\n/** Canonical low→high ordering of the well-known effort ladder. */\nconst EFFORT_LADDER = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'ultra'];\n/** Runner-specific spellings mapped onto the ladder. */\nconst EFFORT_ALIASES: Record<string, string> = { disabled: 'none', adaptive: 'medium' };\n\n/**\n * The one rule for an effort and a model: the effort a task keeps on a model,\n * whether it was written with it or carried from the model before. Kept where\n * the model offers it; otherwise mapped to the nearest rung the model\n * supports (so a Claude-style \"xhigh\" on a low/medium/high model becomes\n * \"high\"); undefined — the runner's own default — when no mapping exists or\n * the model offers no levels, which is how a model discovery does not list\n * reads (`variants` empty). Core's resolver and every surface's model picker\n * call it, so a model change lands on the same effort wherever it is made.\n */\nexport function clampThinkingEffort(\n effort: string | undefined,\n variants: { id: string }[],\n): string | undefined {\n if (!effort) return undefined;\n if (variants.length === 0) return undefined;\n const ids = new Set(variants.map((v) => v.id));\n if (ids.has(effort)) return effort;\n const canon = EFFORT_ALIASES[effort] ?? effort;\n if (ids.has(canon)) return canon;\n const idx = EFFORT_LADDER.indexOf(canon);\n if (idx < 0) return undefined;\n for (let d = 1; d < EFFORT_LADDER.length; d++) {\n const lower = EFFORT_LADDER[idx - d];\n if (lower && ids.has(lower)) return lower;\n const higher = EFFORT_LADDER[idx + d];\n if (higher && ids.has(higher)) return higher;\n }\n return undefined;\n}\n","import type { ExecutionCommandName, SupervisorLevel } from '../models/Execution';\nimport type { RunnerId, Task } from '../models/Task';\nimport type { EffectRules } from './effectAllowlist';\n\n/**\n * The mandate (ADR-0056): what a node may do without a person, and within what\n * limits. The root's is derived on each read from today's settings and never\n * saved; a child's is one pure function of its parent's and its request, which\n * can only narrow what the parent may hand on. Authority only: capability stays\n * at the boundary a session runs in, and a prompt enforces nothing.\n */\n\nexport const GRANTS = ['observe', 'steer', 'control', 'replan', 'approve', 'delegate', 'effect', 'research', 'merge'] as const;\n\n/** Each is a set of things a node may do unasked (M2). */\nexport type Grant = (typeof GRANTS)[number];\n\n/** What a mandate could not finish without: a child holds these unasked, and `narrow` refuses one that would lack any (M2). */\nexport const FLOOR_GRANTS: readonly Grant[] = ['observe', 'steer', 'control', 'replan', 'approve', 'merge'];\n\n/** The shape of a tree, by ADR-0055 D19: refused past the hard cap, never dropped. */\nexport const SHAPE_LIMITS = {\n depth: { default: 2, hard: 4 },\n delegatedTasks: { default: 8, hard: 30 },\n tasksPerPlan: { default: 30, hard: 100 },\n} as const;\n\n/** What a child is given to run in when its task states no time (M3). */\nexport const DEFAULT_CHILD_WALL_CLOCK_MS = 24 * 60 * 60 * 1000;\n\nexport interface MandateLimits {\n /** The node's token budget; the root's is the tree's, from the delegation setting (M3, M5). */\n tokens: number;\n /** Null: no limit, which only the root has. */\n wallClockMs: number | null;\n /** How many levels may still open below this node. */\n depth: number;\n delegatedTasks: number;\n tasksPerPlan: number;\n runners: readonly RunnerId[];\n /** The models a runner is held to; a runner not named may use any it offers, as the user's allowlist reads. */\n models: Readonly<Record<RunnerId, readonly string[]>>;\n}\n\nexport interface MandateExclusions {\n protectedPaths: readonly string[];\n}\n\nexport interface Mandate {\n /** What this node may do. */\n grants: ReadonlySet<Grant>;\n /** What it may hand a child. */\n grantable: ReadonlySet<Grant>;\n /** Read in place of the global level. */\n autonomy: 'full' | 'guarded';\n limits: MandateLimits;\n /** These only accumulate. */\n exclusions: MandateExclusions;\n /** One per level, each with its own `!` rules: a command must match at every level (M4). */\n effectRules: readonly EffectRules[];\n /** The level of `effectRules` this node's own request added: all of it a node keeps, the levels above being read as they stand (M1). */\n ownEffectRules: readonly EffectRules[];\n}\n\n/** What the root's mandate is read from, each where it lives today (M1). */\nexport interface RootSettings {\n /** The run's own copy: where a guard or a failure lowers it, and the user's change lands. */\n level: SupervisorLevel;\n autorun: boolean;\n autonomous: boolean;\n /** The tree's budget; 0 is delegation off (ADR-0055 D21). */\n delegationTokens: number;\n /** The effect allowlist, absent where nothing was read. */\n effects?: EffectRules;\n runners: readonly RunnerId[];\n models: Readonly<Record<RunnerId, readonly string[]>>;\n}\n\n/** What a delegated task asks of the mandate it is given. `grants` names what it asks for past the floor; absent asks for nothing. */\nexport interface MandateRequest {\n /** The level of the node narrowing, the root being 0: the one a refusal names. */\n level: number;\n grants?: readonly Grant[];\n autonomy?: Mandate['autonomy'];\n /** A delegated task must carry one (M5). */\n tokens?: number;\n wallClockMs?: number;\n depth?: number;\n delegatedTasks?: number;\n tasksPerPlan?: number;\n runners?: readonly RunnerId[];\n models?: Readonly<Record<RunnerId, readonly string[]>>;\n protectedPaths?: readonly string[];\n effectRules?: EffectRules;\n}\n\nexport interface MandateRefusal {\n level: number;\n field: string;\n asked: string;\n there: string;\n}\n\nexport type Narrowed = { ok: true; mandate: Mandate } | { ok: false; refusal: MandateRefusal };\n\nexport function mandateRefusalText({ level, field, asked, there }: MandateRefusal): string {\n return `Level ${level} refused ${field}: asked ${asked}, and there is ${there}.`;\n}\n\n/** By the level alone: autorun, autonomy, the effect allowlist and delegation are settings of their own (M2). */\nconst LEVEL_GRANTS: Record<SupervisorLevel, readonly Grant[]> = {\n off: ['research'],\n watch: ['observe', 'research'],\n act: ['observe', 'steer', 'control', 'replan', 'research', 'merge'],\n};\n\n/** What delegation on lets a subplanner hold, whatever the root's level: the level is what the root planner does in its own turns (M2). */\nconst DELEGATED_GRANTS: readonly Grant[] = [...FLOOR_GRANTS, 'research', 'delegate'];\n\n/**\n * The root's mandate, as it stands now (M1): built afresh on each read, so an\n * Act that a guard lowered reads Watch at the next check, and nothing saved\n * could disagree with the settings.\n */\nexport function rootMandate(settings: RootSettings): Mandate {\n const effect = (settings.effects?.rules.length ?? 0) > 0;\n const delegation = settings.delegationTokens > 0;\n const effectRules = settings.effects ? [settings.effects] : [];\n return {\n grants: new Set<Grant>([\n ...LEVEL_GRANTS[settings.level],\n ...(settings.autorun ? ['approve' as const] : []),\n ...(effect ? ['effect' as const] : []),\n ...(delegation ? ['delegate' as const] : []),\n ]),\n grantable: new Set<Grant>(delegation ? [...DELEGATED_GRANTS, ...(effect ? ['effect' as const] : [])] : []),\n autonomy: settings.autonomous ? 'full' : 'guarded',\n limits: {\n tokens: settings.delegationTokens,\n wallClockMs: null,\n depth: SHAPE_LIMITS.depth.default,\n delegatedTasks: SHAPE_LIMITS.delegatedTasks.default,\n tasksPerPlan: SHAPE_LIMITS.tasksPerPlan.default,\n runners: settings.runners,\n models: settings.models,\n },\n exclusions: { protectedPaths: [] },\n effectRules,\n ownEffectRules: effectRules,\n };\n}\n\n/**\n * What holds at a node now (M1): its saved mandate within every ancestor's\n * `grantable` as it stands, under every ancestor's effect rules as they stand,\n * so a change at the root reaches the subtree at the next check. This reading\n * intersects and refuses nothing: the floor binds {@link narrow}, which writes\n * a new child, not this.\n */\nexport function heldMandate(saved: Mandate, ancestors: readonly Mandate[]): Mandate {\n const within = (grants: ReadonlySet<Grant>) => new Set([...grants].filter((grant) => ancestors.every((ancestor) => ancestor.grantable.has(grant))));\n const effectRules = [...ancestors.flatMap((ancestor) => ancestor.effectRules), ...saved.ownEffectRules];\n return { ...saved, grants: within(saved.grants), grantable: within(saved.grantable), effectRules };\n}\n\ntype Ruled<T> = { value: T } | { refused: Omit<MandateRefusal, 'level'> };\n\ntype Rules<Of, From> = { [K in keyof Of]-?: (parent: From, request: MandateRequest) => Ruled<Of[K]> };\n\nconst listed = (grants: Iterable<Grant>): string => [...grants].sort().join(', ') || 'nothing';\n\nconst lesser = (limit: 'delegatedTasks' | 'tasksPerPlan') => (parent: MandateLimits, request: MandateRequest): Ruled<number> => {\n const { hard } = SHAPE_LIMITS[limit];\n const asked = request[limit];\n if (asked !== undefined && asked > hard) return { refused: { field: `limits.${limit}`, asked: String(asked), there: `a hard limit of ${hard}` } };\n return { value: Math.min(parent[limit], asked ?? parent[limit]) };\n};\n\nfunction intersectModels(parent: MandateLimits['models'], asked: MandateLimits['models'] = {}): MandateLimits['models'] {\n const models: Record<RunnerId, readonly string[]> = { ...asked, ...parent };\n for (const runner of Object.keys(parent)) {\n if (asked[runner]) models[runner] = parent[runner].filter((model) => asked[runner].includes(model));\n }\n return models;\n}\n\nconst LIMIT_RULES: Rules<MandateLimits, MandateLimits> = {\n tokens: ({ tokens }, { tokens: asked }) => {\n if (asked === undefined || asked <= 0 || asked > tokens) return { refused: { field: 'limits.tokens', asked: asked === undefined ? 'none' : String(asked), there: String(tokens) } };\n return { value: asked };\n },\n wallClockMs: ({ wallClockMs: left }, { wallClockMs: asked }) => {\n if (asked === undefined) return { value: left === null ? DEFAULT_CHILD_WALL_CLOCK_MS : Math.min(left, DEFAULT_CHILD_WALL_CLOCK_MS) };\n if (asked <= 0 || (left !== null && asked > left)) return { refused: { field: 'limits.wallClockMs', asked: String(asked), there: left === null ? 'no limit' : String(left) } };\n return { value: asked };\n },\n depth: ({ depth }, { depth: asked }) => {\n if (depth <= 0) return { refused: { field: 'limits.depth', asked: 'a child', there: 'no depth left' } };\n const { hard } = SHAPE_LIMITS.depth;\n if (asked !== undefined && asked > hard) return { refused: { field: 'limits.depth', asked: String(asked), there: `a hard limit of ${hard}` } };\n return { value: Math.min(depth - 1, asked ?? depth - 1) };\n },\n delegatedTasks: lesser('delegatedTasks'),\n tasksPerPlan: lesser('tasksPerPlan'),\n runners: ({ runners }, { runners: asked }) => ({ value: asked ? runners.filter((runner) => asked.includes(runner)) : runners }),\n models: ({ models }, { models: asked }) => ({ value: intersectModels(models, asked) }),\n};\n\n/** Both `grants` and `grantable`: a child hands on what it holds. `research`, `delegate` and `effect` come only by name (M2). */\nfunction handedOn(parent: Mandate, request: MandateRequest): Ruled<ReadonlySet<Grant>> {\n const asked = new Set<Grant>([...FLOOR_GRANTS, ...(request.grants ?? [])]);\n const lost = FLOOR_GRANTS.some((grant) => !parent.grantable.has(grant));\n if (lost) return { refused: { field: 'grants', asked: listed(asked), there: listed(parent.grantable) } };\n return { value: new Set([...asked].filter((grant) => parent.grantable.has(grant))) };\n}\n\n/** Each field's rule. Mapped over the keys, so a new field or limit fails to compile until it has one. */\nconst MANDATE_RULES: Rules<Mandate, Mandate> = {\n grants: handedOn,\n grantable: handedOn,\n autonomy: ({ autonomy }, { autonomy: asked }) => ({ value: autonomy === 'guarded' || asked === 'guarded' ? 'guarded' : 'full' }),\n limits: ({ limits }, request) => applyRules<MandateLimits, MandateLimits>(LIMIT_RULES, limits, request),\n exclusions: ({ exclusions }, { protectedPaths }) => ({ value: { protectedPaths: [...new Set([...exclusions.protectedPaths, ...(protectedPaths ?? [])])] } }),\n effectRules: ({ effectRules }, { effectRules: asked }) => ({ value: asked ? [...effectRules, asked] : effectRules }),\n ownEffectRules: (_parent, { effectRules: asked }) => ({ value: asked ? [asked] : [] }),\n};\n\nfunction applyRules<Of extends object, From>(rules: Rules<Of, From>, parent: From, request: MandateRequest): Ruled<Of> {\n const value = {} as Of;\n for (const key of Object.keys(rules) as (keyof Of)[]) {\n const ruled = rules[key](parent, request);\n if ('refused' in ruled) return ruled;\n value[key] = ruled.value;\n }\n return { value };\n}\n\n/**\n * A child's mandate (M4), or the refusal that names the level that refused,\n * the field, what was asked and what is there. Pure, and written to be proved:\n * no result is wider than its parent. `parent.limits.tokens` and `wallClockMs`\n * are what the parent has left, which is the caller's to read.\n */\nexport function narrow(parent: Mandate, request: MandateRequest): Narrowed {\n const ruled = applyRules<Mandate, Mandate>(MANDATE_RULES, parent, request);\n return 'refused' in ruled\n ? { ok: false, refusal: { level: request.level, ...ruled.refused } }\n : { ok: true, mandate: ruled.value };\n}\n\n/** What a delegated task asks of the mandate it is given (M4), written the one way plan time and the carve both read. */\nexport function delegatedRequest(task: Pick<Task, 'grants' | 'budget' | 'protectedPaths'>, level: number): MandateRequest {\n return {\n level,\n ...(task.grants ? { grants: task.grants } : {}),\n ...(task.budget?.tokens !== undefined ? { tokens: task.budget.tokens } : {}),\n ...(task.budget?.wallClockMs !== undefined ? { wallClockMs: task.budget.wallClockMs } : {}),\n ...(task.protectedPaths ? { protectedPaths: task.protectedPaths } : {}),\n };\n}\n\n/** The grant each command needs (M2); null for the user's own controls, which no grant reaches. */\nexport const COMMAND_GRANTS: Readonly<Record<ExecutionCommandName, Grant | null>> = {\n run_plan: 'control',\n run_task: 'control',\n stop_task: 'control',\n stop_run: 'control',\n retry_task: 'control',\n message_task: 'steer',\n answer_approval: 'steer',\n merge_all: 'merge',\n skip_task: 'control',\n force_start: null,\n mark_complete: null,\n mark_not_done: null,\n revert_task: null,\n interrupt_task: null,\n force_send_queued: null,\n remove_queued: null,\n cancel_resume: null,\n answer_checkpoint: 'steer',\n approve_review: null,\n run_script: 'control',\n};\n\n/** Whether a mandate lets a node run `command` unasked. */\nexport function allowsCommand(mandate: Mandate, command: ExecutionCommandName): boolean {\n const grant = COMMAND_GRANTS[command];\n return grant !== null && mandate.grants.has(grant);\n}\n\n/** Why a node refuses what its mandate leaves out, naming the level that refused (M4). */\nexport function missingGrant(depth: number, mandate: Mandate, needed: string): string {\n return `Level ${depth} refused this: it needs the ${needed} grant, and this node holds ${listed(mandate.grants)}.`;\n}\n\n/** Why a child's script may not run as it stands (M9). */\nexport const SCRIPT_PAST_THE_RULES = 'its body is not covered at every level of the effect rules, and it would run unsealed';\n\n/** A planner tool no grant reaches is a read, offered to every node. */\nconst TOOL_GRANTS: readonly (readonly [string, Grant])[] = [\n ...Object.entries(COMMAND_GRANTS).flatMap(([tool, grant]) => (grant ? [[tool, grant] as const] : [])),\n ['submit_plan', 'replan'],\n ['edit_plan', 'replan'],\n];\n\n/**\n * The planner tools a child's token leaves out (M6), in one order so the list\n * it is served is the same list on every start: a changed list breaks the\n * prompt cache. A courtesy, read as its session starts: what stops a call is\n * the seam, so a grant lost mid-session is refused with the list unchanged.\n */\nexport function withheldPlannerTools(mandate: Mandate): string[] {\n return TOOL_GRANTS.filter(([, grant]) => !mandate.grants.has(grant)).map(([tool]) => tool);\n}\n\n/** What a node reads of its own authority, at each check (M1). */\nexport interface NodeAuthority {\n /** How far below the root, which is 0 and where a person remains. */\n readonly depth: number;\n /** The mandate that holds now. `level` is what the root's is read at; a child's does not depend on it. */\n mandate(level: SupervisorLevel): Mandate;\n}\n\n/**\n * Whether a node's runners take their autonomous modes (M6): a child reads its\n * `autonomy`, and the root the global level, which `rootMandate` reads too.\n */\nexport function autonomousAt(child: NodeAuthority | undefined, global: boolean): boolean {\n return child ? child.mandate('off').autonomy === 'full' : global;\n}\n\n/** The root: its settings read as each check asks, the level included, which each caller names. */\nexport function rootAuthority(settings: () => Omit<RootSettings, 'level'>): NodeAuthority {\n return { depth: 0, mandate: (level) => rootMandate({ ...settings(), level }) };\n}\n","import type { IntakeCatalog } from './PlannedTask';\nimport type { DiscoveredModel, RunnerId, Task, TaskModelAssignment } from '../models/Task';\nimport { clampThinkingEffort, effectiveAllowlist } from './ModelAllowlistResolver';\nimport { plannedMode, readOnlyMode, readOnlyRunners, taggedReadOnlyMode, unavailableModeReason, type RunnerModeInfo } from './ModeResolver';\n\n/**\n * Who writes a task's assignment. It decides what a model the writer names\n * meets where the task's runner does not offer it or the allowlist excludes it\n * (ADR-0003), which runners it may put a task on, and whether a live runner's\n * hold applies (ADR-0041):\n *\n * - `plan`: a whole plan the planner submitted, and every planner task as it\n * lands. A stray model is replaced, and the planner is told what moved.\n * - `edit`: the planner's edit. A stray model is refused, which the planner\n * answers in the same reply.\n * - `user`: a user's direct edit. A stray model is refused, with the reason.\n * - `userAdd`: a task the user adds. A stray model is replaced, and the user\n * is told what moved.\n * - `runner`: a switch made with the runner's own `/model`, written as the\n * user's edit. The runner already runs it, so neither the allowlist nor the\n * live runner's hold applies.\n */\nexport type AssignmentWriter = 'plan' | 'edit' | 'user' | 'userAdd' | 'runner';\n\n/**\n * What an assignment is resolved against: the discovered models, the manifest\n * modes and the allowlist, as the session holds them when the write lands —\n * the same catalog the planner's per-turn block shows, so nothing is refused\n * that the planner was never told about.\n */\nexport interface AssignmentCatalog {\n /** A runner absent, or listed with nothing, has models discovery could not find, not none. */\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>;\n /** Absent when no runner's modes are known: no mode is then derived. */\n runnerModes?: Partial<Record<RunnerId, readonly RunnerModeInfo[]>>;\n /** Raw (unfiltered) allowlist, keyed by runner; read through {@link effectiveAllowlist}. */\n perRunnerAllowlist?: Partial<Record<RunnerId, string[]>>;\n /** Why an edit may not write a delegated task, or null when it may; absent, no node is behind it (`IntakeCatalog`). */\n delegationRefusal?: string | null;\n /** Which script tasks an edit adds land sealed (`IntakeCatalog`). */\n sealsScripts?: IntakeCatalog['sealsScripts'];\n /** Full (true) or Guarded: the mode a derived task lands on unless it is read-only (ADR-0001). Full when absent. */\n autonomousDefault?: boolean;\n /**\n * Whether a task's runner is live: an attempt of it is claimed, running,\n * quiet or waiting on someone. Its model, effort and runner are then that\n * runner's (ADR-0041): the process was started on them, and only the\n * runner's own command moves them. Absent means none is.\n */\n liveRunner?: (taskId: string) => boolean;\n}\n\n/** What a runner offers a task, as discovery and its manifest have it. */\nexport interface RunnerCatalog {\n models: DiscoveredModel[];\n modes: RunnerModeInfo[];\n}\n\n/** A change the resolver made to what was written, named so it is never silent (ADR-0001). */\nexport interface AssignmentAdjustment {\n taskId: string;\n title: string;\n field: 'assignedModel' | 'thinkingEffort';\n from: string | null;\n to: string | null;\n}\n\nexport interface AssignmentWrite {\n writer: AssignmentWriter;\n /** The task as written: the plan's task with the edit laid over it, or a new task. Its subtasks are not read. */\n task: Task;\n /** The task as the plan holds it; absent for a new task. */\n before?: Task;\n /**\n * What a new task is made from — the task a split part or merge starts\n * as. Its runner and model are read as `before`'s are: a part moved to\n * another runner carries a model chosen for the old one.\n */\n from?: Pick<Task, 'assignedRunner' | 'assignedModel' | 'taskMode'>;\n /** The planner's answer to read-only or not (ADR-0001). Absent, the task stays as it was. */\n readOnly?: boolean;\n catalog: AssignmentCatalog;\n}\n\nexport type AssignmentOutcome =\n | { ok: true; task: Task; adjustments: AssignmentAdjustment[] }\n | { ok: false; field: 'assignedRunner' | 'assignedModel' | 'taskMode'; error: string };\n\n/**\n * Why a task's model or effort cannot change while its runner is live, for\n * every writer but the runner itself. The plan follows a switch made with the\n * runner's own command instead (ADR-0041), so that is offered beside stopping it.\n */\nexport function liveModelRefusal(task: Pick<Task, 'title'>): string {\n return `\"${task.title}\" has a live runner, so its model and effort cannot change now: stop the task first, or use the runner's own /model`;\n}\n\n/**\n * Why a task cannot move to another runner while its runner is live: the move\n * re-derives the model from the new runner, under the same hold as\n * {@link liveModelRefusal}, and no runner's own command can make it.\n */\nexport function liveRunnerRefusal(task: Pick<Task, 'title'>): string {\n return `\"${task.title}\" has a live runner, so its runner cannot change now: stop the task first`;\n}\n\n/**\n * The runners a writer may put a task on (ADR-0003, V1): the planner's, a\n * submitted plan or an edit, the runners enabled now; a user any runner.\n * Undefined means any. A task an edit leaves on a runner switched off since is\n * not put there by the edit, so it stands (`applyTaskOps`, ADR-0043).\n */\nexport function assignableRunners(writer: AssignmentWriter, enabled: readonly RunnerId[]): RunnerId[] | undefined {\n if (writer === 'plan' || writer === 'edit') return [...enabled];\n return undefined;\n}\n\nfunction sameAssignment(a: TaskModelAssignment | undefined, b: TaskModelAssignment | undefined): boolean {\n return a?.modelId === b?.modelId && a?.thinkingEffort === b?.thinkingEffort;\n}\n\n/** Whether `mode` selects Ordewell's read-only profile on this runner (ADR-0046). */\nfunction readOnlyOn(mode: string | undefined, runner: RunnerId, catalog: AssignmentCatalog): boolean {\n return mode !== undefined && mode === taggedReadOnlyMode(catalog.runnerModes?.[runner]);\n}\n\n/**\n * The task's mode as written. The writer's own pick stands where the runner\n * offers it; otherwise a task the writer creates, moves, turns into an AI task\n * or says read-only or not of gets the mode the planner path gives it\n * (ADR-0001's fill-in table): its read-only mode, else the mode it has when\n * the runner offers it, else the runner's mode for the level. Silence keeps\n * what is, so a mode the user picked by hand survives every other edit.\n */\nfunction modeFor(write: AssignmentWrite, task: Task, moved: boolean): { ok: true; mode: string | undefined } | { ok: false; error: string } {\n const { writer, before, catalog } = write;\n const prior = before ?? write.from;\n const runner = task.assignedRunner;\n const modes = catalog.runnerModes?.[runner];\n const picked = (writer === 'user' || writer === 'userAdd') && task.taskMode !== undefined && task.taskMode !== prior?.taskMode;\n if (picked) {\n if (modes && modes.length > 0 && !modes.some((m) => m.id === task.taskMode)) {\n return { ok: false, error: `Runner \"${runner}\" has no task mode \"${task.taskMode}\": valid modes: ${modes.map((m) => m.id).join(', ')}` };\n }\n const unavailable = unavailableModeReason(modes, task.taskMode);\n if (unavailable) return { ok: false, error: `Mode \"${task.taskMode}\" of runner \"${runner}\" is unavailable on this host: ${unavailable}` };\n return { ok: true, mode: task.taskMode };\n }\n const becameAi = before !== undefined && before.type !== 'ai';\n if (writer === 'runner' || !catalog.runnerModes || (before && !moved && !becameAi && write.readOnly === undefined)) return { ok: true, mode: task.taskMode };\n // A move carries the old runner's mode id, which says read-only only on that runner.\n const carried = prior !== undefined && task.taskMode === prior.taskMode && readOnlyOn(prior.taskMode, prior.assignedRunner, catalog);\n const readOnly = write.readOnly ?? (carried || readOnlyOn(task.taskMode, runner, catalog));\n if (readOnly && !readOnlyMode(modes) && writer !== 'plan' && writer !== 'edit') {\n const reason = unavailableModeReason(modes, taggedReadOnlyMode(modes));\n const able = readOnlyRunners(catalog.runnerModes).filter((r) => r !== runner);\n return {\n ok: false,\n error: `\"${task.title}\" is read-only, and runner \"${runner}\" has no read-only mode${reason ? ' available on this host' : ''}: give it another mode first${able.length > 0 ? `, or move it to one of: ${able.join(', ')}` : ''}${reason ? `. ${reason}` : ''}`,\n };\n }\n const mode = plannedMode(runner, catalog.runnerModes, { readOnly, current: task.taskMode }, catalog.autonomousDefault ?? false);\n return mode.ok ? { ok: true, mode: mode.mode ?? task.taskMode } : mode;\n}\n\n/**\n * Resolve what one task runs on — its runner, model, thinking effort and mode\n * — for whichever writer wrote it. Every writer calls this, so they cannot\n * disagree. Returns the task with what it resolved, and each change made to\n * what was written, named; or a refusal.\n *\n * - **The live runner's hold.** While its runner is live a task's runner,\n * model and effort are that runner's (ADR-0041): any other writer is\n * refused a change, a model cleared as much as one replaced.\n * - **A model is its runner's.** A model the writer left alone stays, even off\n * the allowlist: the allowlist shapes what is written, not a model the user\n * switched to (ADR-0043). A model the task carries from another runner — a\n * move, or a part made from a task on another one — stays only where its new\n * runner lists it, or nothing is known against it, and the allowlist admits\n * it. A model the writer names is held to the runner and the allowlist as\n * its {@link AssignmentWriter} row says: the runner already runs it\n * (`runner`), or it is refused (`edit`, `user`), or replaced (`plan`,\n * `userAdd`) when only another runner lists it (it provably cannot run here)\n * or the allowlist excludes it. A model listed by no runner is not one any\n * runner disowns, so it stands, and the runner validates last.\n * - **Filling a model.** A missing, carried-off or replaced model is refilled\n * from the runner: the allowlist's first model the runner lists, else the\n * allowlist's first, else the runner's own first, else none, which the\n * runner fills with its own default.\n * - **Effort follows its model.** Whenever the model is listed, its effort is\n * held to what it offers ({@link clampThinkingEffort}, the one mapping rule:\n * the nearest level the model has, none when it has none); a model put in\n * here that discovery does not list gets none. A model discovery does not\n * list keeps the effort written with it, which the runner validates.\n * - **The mode** is the writer's pick where it has one, else derived as\n * {@link modeFor} says.\n *\n * Which runners a writer may use is the plan's rule ({@link assignableRunners},\n * `checkPlanInvariants`); this never moves a task to another runner.\n */\nexport function resolveAssignment(write: AssignmentWrite): AssignmentOutcome {\n const { writer, before, catalog } = write;\n const written = write.task;\n const prior = before ?? write.from;\n const moved = prior !== undefined && prior.assignedRunner !== written.assignedRunner;\n const title = (before ?? written).title;\n\n const live = writer !== 'runner' && !!before && !!catalog.liveRunner?.(before.id);\n if (live && moved) return { ok: false, field: 'assignedRunner', error: liveRunnerRefusal({ title }) };\n if (live && !sameAssignment(before?.assignedModel, written.assignedModel)) return { ok: false, field: 'assignedModel', error: liveModelRefusal({ title }) };\n // A manual task runs on nothing, and a script task on no runner (ADR-0035).\n if (written.type !== 'ai' && written.type !== 'delegated') return { ok: true, task: written, adjustments: [] };\n\n // A delegated task's runner runs a planner, in no mode the plan holds (ADR-0055 D14).\n const mode = written.type === 'delegated' ? { ok: true as const, mode: undefined } : modeFor(write, written, moved);\n if (!mode.ok) return { ok: false, field: 'taskMode', error: mode.error };\n\n // A live runner holds its model and effort as they are, even where its model's levels have changed since.\n const model: ModelResult = live ? { ok: true, assignment: written.assignedModel } : modelFor(write, moved);\n if (!model.ok) return { ok: false, field: 'assignedModel', error: model.error };\n\n const task = model.assignment === written.assignedModel && mode.mode === written.taskMode\n ? written\n : { ...written, assignedModel: model.assignment, taskMode: mode.mode };\n const adjustments: AssignmentAdjustment[] = [];\n const note = (field: AssignmentAdjustment['field'], from: string | undefined, to: string | undefined) => {\n if ((from ?? null) !== (to ?? null)) adjustments.push({ taskId: written.id, title: written.title, field, from: from ?? null, to: to ?? null });\n };\n note('assignedModel', written.assignedModel?.modelId, task.assignedModel?.modelId);\n note('thinkingEffort', written.assignedModel?.thinkingEffort, task.assignedModel?.thinkingEffort);\n return { ok: true, task, adjustments };\n}\n\ntype ModelResult = { ok: true; assignment: TaskModelAssignment | undefined } | { ok: false; error: string };\n\n/** The model half of {@link resolveAssignment}. */\nfunction modelFor(write: AssignmentWrite, moved: boolean): ModelResult {\n const { writer, before, catalog } = write;\n const prior = before ?? write.from;\n const written = write.task.assignedModel;\n const runner = write.task.assignedRunner;\n const models = catalog.modelsByRunner;\n const own = models[runner] ?? [];\n const listing = (id: string) => own.find((m) => m.modelId === id);\n // A model the task ran with on another runner is evidence that runner lists it, which the allowlist is read with (R1).\n const carriedFrom = moved && written && prior?.assignedModel?.modelId === written.modelId ? prior.assignedRunner : undefined;\n const seen = carriedFrom && written && !models[carriedFrom]?.some((m) => m.modelId === written.modelId)\n ? { ...models, [carriedFrom]: [...(models[carriedFrom] ?? []), { modelId: written.modelId, modelLabel: written.modelLabel, variants: [] }] }\n : models;\n const allowed = effectiveAllowlist(catalog.perRunnerAllowlist?.[runner], runner, seen);\n const allows = (id: string) => !allowed || allowed.includes(id);\n\n // Held to what its model offers, unless that model is one discovery does not list.\n const settled = (assignment: TaskModelAssignment): TaskModelAssignment => {\n const known = listing(assignment.modelId);\n if (!known) return assignment;\n const thinkingEffort = clampThinkingEffort(assignment.thinkingEffort, known.variants);\n const availableVariants = known.variants.map((v) => v.id);\n if (thinkingEffort === assignment.thinkingEffort && assignment.availableVariants?.join() === availableVariants.join()) return assignment;\n const next: TaskModelAssignment = { ...assignment, availableVariants };\n if (thinkingEffort === undefined) delete next.thinkingEffort;\n else next.thinkingEffort = thinkingEffort;\n return next;\n };\n // The allowlist's order is its priority, among the models the runner lists\n // first; an allowlisted id discovery does not list still beats one the user excluded (R1).\n const refill = (effort: string | undefined): TaskModelAssignment | undefined => {\n const id = allowed?.find((a) => listing(a)) ?? allowed?.[0] ?? own[0]?.modelId;\n if (id === undefined) return undefined;\n const known = listing(id);\n const thinkingEffort = clampThinkingEffort(effort, known?.variants ?? []);\n return {\n modelId: id,\n modelLabel: known?.modelLabel ?? id,\n ...(thinkingEffort !== undefined ? { thinkingEffort } : {}),\n ...(known ? { availableVariants: known.variants.map((v) => v.id) } : {}),\n };\n };\n\n if (!written) return { ok: true, assignment: writer === 'runner' ? undefined : refill(undefined) };\n if (writer === 'runner') return { ok: true, assignment: settled(written) };\n\n const id = written.modelId;\n const same = prior?.assignedModel?.modelId === id;\n if (before && same && !moved) return { ok: true, assignment: settled(written) };\n\n const listedElsewhere = Object.entries(models).some(([other, list]) => other !== runner && list?.some((m) => m.modelId === id));\n if (same) {\n // Carried from a task on another runner, it was chosen for that one: it\n // needs this one's listing, or nothing known against it.\n const fits = !moved || !!listing(id) || (own.length === 0 && !listedElsewhere);\n return { ok: true, assignment: fits && allows(id) ? settled(written) : refill(written.thinkingEffort) };\n }\n\n if (writer === 'edit' || writer === 'user') {\n // Allowlisted ids are kept even unlisted (ADR-0003, R1); an empty list is discovery that found nothing.\n const offered = own.length === 0 || !!listing(id) || !!allowed?.includes(id);\n if (!offered) return { ok: false, error: `Runner \"${runner}\" does not offer model \"${id}\"` };\n if (!allows(id)) return { ok: false, error: `Model \"${id}\" is excluded by the allowlist for runner \"${runner}\"` };\n return { ok: true, assignment: settled(written) };\n }\n // Only another runner lists it: it provably cannot run here.\n const disowned = !listing(id) && listedElsewhere;\n return { ok: true, assignment: disowned || !allows(id) ? refill(written.thinkingEffort) : settled(written) };\n}\n\n/**\n * The planner's tasks as they land, subtasks included: each resolved as the\n * planner's ({@link resolveAssignment}, `plan`) against the catalog read now\n * and against the plan's task of the same id, so a model or allowlist that\n * changed since the write was checked is applied and named. A task the\n * planner left alone keeps its model; one whose runner is live keeps all of\n * its assignment. Modes were decided when the task was written, and are not\n * revisited. Nothing is refused here: a write the catalog no longer allows is\n * kept as it was written, and the runner validates last.\n */\nexport function resolveAssignments(\n tasks: readonly Task[],\n planned: readonly Task[],\n catalog: AssignmentCatalog,\n): { tasks: Task[]; adjustments: AssignmentAdjustment[] } {\n const prior = new Map<string, Task>();\n const index = (list: readonly Task[]) => list.forEach((t) => { prior.set(t.id, t); index(t.subtasks ?? []); });\n index(planned);\n const models = { ...catalog, runnerModes: undefined };\n const adjustments: AssignmentAdjustment[] = [];\n const walk = (list: readonly Task[]): Task[] => list.map((task) => {\n const outcome = resolveAssignment({ writer: 'plan', task, before: prior.get(task.id), catalog: models });\n const resolved = outcome.ok ? outcome.task : task;\n if (outcome.ok) adjustments.push(...outcome.adjustments);\n return { ...resolved, subtasks: walk(task.subtasks ?? []) };\n });\n return { tasks: walk(tasks), adjustments };\n}\n","import type { Task } from './Task';\nimport { GRANTS, type Grant } from '../services/Mandate';\nimport { flattenTasks } from './Task';\nimport { ONE_LINE, splitLines } from './lineBreaks';\nimport { taggedReadOnlyMode, type RunnerModeInfo } from '../services/ModeResolver';\n\n/** A delegated task's budget: tokens, and optionally wall-clock time (ADR-0056 M5). */\nexport interface DelegatedBudget {\n tokens: number;\n wallClockMs?: number;\n}\n\n/** Where a child plan's tasks stand now: the counts a delegated task's row shows while its child runs (ADR-0055 D20). */\nexport interface ChildTaskCounts {\n completed: number;\n running: number;\n /** Waiting on a person, a checkpoint among them. */\n waiting: number;\n pending: number;\n failed: number;\n skipped: number;\n}\n\n/**\n * What a delegated task's row says beyond any task's (ADR-0055 D16, D20): all of\n * it derived where it is read, from the child's plan, the tree's ledger and the\n * Stop, never kept. Every part is absent when there is nothing to say.\n */\nexport interface DelegatedRow {\n /** The child's tasks by where they stand; absent with no child session open. */\n tasks?: ChildTaskCounts;\n /** The task's token budget, and what the tree has not yet spent of it, across every child it has had (ADR-0056 M10). */\n tokens?: { budget: number; left: number };\n /** A Stop is still winding the subtree down, though the task already reads as not started (D16). */\n stopping?: true;\n}\n\nexport function countChildTasks(statuses: readonly Task['status'][]): ChildTaskCounts {\n const counts: ChildTaskCounts = { completed: 0, running: 0, waiting: 0, pending: 0, failed: 0, skipped: 0 };\n for (const status of statuses) {\n if (status === 'completed') counts.completed += 1;\n else if (status === 'in_progress') counts.running += 1;\n else if (status === 'awaiting_user') counts.waiting += 1;\n else if (status === 'failed') counts.failed += 1;\n else if (status === 'skipped') counts.skipped += 1;\n else counts.pending += 1;\n }\n return counts;\n}\n\n/** What a task declares it works on (ADR-0057 R6). Advisory: nothing gates on it. */\nexport interface TaskScope {\n paths?: string[];\n provides?: string[];\n consumes?: string[];\n}\n\n/** How long a scope's item is, and how many of each it holds: each can reach a line Ordewell writes (ADR-0057 R6). */\nexport const SCOPE_LIMITS = { item: 200, items: 50 } as const;\n\n/** What a delegated task does not have: it holds a goal, not a runner prompt, so it has no mode, skills or steps, and it never runs in the checkout (ADR-0055 D1). */\nexport const NOT_A_DELEGATED_TASKS_FIELDS = ['prompt', 'taskMode', 'skills', 'userSteps', 'ops', 'commands', 'script', 'timeoutMs', 'research'] as const satisfies readonly (keyof Task)[];\n\n/** The fields only a delegated task has. */\nexport const DELEGATED_FIELDS = ['goal', 'budget', 'grants', 'protectedPaths', 'scope'] as const satisfies readonly (keyof Task)[];\n\n/** Refused until something asks for it by name: a planner with no node behind it has no mandate to read. */\nexport const DELEGATION_UNAVAILABLE = 'delegation is not available in this session';\n\nexport function notOnADelegatedMessage(fields: readonly string[]): string {\n return `is a delegated task, which holds a goal for a child plan: leave out ${fields.map((f) => `\"${f}\"`).join(', ')}`;\n}\n\nexport interface DelegationError {\n taskId: string;\n field: string;\n message: string;\n}\n\nexport interface DelegationRules {\n /** The modes of each runner, for what makes an AI task read-only (ADR-0031). */\n runnerModes?: Partial<Record<string, readonly RunnerModeInfo[]>>;\n /** Whether a script can run sealed on this host (ADR-0036 S6); unknown reads as yes, since `checkPlanInvariants` is pure. */\n canSeal?: boolean;\n}\n\nfunction isBudget(value: unknown): value is DelegatedBudget {\n if (typeof value !== 'object' || value === null) return false;\n const { tokens } = value as { tokens?: unknown };\n return typeof tokens === 'number' && Number.isInteger(tokens) && tokens > 0;\n}\n\n/** A positive whole number of milliseconds, or none at all. */\nfunction wallClockOk(budget: DelegatedBudget): boolean {\n const { wallClockMs } = budget;\n return wallClockMs === undefined || (Number.isInteger(wallClockMs) && wallClockMs > 0);\n}\n\n/** Whether `task` is an AI task that runs read-only, as its mode says (ADR-0031). */\nfunction readsOnly(task: Task, runnerModes: DelegationRules['runnerModes']): boolean {\n if (task.type !== 'ai') return false;\n const mode = runnerModes ? taggedReadOnlyMode(runnerModes[task.assignedRunner]) : 'plan';\n return mode !== undefined && task.taskMode === mode;\n}\n\n/** Whether nothing here can say what mode `task` runs in: its runner was switched off since, removed, or belongs to another machine. */\nfunction runnerUnread(task: Task, runnerModes: DelegationRules['runnerModes']): boolean {\n return task.type === 'ai' && runnerModes !== undefined && runnerModes[task.assignedRunner] === undefined;\n}\n\n/** Whether a task runs at the workspace root behind a merge gate, so it cannot be cut from the integration tip. */\nfunction atAGate(task: Task): boolean {\n return (task.type === 'script' && !task.readOnly) || task.ops === true;\n}\n\n/** Everything `taskId` depends on, directly or through other tasks. */\nfunction reaches(tasks: readonly Task[], from: Task, target: (task: Task) => boolean): boolean {\n const byId = new Map(tasks.map((t) => [t.id, t]));\n const seen = new Set<string>();\n const walk = (task: Task): boolean => task.dependencies.some((id) => {\n if (seen.has(id)) return false;\n seen.add(id);\n const dep = byId.get(id);\n return dep !== undefined && (target(dep) || walk(dep));\n });\n return walk(from);\n}\n\n/**\n * The rules a delegated task is held to on every route (ADR-0055 D1, D7, D8),\n * as `loopErrors` holds a loop: what it must carry, and its check. A check is a\n * task that directly depends on it, a read-only AI task or a script marked\n * `readOnly`, and on a `readOnly` delegated task only the first: it never lands,\n * so a script there would judge the unchanged baseline. Passing proves a list\n * of paths was written, not that it is whole (D7).\n */\nexport function delegationErrors(tasks: readonly Task[], rules: DelegationRules = {}): DelegationError[] {\n const errors: DelegationError[] = [];\n const delegated = tasks.filter((t) => t.type === 'delegated');\n const fail = (task: Task, field: string, message: string) => errors.push({ taskId: task.id, field, message });\n\n for (const task of delegated) {\n const where = `Task \"${task.title}\"`;\n if (typeof task.goal !== 'string' || !task.goal.trim()) fail(task, 'goal', `${where} is a delegated task with no \"goal\": say what its child plan must achieve`);\n if (!isBudget(task.budget)) fail(task, 'budget', `${where} is a delegated task with no \"budget\": give it {\"tokens\": <a whole number>}, and \"wallClockMs\" if it has a time limit`);\n else if (!wallClockOk(task.budget)) fail(task, 'budget', `${where} has a \"wallClockMs\" that is not a whole number of milliseconds above 0`);\n const paths = task.protectedPaths;\n if (!task.readOnly && (!Array.isArray(paths) || paths.length === 0 || !paths.every((p) => typeof p === 'string' && p.trim()))) {\n fail(task, 'protectedPaths', `${where} is a delegated task that lands, with no \"protectedPaths\": name the paths its child may not change, what its check runs and the configuration that runs it`);\n }\n if (task.scope !== undefined && !scopeOk(task.scope)) fail(task, 'scope', `${where} has a \"scope\" that is not lists of text: \"paths\", \"provides\" and \"consumes\", at most ${SCOPE_LIMITS.items} items of one line and ${SCOPE_LIMITS.item} characters each`);\n const unknown = (task.grants ?? []).filter((grant) => !GRANTS.includes(grant as Grant));\n if (unknown.length > 0) fail(task, 'grants', `${where} asks in \"grants\" for ${unknown.map((g) => `\"${g}\"`).join(', ')}, which no grant is: one of ${GRANTS.join(', ')}`);\n\n const dependents = tasks.filter((t) => t.dependencies.includes(task.id));\n if (task.readOnly) {\n for (const script of dependents.filter((t) => t.type === 'script')) {\n fail(script, 'dependencies', `Task \"${script.title}\" depends on \"${task.title}\", which is a read-only delegated task, which lands nothing, so a script has nothing to run on: make the check a read-only AI task, which reads its handoff`);\n }\n }\n if (!dependents.some((t) => judges(t, task, rules.runnerModes))) {\n fail(task, 'dependencies', `${where} is a delegated task with no check: add a read-only AI task${task.readOnly ? ', which reads its handoff,' : ', or a script task marked \"readOnly\",'} that depends on it directly`);\n }\n }\n\n for (const task of tasks.filter((t) => t.type === 'script' && t.readOnly)) {\n if (rules.canSeal === false) fail(task, 'readOnly', `Task \"${task.title}\" is a read-only script task, and this machine has no sandbox to seal one in: make the check a read-only AI task`);\n }\n\n // A body at a gate waits for a merge the delegated task's hold keeps back (D9), and the check waits on that body.\n for (const check of tasks.filter((t) => t.loop)) {\n if (!reaches(tasks, check, (t) => t.type === 'delegated')) continue;\n for (const id of check.loop?.body ?? []) {\n const body = tasks.find((t) => t.id === id);\n if (body && atAGate(body)) {\n fail(body, 'loop', `Task \"${check.title}\" names \"${body.title}\" in its loop's \"body\", which waits at a merge gate for work a delegated task's check holds back: make the fix a change task, cut from the integration tip`);\n }\n }\n }\n return errors;\n}\n\nfunction scopeOk(scope: unknown): boolean {\n if (typeof scope !== 'object' || scope === null) return false;\n const { paths, provides, consumes } = scope as Record<string, unknown>;\n const itemOk = (item: unknown) => typeof item === 'string' && item.trim().length > 0 && item.length <= SCOPE_LIMITS.item && ONE_LINE.test(item);\n return [paths, provides, consumes].every((list) => list === undefined || (Array.isArray(list) && list.length <= SCOPE_LIMITS.items && list.every(itemOk)));\n}\n\n/** Whether `task` can judge `delegated`: a read-only AI task, or a read-only script of one that lands (D8). */\nfunction judges(task: Task, delegated: Task, runnerModes: DelegationRules['runnerModes']): boolean {\n return readsOnly(task, runnerModes) || (!delegated.readOnly && task.type === 'script' && task.readOnly === true);\n}\n\n/**\n * The checks of a delegated task: what depends on it directly and can judge it\n * (D8). One whose runner cannot be read may be its only check, so it counts,\n * and the hold fails closed (D9). Only a plan being written is held to\n * `judges` alone: a task nothing can read is no check to accept one on.\n */\nexport function checksOf(tasks: readonly Task[], delegated: Task, rules: Pick<DelegationRules, 'runnerModes'> = {}): Task[] {\n return tasks.filter((t) => t.dependencies.includes(delegated.id) && (judges(t, delegated, rules.runnerModes) || runnerUnread(t, rules.runnerModes)));\n}\n\n/**\n * The checks that hold every merge but the user's (ADR-0055 D9): each of a\n * delegated task with landed work not yet merged that has neither passed nor\n * been skipped. Work that has not landed holds nothing, and a read-only task\n * never lands.\n */\nexport function checksHoldingMerge(tasks: readonly Task[], awaitsMerge: (taskId: string) => boolean, rules: Pick<DelegationRules, 'runnerModes'> = {}): Task[] {\n return tasks\n .filter((t) => t.type === 'delegated' && awaitsMerge(t.id))\n .flatMap((t) => checksOf(tasks, t, rules))\n .filter((check) => check.status !== 'completed' && check.status !== 'skipped');\n}\n\n/** Something a check is made of. A `command` is the check itself at any length, where prose says little until it has some. */\nexport interface CheckWord {\n text: string;\n command: boolean;\n}\n\n/** The commands a check runs, a script's one by one: holding any of them is holding the check. */\nfunction commandsOf({ script, commands }: Task): string[] {\n const written = splitLines(script ?? '').flatMap((line) => line.split(/[;|&]+/)).map((command) => command.trim()).filter((command) => !command.startsWith('#'));\n return [...written, ...(commands ?? []).map((argv) => argv.join(' '))].filter(Boolean);\n}\n\n/**\n * What this plan's checks are made of (ADR-0057 R10): the words of whatever\n * depends directly on a delegated task, which is all a pure reader of the plan\n * can tell a check by. A pin may hold none of them whole.\n */\nexport function checkWords(tasks: readonly Task[]): CheckWord[] {\n const delegated = new Set(tasks.filter((t) => t.type === 'delegated').map((t) => t.id));\n return tasks.filter((t) => t.dependencies.some((id) => delegated.has(id))).flatMap((t) => [\n ...[t.title, t.prompt ?? ''].map((text) => ({ text, command: false })),\n ...commandsOf(t).map((text) => ({ text, command: true })),\n ]);\n}\n\n/** Whether `task` is the check of a delegated task of `tasks`: what a model may not skip past, since that lets the work past its only check (D8). */\nexport function checksDelegatedTask(tasks: readonly Task[], task: Task, rules: Pick<DelegationRules, 'runnerModes'> = {}): boolean {\n if (!readsOnly(task, rules.runnerModes) && !runnerUnread(task, rules.runnerModes) && !(task.type === 'script' && task.readOnly)) return false;\n return tasks.some((t) => t.type === 'delegated' && task.dependencies.includes(t.id));\n}\n\n/** The tasks a child's plan counts: its whole list, subtasks included. */\nexport function planSize(tasks: readonly Task[]): number {\n return flattenTasks(tasks).length;\n}\n\n/**\n * Whether one path of a repository falls under a protected path: a file it\n * names, a directory it names with or without a trailing slash, or a `*`\n * pattern. Case and separators as git prints them; nothing resolves a link,\n * since a diff lists what the branch changed by name.\n */\nexport function underProtectedPath(file: string, protectedPath: string): boolean {\n const rule = protectedPath.trim().replace(/^\\.\\//, '').replace(/\\\\/g, '/');\n if (!rule) return false;\n if (rule.includes('*')) return globRegExp(rule).test(file);\n const bare = rule.replace(/\\/+$/, '');\n return file === bare || file.startsWith(`${bare}/`);\n}\n\n/** What comes before a rule's first `*`: all two patterns can be told apart by without matching one against the other. */\nfunction fixedStart(rule: string): string {\n const bare = rule.trim().replace(/^\\.\\//, '').replace(/\\\\/g, '/');\n const star = bare.indexOf('*');\n return star === -1 ? bare : bare.slice(0, star);\n}\n\n/** Whether two declared paths can name one file. Advisory, so two patterns are read generously: what they start with decides it. */\nexport function pathsMeet(a: string, b: string): boolean {\n if (underProtectedPath(a.replace(/\\/+$/, ''), b) || underProtectedPath(b.replace(/\\/+$/, ''), a)) return true;\n if (!a.includes('*') || !b.includes('*')) return false;\n const [one, other] = [fixedStart(a), fixedStart(b)];\n return one.startsWith(other) || other.startsWith(one);\n}\n\n/** The narrower of two declared paths that meet: what a planner reads the overlap as. */\nfunction narrower(a: string, b: string): string {\n return b.includes('*') || (!a.includes('*') && a.length >= b.length) ? a : b;\n}\n\n/** Whether an edge of the plan puts one of two tasks after the other. */\nfunction ordered(tasks: readonly Task[], a: Task, b: Task): boolean {\n return reaches(tasks, a, (t) => t.id === b.id) || reaches(tasks, b, (t) => t.id === a.id);\n}\n\n/**\n * What a plan's scopes leave for its planner to settle (ADR-0057 R6), a\n * sentence each. It refuses nothing, since a scope is advisory: this is the\n * answer the tool gives, and two tasks an edge orders have nothing to settle.\n */\nexport function scopeOverlaps(tasks: readonly Task[]): string[] {\n const scoped = tasks.filter((t) => t.type === 'delegated' && t.scope);\n const said: string[] = [];\n scoped.forEach((a, i) => {\n for (const b of scoped.slice(i + 1)) {\n if (ordered(tasks, a, b)) continue;\n const declared = (a.scope?.paths ?? []).flatMap((one) => (b.scope?.paths ?? []).filter((other) => pathsMeet(one, other)).map((other) => narrower(one, other)));\n if (declared.length > 0) said.push(`Tasks \"${a.title}\" and \"${b.title}\" both declare ${[...new Set(declared)].join(', ')}, and nothing orders them: give one a dependency on the other, or name an owner.`);\n for (const name of a.scope?.provides ?? []) {\n if (b.scope?.provides?.includes(name)) said.push(`Tasks \"${a.title}\" and \"${b.title}\" both provide \"${name}\", and nothing orders them: name one owner.`);\n }\n for (const [producer, consumer] of [[a, b], [b, a]] as const) {\n for (const name of producer.scope?.provides ?? []) {\n if (consumer.scope?.consumes?.includes(name)) said.push(`Task \"${consumer.title}\" consumes \"${name}\", which \"${producer.title}\" provides, and nothing orders them: a dependency puts the producer first; without one it gets a line when \"${producer.title}\" lands.`);\n }\n }\n }\n });\n return said;\n}\n\nfunction globRegExp(rule: string): RegExp {\n const pattern = rule.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*\\*\\/?|\\*/g, (star) => (star === '*' ? '[^/]*' : '(?:.*/)?'));\n return new RegExp(`^${pattern}(?:/.*)?$`);\n}\n","import { dependencyTargetErrors, findDependencyCycle } from './PlanTree';\nimport { v4 as uuidv4 } from 'uuid';\nimport { Task, RunnerId, TaskModelAssignment, DEFAULT_RUNNERS, createTask, flattenTasksWithParents, inheritedSkills, skillNames } from '../models/Task';\nimport { taggedReadOnlyMode, type RunnerModeInfo } from './ModeResolver';\nimport { resolveAssignment, type AssignmentAdjustment, type AssignmentCatalog } from './TaskAssignment';\nimport { notAScriptsFields, scriptBodyErrors } from '../models/ScriptTask';\nimport { loopErrors, loopSpec } from '../models/Loop';\nimport { DELEGATION_UNAVAILABLE, NOT_A_DELEGATED_TASKS_FIELDS, delegationErrors, notOnADelegatedMessage, type DelegatedBudget, type DelegationRules, type TaskScope } from '../models/Delegation';\n\n/** One reason a planned task was refused, pinned to the task and field it is about. */\nexport interface PlanTaskError {\n /** Absent when the envelope itself is wrong rather than one of its tasks. */\n taskId?: string;\n field: string;\n message: string;\n}\n\n/** What a planned task may be given: the runners it may run on and their modes. */\nexport interface IntakeCatalog {\n runners: readonly RunnerId[];\n /** Absent when no runner's modes are known: the mode is then guessed (ADR-0031). */\n runnerModes?: Partial<Record<RunnerId, readonly RunnerModeInfo[]>>;\n autonomousDefault?: boolean;\n /**\n * An edit's assignments are resolved against the catalog as it is planned,\n * and a model it names that the runner does not offer is refused; a\n * submitted plan's models are resolved as it lands instead (ADR-0003).\n */\n models?: AssignmentCatalog;\n /**\n * Why this planner may not write a delegated task or a read-only script\n * (ADR-0055 D1, D8), or null when it may. Absent, there is no node to read:\n * a one-shot planner, or a route that holds no mandate.\n */\n delegationRefusal?: string | null;\n /** Which of a child's script tasks run sealed (ADR-0056 M9): each such lands read-only, on every route. */\n sealsScripts?: (task: Pick<Task, 'commands' | 'script' | 'timeoutMs'>) => boolean;\n}\n\n/** Where a planned task lands, which decides what it inherits. */\nexport interface Placement {\n /** The task it is a subtask of. */\n parent?: Pick<Task, 'title' | 'sliceType' | 'autonomy'> & { readOnly: boolean };\n /**\n * A task made from others — a merge, or a split part: what the planner\n * leaves out comes from these fields, and it stays read-only when they were.\n */\n from?: { fields: Partial<Task>; readOnly: boolean };\n /**\n * An edit's tasks get ids of their own, so a planner cannot name one after\n * a task already in the plan. A submitted plan keeps the planner's, which\n * its dependencies are written against; one it left out is made up.\n */\n freshIds?: boolean;\n /** Where a made-up id comes from: a new one each time, unless the caller keeps them. */\n newId?: () => string;\n}\n\nexport interface PlannedTask {\n task: Task;\n /** Rules the task, or one of its subtasks, breaks on its own. */\n errors: PlanTaskError[];\n /**\n * What the planner asked for that is not its to set — a mode, or read-only\n * on a manual task (ADR-0031). A whole plan lands without it; an edit is\n * refused.\n */\n ignored: PlanTaskError[];\n /** The planner's id for each task of the tree that was given a fresh one. */\n renamed: Map<string, string>;\n /** What the tree's assignments were adjusted to beyond what the planner wrote, for the planner to be told. */\n adjustments: AssignmentAdjustment[];\n}\n\n/** The planner names no mode (ADR-0031): it says read-only, and the mode follows. */\nexport const MODE_NOT_THE_PLANNERS = '\"taskMode\" is the user\\'s to choose: set \"readOnly\": true on a task that must not change files, and leave it out otherwise';\n\n/** A manual task runs in no mode, so it cannot be read-only. */\nexport const MANUAL_NOT_READ_ONLY = '\"readOnly\" is for AI tasks: a manual task runs in no mode';\n\n/** An ops task acts in the workspace (ADR-0020); a read-only task lands nothing (ADR-0046). */\nexport const OPS_NOT_READ_ONLY = '\"readOnly\" is not for an ops task: it acts in the workspace, while a read-only task lands nothing';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction text(value: unknown): string | undefined {\n return typeof value === 'string' || typeof value === 'number' ? String(value) : undefined;\n}\n\n/**\n * What a script task's planner may not write on it (ADR-0035): it runs its\n * body with no model, so nothing about a runner, a model, a mode or a prompt\n * applies, and it has no subtasks.\n */\nconst NOT_ON_A_SCRIPT = ['assignedRunner', 'assignedModel', 'thinkingEffort', 'taskMode', 'readOnly', 'prompt', 'skills', 'userSteps', 'ops', 'subtasks'] as const;\n\n/** The fields a planner wrote on a script task that it may not have, by name; none when it wrote none. */\nexport function notOnAScript(raw: Record<string, unknown>): string[] {\n return NOT_ON_A_SCRIPT.filter((f) => {\n const value = raw[f];\n return value !== undefined && value !== null && value !== false && !(Array.isArray(value) && value.length === 0);\n });\n}\n\n/** What a planner wrote on a delegated task that belongs to some other kind of task. */\nfunction notOnADelegated(raw: Record<string, unknown>): string[] {\n return NOT_A_DELEGATED_TASKS_FIELDS.filter((f) => {\n const value = raw[f];\n return value !== undefined && value !== null && value !== false && !(Array.isArray(value) && value.length === 0);\n });\n}\n\n/** A planner's fields, as untyped as the rest of its JSON; a rule refuses what is wrong with a value that reached the task. */\nfunction delegatedFields(raw: Record<string, unknown>, base: Partial<Task>): Pick<Task, 'goal' | 'budget' | 'grants' | 'protectedPaths' | 'scope'> & { readOnly?: true } {\n const list = (value: unknown): string[] | undefined => (Array.isArray(value) ? value.map(String) : undefined);\n const goal = text(raw.goal) ?? base.goal;\n const budget = (isRecord(raw.budget) ? raw.budget as unknown as DelegatedBudget : undefined) ?? base.budget;\n const grants = (list(raw.grants) ?? base.grants) as Task['grants'];\n const protectedPaths = list(raw.protectedPaths) ?? base.protectedPaths;\n const scope = (isRecord(raw.scope) ? raw.scope as TaskScope : undefined) ?? base.scope;\n return {\n ...(goal !== undefined ? { goal } : {}),\n ...(budget ? { budget } : {}),\n ...(grants ? { grants } : {}),\n ...(protectedPaths ? { protectedPaths } : {}),\n ...(scope ? { scope } : {}),\n ...(raw.readOnly === true || (raw.readOnly === undefined && base.readOnly) ? { readOnly: true as const } : {}),\n };\n}\n\n/** The refusal of those fields, worded for the planner. */\nexport function notOnAScriptMessage(fields: readonly string[]): string {\n return `is a script task, which runs its \"commands\" or \"script\" with no model: leave out ${fields.map((f) => `\"${f}\"`).join(', ')}`;\n}\n\n/**\n * Why a task may not be an ops task (ADR-0020), or null when it may: the flag\n * decides where the task runs, and a manual task runs nowhere, a subtask\n * where its parent does.\n */\nexport function opsPlacementRefusal(type: Task['type'], isSubtask: boolean): string | null {\n if (type === 'script') return 'is a script task, which is an ops task by nature: leave \"ops\" out';\n if (type !== 'ai') return 'is a manual task: only an AI task can be an ops task';\n if (isSubtask) return 'is a subtask, which runs with its parent: only a top-level task can be an ops task';\n return null;\n}\n\n/** How an error names a task, so the planner can find the object it wrote. */\nexport function taskWhere(title: string, parentTitle?: string): string {\n return parentTitle !== undefined ? `subtask \"${title}\" of \"${parentTitle}\"` : `Task \"${title}\"`;\n}\n\n/**\n * What each planned task asked to attach, as the planner wrote it. Kept beside\n * the task rather than on it: {@link skillNames} drops a name no skill could\n * have, and the plan's skill check still owes a warning for it. A copy of the\n * task (assignment coercion) does not carry it, so check what was planned.\n */\nconst skillsAsked = new WeakMap<Task, unknown[]>();\n\n/** The `skills` a planned task was submitted with, before normalization; undefined for a task not planned here. */\nexport function requestedSkills(task: Task): readonly unknown[] | undefined {\n return skillsAsked.get(task);\n}\n\n/** The model as a task stores it; a top-level `thinkingEffort` is the model's, as the effort has one home. */\nfunction modelOf(raw: Record<string, unknown>, from: TaskModelAssignment | undefined): TaskModelAssignment | undefined {\n const effort = text(raw.thinkingEffort);\n if (isRecord(raw.assignedModel)) {\n const m = raw.assignedModel;\n return {\n modelId: text(m.modelId) ?? '',\n modelLabel: text(m.modelLabel) ?? '',\n thinkingEffort: text(m.thinkingEffort) ?? effort,\n };\n }\n return from && effort !== undefined ? { ...from, thinkingEffort: effort } : from;\n}\n\n/**\n * A planned task's body fields (ADR-0035): what the planner wrote, else what\n * the task it is made from had. Only a well-formed value is kept on the task;\n * `malformed` names the fields that were not, for their refusal, and `raw` is\n * what was judged.\n */\nfunction bodyFields(raw: Record<string, unknown>, base: Partial<Task>): {\n fields: Pick<Task, 'commands' | 'script' | 'timeoutMs'>;\n raw: Record<'commands' | 'script' | 'timeoutMs', unknown>;\n malformed: Set<string>;\n} {\n const pick = (field: 'commands' | 'script' | 'timeoutMs'): unknown => (raw[field] !== undefined && raw[field] !== null ? raw[field] : base[field]);\n const judged = { commands: pick('commands'), script: pick('script'), timeoutMs: pick('timeoutMs') };\n const malformed = new Set<string>();\n const commands = isCommands(judged.commands) ? judged.commands : undefined;\n if (judged.commands !== undefined && !commands) malformed.add('commands');\n const script = typeof judged.script === 'string' ? judged.script : undefined;\n if (judged.script !== undefined && script === undefined) malformed.add('script');\n const timeoutMs = typeof judged.timeoutMs === 'number' ? judged.timeoutMs : undefined;\n if (judged.timeoutMs !== undefined && timeoutMs === undefined) malformed.add('timeoutMs');\n return {\n fields: { ...(commands ? { commands } : {}), ...(script !== undefined ? { script } : {}), ...(timeoutMs !== undefined ? { timeoutMs } : {}) },\n raw: judged,\n malformed,\n };\n}\n\nfunction isCommands(value: unknown): value is string[][] {\n return Array.isArray(value) && value.every((argv) => Array.isArray(argv) && argv.every((word) => typeof word === 'string'));\n}\n\n/**\n * Build a task from what a planner wrote, by whichever route it arrived: a\n * submitted plan, or an edit that adds, merges or splits. Every fallback a\n * planner's omission meets is here, so the routes cannot drift apart:\n *\n * - the runner is the one named, else the task's it is made from, else the\n * first one allowed — never a substitute for one named but unknown, which\n * {@link checkPlanInvariants} refuses;\n * - an AI task's prompt is its own, else its description, else its title, so\n * it is never unschedulable;\n * - the assignment — model, effort, and the mode decided from read-only or\n * not, never named (ADR-0031) — is the resolver's (`resolveAssignment`),\n * as it is for every writer: a model a merge or split carries is read as\n * what the task was made from, so a part moved to another runner gets that\n * runner's;\n * - an AI subtask with no slice classification takes its parent's: an `ai`\n * sub-step of an AFK slice is AFK. Not a blanket default, which would strip\n * a human gate the planner intended; a manual subtask must still say HITL.\n */\nexport function plannedTask(spec: unknown, catalog: IntakeCatalog, at: Placement = {}): PlannedTask {\n const raw = isRecord(spec) ? spec : {};\n const { parent, from, freshIds, newId = uuidv4 } = at;\n const base = from?.fields ?? {};\n const errors: PlanTaskError[] = [];\n const ignored: PlanTaskError[] = [];\n const renamed = new Map<string, string>();\n const adjustments: AssignmentAdjustment[] = [];\n\n const title = text(raw.title) ?? '';\n const where = taskWhere(title, parent?.title);\n const plannerId = text(raw.id);\n const id = freshIds || !plannerId ? newId() : plannerId;\n if (freshIds && plannerId) renamed.set(plannerId, id);\n\n const delegating = catalog.delegationRefusal === null;\n const type: Task['type'] = raw.type === 'user' || raw.type === 'ai' || raw.type === 'script' || raw.type === 'delegated' ? raw.type : base.type ?? 'ai';\n const ai = type === 'ai';\n const script = type === 'script';\n const delegated = type === 'delegated';\n // A read-only script exists for a delegated task's check (ADR-0055 D8), so where nothing can delegate it reads as it always did.\n const sealedScript = script && (catalog.sealsScripts?.({ ...(Array.isArray(raw.commands) ? { commands: raw.commands as string[][] } : {}), ...(typeof raw.script === 'string' ? { script: raw.script } : {}), ...(typeof raw.timeoutMs === 'number' ? { timeoutMs: raw.timeoutMs } : {}) }) === true || (delegating && raw.readOnly === true));\n const assignedRunner = text(raw.assignedRunner) ?? base.assignedRunner ?? catalog.runners[0] ?? DEFAULT_RUNNERS[0];\n const description = text(raw.description) ?? base.description ?? title;\n\n // What it may not have is refused rather than dropped: a prompt left on a\n // script, or a runner named for it, says the planner meant something else.\n const notScripts = script ? notOnAScript(raw).filter((f) => !(sealedScript && f === 'readOnly')) : [];\n if (notScripts.length > 0) errors.push({ taskId: id, field: notScripts[0], message: `${where} ${notOnAScriptMessage(notScripts)}` });\n if (delegated) {\n if (!delegating) errors.push({ taskId: id, field: 'type', message: catalog.delegationRefusal ?? `${where} is a delegated task, and ${DELEGATION_UNAVAILABLE}.` });\n const extra = notOnADelegated(raw);\n if (extra.length > 0) errors.push({ taskId: id, field: extra[0], message: `${where} ${notOnADelegatedMessage(extra)}` });\n }\n // A body's shape is judged here, where it is still what the planner wrote: a Task holds only a well-formed one.\n const body = bodyFields(raw, base);\n const shapeErrors = scriptBodyErrors({ type, ...body.raw }).filter((e) => body.malformed.has(e.field));\n for (const e of shapeErrors) errors.push({ taskId: id, field: e.field, message: `${where} ${e.message}` });\n // Its body's references are kept as written: an edit resolves them against the plan, a submitted plan names its own ids.\n const loop = loopSpec(raw.loop);\n if ('error' in loop) errors.push({ taskId: id, field: 'loop', message: `${where} ${loop.error}` });\n // A manual task stores no ops flag, so this is the one place it can still be seen.\n if (raw.ops === true && !ai && !script) errors.push({ taskId: id, field: 'ops', message: `${where} ${opsPlacementRefusal(type, !!parent)}` });\n if (raw.taskMode !== undefined && !script && !delegated) ignored.push({ taskId: id, field: 'taskMode', message: `${where}: ${MODE_NOT_THE_PLANNERS}` });\n if (type === 'user' && raw.readOnly === true) ignored.push({ taskId: id, field: 'readOnly', message: `${where}: ${MANUAL_NOT_READ_ONLY}` });\n const ops = raw.ops !== undefined ? raw.ops === true : base.ops;\n if (ai && ops && raw.readOnly === true) ignored.push({ taskId: id, field: 'readOnly', message: `${where}: ${OPS_NOT_READ_ONLY}` });\n // A read-only task's subtasks run as tasks of their own, so they would\n // otherwise get write access the planner said the work must not have.\n const asked = typeof raw.readOnly === 'boolean' ? raw.readOnly : undefined;\n const readOnly = ai && !ops && (asked ?? from?.readOnly ?? parent?.readOnly ?? false);\n if (raw.research !== undefined && typeof raw.research !== 'boolean') errors.push({ taskId: id, field: 'research', message: `${where}: \"research\" must be a boolean` });\n\n const assignedModel = ai || delegated ? modelOf(raw, base.assignedModel) : undefined;\n const slice = (value: unknown): 'AFK' | 'HITL' | undefined => (value === 'AFK' || value === 'HITL' ? value : undefined);\n // Explicit child values always win; inheritance only fills a gap, and only for `ai` tasks.\n const autonomy = ai ? slice(raw.autonomy) ?? base.autonomy ?? parent?.autonomy : undefined;\n const sliceType = slice(raw.sliceType) ?? base.sliceType ?? (ai ? parent?.sliceType : undefined);\n\n const subtasks: Task[] = [];\n if (Array.isArray(raw.subtasks)) {\n for (const s of raw.subtasks) {\n const child = plannedTask(s, catalog, { parent: { title, sliceType, autonomy, readOnly }, freshIds, newId });\n subtasks.push(child.task);\n errors.push(...child.errors);\n ignored.push(...child.ignored);\n adjustments.push(...child.adjustments);\n for (const [was, now] of child.renamed) renamed.set(was, now);\n }\n }\n\n const fields = {\n id,\n order: Number(raw.order ?? 0),\n title,\n description,\n type,\n dependencies: Array.isArray(raw.dependencies) ? raw.dependencies.map(String) : base.dependencies ?? [],\n // What a merge or split carries over for a runner is nothing a script runs.\n prompt: script || delegated ? undefined : text(raw.prompt) || base.prompt || (ai ? description || title || undefined : undefined),\n userSteps: Array.isArray(raw.userSteps)\n ? raw.userSteps.map((s) => (isRecord(s) ? s : {})).map((s) => ({ order: Number(s.order ?? 0), instruction: String(s.instruction ?? ''), completed: false }))\n : base.userSteps,\n subtasks,\n assignedModel,\n assignedRunner,\n autonomy,\n sliceType,\n userStoriesCovered: Array.isArray(raw.userStoriesCovered) ? raw.userStoriesCovered.map(String) : base.userStoriesCovered,\n ops: script || delegated ? undefined : ops,\n research: typeof raw.research === 'boolean' ? raw.research : base.research,\n skills: script || delegated ? undefined : from ? inheritedSkills(raw.skills, base.skills) : skillNames(raw.skills),\n ...body.fields,\n ...('loop' in loop && loop.loop ? { loop: loop.loop } : {}),\n ...(delegated ? delegatedFields(raw, base) : {}),\n ...(sealedScript ? { readOnly: true as const } : {}),\n };\n let taskMode = script || delegated ? undefined : base.taskMode;\n let landedModel = assignedModel;\n if ((ai || delegated) && catalog.runners.includes(assignedRunner)) {\n const resolved = resolveAssignment({\n writer: catalog.models ? 'edit' : 'plan',\n task: { ...createTask(fields), taskMode },\n from: from ? { assignedRunner: base.assignedRunner ?? assignedRunner, assignedModel: base.assignedModel, taskMode: base.taskMode } : undefined,\n readOnly,\n catalog: { modelsByRunner: {}, ...catalog.models, runnerModes: catalog.runnerModes, autonomousDefault: catalog.autonomousDefault },\n });\n if (!resolved.ok) {\n // The planner names no mode: one it cannot have is about the read-only answer it gave (ADR-0031).\n errors.push({ taskId: id, field: resolved.field === 'taskMode' ? 'readOnly' : resolved.field, message: `${where}: ${resolved.error}` });\n } else {\n // A delegated task has no mode on the plan: a subplanner's is the planner's, and a repair's comes from its mandate (ADR-0055 D14).\n taskMode = delegated ? undefined : resolved.task.taskMode;\n landedModel = resolved.task.assignedModel;\n adjustments.push(...resolved.adjustments);\n }\n }\n // With no runner modes to read, `plan` is the guess that keeps a read-only task from writing.\n if (taskMode === undefined && readOnly && !catalog.runnerModes) taskMode = 'plan';\n\n const task = createTask({ ...fields, assignedModel: landedModel, taskMode });\n if (Array.isArray(raw.skills)) skillsAsked.set(task, raw.skills);\n return { task, errors, ignored, renamed, adjustments };\n}\n\n/** An AI task on a runner outside `runners`: what a plan accepted earlier is held to again where it lands, the runners enabled then being the ones that count. */\nexport function checkPlanRunners(tasks: readonly Task[], runners: readonly RunnerId[] | undefined): PlanTaskError[] {\n if (!runners) return [];\n return flattenTasksWithParents(tasks)\n .filter(({ task: t }) => (t.type === 'ai' || t.type === 'delegated') && !runners.includes(t.assignedRunner))\n .map(({ task: t, parent }) => ({\n taskId: t.id,\n field: 'assignedRunner',\n message: `${taskWhere(t.title, parent?.title)} has invalid assignedRunner \"${t.assignedRunner}\". Expected one of: ${runners.join(', ')}`,\n }));\n}\n\n/**\n * The rules a plan's tasks are held to together, subtasks included, whichever\n * route they arrived by and whoever wrote them, the planner or the user.\n * `runners` are the ones the writer may put a task on (`assignableRunners`),\n * any when undefined; with `runnerModes`, an ops task is held off its\n * runner's read-only mode. A script task (ADR-0035) runs exactly one\n * well-formed body, at the top level, and carries nothing a runner would read.\n * A loop (ADR-0045) keeps its body for its check alone, on an acyclic graph.\n */\nexport function checkPlanInvariants(\n tasks: readonly Task[],\n runners: readonly RunnerId[] | undefined,\n runnerModes?: Partial<Record<RunnerId, readonly RunnerModeInfo[]>>,\n delegation: Pick<DelegationRules, 'canSeal'> = {},\n): PlanTaskError[] {\n const rows = flattenTasksWithParents(tasks);\n const errors: PlanTaskError[] = [];\n const seen = new Set<string>();\n const body = new Set(tasks.flatMap((t) => t.loop?.body ?? []));\n for (const { task: t, parent } of rows) {\n const where = taskWhere(t.title, parent?.title);\n const fail = (field: string, message: string) => errors.push({ taskId: t.id, field, message });\n if (seen.has(t.id)) fail('id', `${where} has id \"${t.id}\", which another task in the plan has too: every task, subtasks included, needs an id of its own`);\n seen.add(t.id);\n if (t.research !== undefined && typeof t.research !== 'boolean') fail('research', `${where}: \"research\" must be a boolean`);\n // Research's approval exception is safe only under the shared read-only profile (ADR-0037 R1, R4).\n const readOnly = runnerModes ? taggedReadOnlyMode(runnerModes[t.assignedRunner]) : 'plan';\n if (t.research && (t.type !== 'ai' || parent !== null || t.ops || body.has(t.id)\n || readOnly === undefined || t.taskMode !== readOnly)) {\n fail('research', `${where}: research is only for top-level read-only AI tasks, never a loop's body`);\n }\n if (t.autonomy === 'AFK' && t.userSteps && t.userSteps.length > 0) {\n fail('userSteps', `${where} has autonomy \"AFK\" but contains userSteps. AFK tasks must not have user touchpoints.`);\n }\n if (t.type === 'user' && t.sliceType && t.sliceType !== 'HITL') {\n fail('sliceType', `User ${where} has sliceType \"${t.sliceType}\". User tasks must have sliceType \"HITL\".`);\n }\n const opsRefused = t.ops && t.type !== 'script' ? opsPlacementRefusal(t.type, parent !== null) : null;\n if (opsRefused) fail('ops', `${where} ${opsRefused}`);\n if (t.type === 'script') {\n // It runs at the workspace root on its own (ADR-0035): nothing hangs under it, and it hangs under nothing.\n if (parent !== null) fail('type', `${where} is a script task: only a top-level task can be one, as only a top-level task can be an ops task`);\n if (t.subtasks?.length) fail('subtasks', `${where} is a script task, which has no subtasks: make each step a command of its own, or a task of its own`);\n const extra = notAScriptsFields(t);\n if (extra.length > 0) fail(extra[0], `${where} ${notOnAScriptMessage(extra)}`);\n }\n if (t.type === 'delegated') {\n // Top-level like a script task, and its child plan's tasks are the child's own (ADR-0055 D1).\n if (parent !== null) fail('type', `${where} is a delegated task: only a top-level task can be delegated`);\n if (t.subtasks?.length) fail('subtasks', `${where} is a delegated task, which has no subtasks: its child plan's tasks are its child's own`);\n }\n for (const e of scriptBodyErrors(t)) fail(e.field, `${where} ${e.message}`);\n if (t.ops && t.taskMode !== undefined && t.taskMode === taggedReadOnlyMode(runnerModes?.[t.assignedRunner])) {\n fail('taskMode', `${where} is an ops task, which acts in the workspace, so it cannot use the read-only profile`);\n }\n }\n errors.push(...checkPlanRunners(tasks, runners));\n errors.push(...loopErrors(tasks));\n errors.push(...delegationErrors(tasks, { ...(runnerModes ? { runnerModes } : {}), ...delegation }));\n for (const { task: t, parent } of rows) {\n // Self-dependencies are reported with the cycle below, including its full path.\n for (const error of dependencyTargetErrors(tasks, t.id, t.dependencies.filter((id) => id !== t.id))) {\n errors.push({ taskId: t.id, field: 'dependencies', message: `${taskWhere(t.title, parent?.title)}: ${error}` });\n }\n }\n const cycle = findCycle(rows.map((r) => r.task));\n // Pinned to a task on the cycle: a plan whose only fault is a rule a task\n // breaks is worth naming back to the planner, not re-asking for as JSON.\n if (cycle) errors.push({ taskId: cycle[0].id, field: 'dependencies', message: `Dependency cycle detected: ${[...cycle, cycle[0]].map((t) => `\"${t.title}\"`).join(' → ')}` });\n return errors;\n}\n\n/** The tasks on one dependency cycle, in dependency order, or null when there is none. A self-dependency is a cycle of one. */\nexport function findCycle(tasks: readonly Task[]): Task[] | null {\n return findDependencyCycle(tasks);\n}\n\n/** The title of a task on a dependency cycle, or null when there is none. */\nexport function detectCycle(tasks: readonly Task[]): string | null {\n return findCycle(tasks)?.[0].title ?? null;\n}\n"],"mappings":";;;;;;;;;;;;AASO,IAAM,4BAA4B,KAAK;AAMvC,IAAM,wBAAwB,KAAK,KAAK;AAUxC,IAAM,qBAAqB,CAAC,YAAY,UAAU,WAAW;AAM7D,IAAM,uBAAuB,CAAC,iBAAiB,YAAY,UAAU,UAAU,aAAa,KAAK;AAKjG,SAAS,aAAa,MAAqC;AAChE,MAAI,KAAK,SAAS,YAAY,iBAAiB,IAAI,EAAE,SAAS,EAAG,QAAO;AACxE,QAAM,YAAY,KAAK,aAAa;AACpC,SAAO,KAAK,WAAW,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,GAAG,UAAU,IAAI,EAAE,QAAQ,KAAK,UAAU,IAAI,UAAU;AAClI;AAGO,SAAS,eAAe,GAAe,GAAwB;AACpE,SAAO,KAAK,UAAU,QAAQ,CAAC,CAAC,MAAM,KAAK,UAAU,QAAQ,CAAC,CAAC;AACjE;AAQO,SAAS,iBAAiB,QAAyB,OAAkC;AAC1F,QAAM,QAAQ,IAAI,IAAI,aAAa,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAChE,SAAO,aAAa,KAAK,EAAE,OAAO,CAAC,MAAM;AACvC,UAAM,MAAM,MAAM,IAAI,EAAE,EAAE;AAC1B,WAAO,QAAQ,WAAc,EAAE,SAAS,YAAY,IAAI,SAAS,aAAa,CAAC,eAAe,KAAK,CAAC;AAAA,EACtG,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE;AACpB;AAEA,SAAS,QAAQ,MAA2B;AAC1C,SAAO,KAAK,SAAS,WAAW,CAAC,KAAK,YAAY,MAAM,KAAK,UAAU,MAAM,KAAK,aAAa,yBAAyB,IAAI;AAC9H;AASO,SAAS,iBAAiB,MAA0H;AACzJ,MAAI,KAAK,SAAS,UAAU;AAC1B,WAAO,mBAAmB,OAAO,CAAC,MAAM,KAAK,CAAC,MAAM,MAAS,EAC1D,IAAI,CAAC,WAAW,EAAE,OAAO,SAAS,QAAQ,KAAK,yEAAyE,EAAE;AAAA,EAC/H;AACA,QAAM,SAA+C,CAAC;AACtD,QAAM,EAAE,UAAU,QAAQ,UAAU,IAAI;AACxC,MAAI,aAAa,UAAa,WAAW,QAAW;AAClD,WAAO,KAAK,EAAE,OAAO,YAAY,SAAS,2EAA2E,CAAC;AAAA,EACxH,WAAW,aAAa,UAAa,WAAW,QAAW;AACzD,WAAO,KAAK,EAAE,OAAO,YAAY,SAAS,4GAA4G,CAAC;AAAA,EACzJ;AACA,MAAI,aAAa,OAAW,QAAO,KAAK,GAAG,eAAe,QAAQ,CAAC;AACnE,MAAI,WAAW,WAAc,OAAO,WAAW,YAAY,CAAC,OAAO,KAAK,IAAI;AAC1E,WAAO,KAAK,EAAE,OAAO,UAAU,SAAS,kDAAkD,CAAC;AAAA,EAC7F;AACA,MAAI,cAAc,UAAa,EAAE,OAAO,cAAc,YAAY,OAAO,UAAU,SAAS,KAAK,YAAY,KAAK,aAAa,wBAAwB;AACrJ,WAAO,KAAK,EAAE,OAAO,aAAa,SAAS,mBAAmB,KAAK,UAAU,SAAS,CAAC,gEAAgE,qBAAqB,gCAAgC,CAAC;AAAA,EAC/M;AACA,SAAO;AACT;AAEA,SAAS,eAAe,UAAyD;AAC/E,QAAM,QAAQ;AACd,MAAI,CAAC,MAAM,QAAQ,QAAQ,KAAK,SAAS,WAAW,EAAG,QAAO,CAAC,EAAE,OAAO,YAAY,SAAS,8BAA8B,KAAK,GAAG,CAAC;AACpI,aAAW,CAAC,GAAG,IAAI,KAAK,SAAS,QAAQ,GAAG;AAC1C,UAAM,IAAI,IAAI;AACd,QAAI,CAAC,MAAM,QAAQ,IAAI,KAAK,CAAC,KAAK,MAAM,CAAC,SAAS,OAAO,SAAS,QAAQ,GAAG;AAC3E,aAAO,CAAC,EAAE,OAAO,YAAY,SAAS,eAAe,CAAC,kDAAkD,KAAK,GAAG,CAAC;AAAA,IACnH;AACA,QAAI,KAAK,WAAW,EAAG,QAAO,CAAC,EAAE,OAAO,YAAY,SAAS,eAAe,CAAC,yDAAyD,CAAC;AACvI,QAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAG,QAAO,CAAC,EAAE,OAAO,YAAY,SAAS,eAAe,CAAC,4DAA4D,CAAC;AAAA,EAC1I;AACA,SAAO,CAAC;AACV;AAGO,SAAS,kBAAkB,MAAiF;AACjH,SAAO,qBAAqB,OAAO,CAAC,MAAM;AACxC,UAAM,QAAQ,KAAK,CAAC;AACpB,WAAO,UAAU,UAAa,UAAU,SAAS,EAAE,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW;AAAA,EAC9F,CAAC;AACH;AAGO,SAAS,kBAAkB,SAAuC;AACvE,aAAW,SAAS,mBAAoB,KAAK,QAAQ,KAAK,MAAkB,KAAM,SAAQ,KAAK,IAAI;AACnG,SAAO;AACT;AAEA,IAAM,aAAa;AAQnB,IAAM,SAAS;AAQR,SAAS,YAAY,MAAiC;AAC3D,SAAO,KAAK,IAAI,UAAU,EAAE,KAAK,GAAG;AACtC;AAEA,SAAS,WAAW,MAAsB;AACxC,MAAI,WAAW,KAAK,IAAI,EAAG,QAAO;AAClC,MAAI,CAAC,OAAO,KAAK,IAAI,EAAG,QAAO,IAAI,KAAK,QAAQ,MAAM,OAAO,CAAC;AAC9D,SAAO,KAAK,CAAC,GAAG,IAAI,EAAE,IAAI,OAAO,EAAE,KAAK,EAAE,CAAC;AAC7C;AAEA,IAAM,UAAkC,EAAE,MAAM,QAAQ,KAAK,OAAO,MAAM,OAAO,MAAM,OAAO,KAAM,MAAM;AAE1G,SAAS,QAAQ,MAAsB;AACrC,SAAO,QAAQ,IAAI,MAAM,OAAO,KAAK,IAAI,IAAI,OAAO,IAAI,IAAI;AAC9D;AAEA,SAAS,OAAO,MAAsB;AACpC,QAAM,OAAO,KAAK,YAAY,CAAC,KAAK;AACpC,QAAM,MAAM,KAAK,SAAS,EAAE,EAAE,YAAY;AAC1C,SAAO,QAAQ,MAAO,MAAM,IAAI,SAAS,GAAG,GAAG,CAAC,KAAK,QAAQ,QAAS,MAAM,IAAI,SAAS,GAAG,GAAG,CAAC,KAAK,MAAM,IAAI,SAAS,GAAG,GAAG,CAAC;AACjI;AAQO,SAAS,eAAe,MAA0B;AACvD,QAAM,QAAQ,cAAc,OACxB,KAAK,SAAS,IAAI,WAAW,IAC7B,CAAC,KAAK,OAAO,QAAQ,qCAAqC,CAAC,SAAU,SAAS,UAAU,SAAS,QAAQ,SAAS,MAChH,OACA,OAAO,KAAK,YAAY,CAAC,KAAK,GAAG,SAAS,EAAE,EAAE,YAAY,EAAE,SAAS,GAAG,GAAG,CAAC,GAAI,CAAC;AACvF,SAAO,CAAC,GAAG,OAAO,IAAI,eAAe,cAAc,KAAK,SAAS,CAAC,GAAG,EAAE,KAAK,IAAI;AAClF;AAOO,SAAS,eAAe,MAA0B;AACvD,QAAM,OAAO,aAAa,IAAI;AAC9B,SAAO,OAAO,eAAe,IAAI,IAAI;AACvC;AAGO,SAAS,cAAc,IAAoB;AAChD,QAAM,QAA4B,CAAC,CAAC,MAAW,MAAM,GAAG,CAAC,KAAQ,QAAQ,GAAG,CAAC,KAAO,QAAQ,GAAG,CAAC,GAAG,aAAa,CAAC;AACjH,QAAM,CAAC,MAAM,IAAI,IAAI,MAAM,KAAK,CAAC,CAAC,IAAI,MAAM,KAAK,SAAS,CAAC,KAAK,MAAM,MAAM,SAAS,CAAC;AACtF,QAAM,IAAI,KAAK;AACf,SAAO,GAAG,CAAC,IAAI,IAAI,GAAG,MAAM,IAAI,KAAK,GAAG;AAC1C;;;ACnLO,IAAM,sBAAsB;AAG5B,IAAM,kBAAkB;AAoBxB,SAAS,YAAY,OAA+C;AACzE,SAAO,MAAM,aAAa;AAC5B;AAQA,SAAS,aAAa,OAA6B;AACjD,SAAO,MAAM,SAAS,YAAY,UAAU,MAAM,QAAQ,aAAa;AACzE;AAQO,SAAS,cAAc,OAA6B;AACzD,SAAO,CAAC,CAAC,MAAM,QAAQ,MAAM,WAAW,YAAY,aAAa,KAAK,KAAK,YAAY,KAAK,IAAI,MAAM,KAAK;AAC7G;AAGO,SAAS,YAAY,OAA6B;AACvD,SAAO,CAAC,CAAC,MAAM,QAAQ,MAAM,WAAW,YAAY,aAAa,KAAK,KAAK,YAAY,KAAK,KAAK,MAAM,KAAK;AAC9G;AAOO,SAAS,UAAU,OAA6B;AACrD,SAAO,MAAM,WAAW,eAAe,MAAM,WAAW,aAAa,YAAY,KAAK;AACxF;AAGO,SAAS,QAA6C,OAAqB,QAA+B;AAC/G,SAAO,MAAM,KAAK,CAAC,MAAM,EAAE,MAAM,KAAK,SAAS,MAAM,CAAC;AACxD;AAGO,SAAS,eAAoD,OAAqC;AACvG,QAAM,SAAS,oBAAI,IAAe;AAClC,aAAW,QAAQ,OAAO;AACxB,eAAW,MAAM,KAAK,MAAM,QAAQ,CAAC,EAAG,KAAI,CAAC,OAAO,IAAI,EAAE,EAAG,QAAO,IAAI,IAAI,IAAI;AAAA,EAClF;AACA,SAAO;AACT;AAGO,SAAS,OAAO,OAAoD,MAAiD;AAC1H,SAAO,CAAC,CAAC,KAAK,QAAQ,QAAQ,OAAO,KAAK,EAAE,MAAM;AACpD;AAEA,IAAM,QAAQ;AAEd,SAAS,cAAc,OAAwB;AAC7C,SAAO,mBAAmB,KAAK,UAAU,KAAK,CAAC,qCAAqC,eAAe,cAAc,mBAAmB;AACtI;AAEA,SAAS,aAAa,OAAiC;AACrD,SAAO,OAAO,UAAU,YAAY,OAAO,UAAU,KAAK,KAAK,SAAS,KAAK,SAAS;AACxF;AASO,SAAS,SAAS,OAAoE;AAC3F,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO,EAAE,MAAM,OAAU;AACpE,MAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,EAAG,QAAO,EAAE,OAAO,qBAAqB,KAAK,GAAG;AACpG,QAAM,EAAE,MAAM,UAAU,IAAI;AAC5B,MAAI,CAAC,MAAM,QAAQ,IAAI,KAAK,CAAC,KAAK,MAAM,CAAC,OAAO,OAAO,OAAO,YAAY,OAAO,OAAO,QAAQ,EAAG,QAAO,EAAE,OAAO,6BAA6B,KAAK,GAAG;AACxJ,MAAI,KAAK,WAAW,EAAG,QAAO,EAAE,OAAO,2EAA2E;AAClH,MAAI,cAAc,UAAa,CAAC,aAAa,SAAS,EAAG,QAAO,EAAE,OAAO,cAAc,SAAS,EAAE;AAClG,SAAO,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,MAAM,GAAG,WAAW,aAAa,oBAAoB,EAAE;AACzF;AAkBO,SAAS,WAAW,OAAqC;AAC9D,QAAM,OAAO,wBAAwB,KAAK;AAC1C,QAAM,OAAO,IAAI,IAAI,KAAK,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,IAAI,GAAG,CAAC,CAAC;AAC1D,QAAM,SAAsB,CAAC;AAC7B,QAAM,YAAY,oBAAI,IAAkB;AAExC,aAAW,EAAE,MAAM,OAAO,OAAO,KAAK,MAAM;AAC1C,UAAM,OAAO,MAAM;AACnB,QAAI,CAAC,KAAM;AACX,UAAM,QAAQ,SAAS,YAAY,MAAM,KAAK,SAAS,OAAO,KAAK,MAAM,SAAS,MAAM,KAAK;AAC7F,UAAM,OAAO,CAAC,YAAoB,OAAO,KAAK,EAAE,QAAQ,MAAM,IAAI,OAAO,QAAQ,SAAS,GAAG,KAAK,IAAI,OAAO,GAAG,CAAC;AACjH,QAAI,OAAQ,MAAK,+DAAgE;AACjF,QAAI,MAAM,SAAS,OAAQ,MAAK,2JAA4J;AAC5L,QAAI,MAAM,SAAS,YAAa,MAAK,8KAA+K;AACpN,QAAI,MAAM,UAAU,OAAQ,MAAK,0EAA2E;AAC5G,QAAI,CAAC,aAAa,KAAK,SAAS,EAAG,MAAK,cAAc,KAAK,SAAS,CAAC;AACrE,QAAI,CAAC,MAAM,QAAQ,KAAK,IAAI,KAAK,KAAK,KAAK,WAAW,EAAG,MAAK,0EAA0E;AACxI,UAAM,QAAQ,oBAAI,IAAY;AAC9B,eAAW,MAAM,KAAK,QAAQ,CAAC,GAAG;AAChC,YAAM,MAAM,KAAK,IAAI,EAAE;AACvB,UAAI,MAAM,IAAI,EAAE,GAAG;AAAE,aAAK,UAAU,KAAK,KAAK,SAAS,EAAE,8BAA8B;AAAG;AAAA,MAAU;AACpG,YAAM,IAAI,EAAE;AACZ,UAAI,CAAC,KAAK;AAAE,aAAK,UAAU,EAAE,sDAAsD;AAAG;AAAA,MAAU;AAChG,YAAM,OAAO,IAAI;AACjB,UAAI,KAAK,OAAO,MAAM,IAAI;AAAE,aAAK,iFAAkF;AAAG;AAAA,MAAU;AAChI,UAAI,IAAI,QAAQ;AAAE,aAAK,kBAAkB,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,uEAAuE;AAAG;AAAA,MAAU;AAChK,YAAM,QAAQ,UAAU,IAAI,EAAE;AAC9B,UAAI,OAAO;AAAE,aAAK,UAAU,KAAK,KAAK,oDAAoD,MAAM,KAAK,+CAA+C;AAAG;AAAA,MAAU;AACjK,gBAAU,IAAI,IAAI,KAAK;AACvB,UAAI,KAAK,KAAM,MAAK,UAAU,KAAK,KAAK,yFAAyF;AACjI,UAAI,KAAK,SAAS,OAAQ,MAAK,sBAAsB,KAAK,KAAK,4FAA4F;AAC3J,UAAI,KAAK,SAAS,YAAa,MAAK,yBAAyB,KAAK,KAAK,uFAAuF;AAC9J,UAAI,KAAK,UAAU,OAAQ,MAAK,UAAU,KAAK,KAAK,2HAA2H;AAAA,IACjL;AAAA,EACF;AAEA,aAAW,CAAC,QAAQ,KAAK,KAAK,WAAW;AACvC,UAAM,OAAO,KAAK,IAAI,MAAM,EAAG;AAC/B,UAAM,QAAQ,SAAS,KAAK,KAAK,wBAAwB,MAAM,KAAK;AACpE,QAAI,CAAC,KAAK,aAAa,SAAS,MAAM,EAAE,GAAG;AACzC,aAAO,KAAK,EAAE,QAAQ,KAAK,IAAI,OAAO,gBAAgB,SAAS,GAAG,KAAK,uBAAuB,MAAM,KAAK,gDAAgD,MAAM,KAAK,wBAAwB,CAAC;AAAA,IAC/L;AACA,eAAW,OAAO,KAAK,cAAc;AACnC,UAAI,QAAQ,MAAM,MAAM,MAAM,aAAa,SAAS,GAAG,KAAK,UAAU,IAAI,GAAG,MAAM,MAAO;AAC1F,aAAO,KAAK,EAAE,QAAQ,KAAK,IAAI,OAAO,gBAAgB,SAAS,GAAG,KAAK,4BAA4B,MAAM,KAAK,eAAe,MAAM,KAAK,kDAAkD,KAAK,IAAI,GAAG,GAAG,KAAK,SAAS,GAAG,qBAAqB,CAAC;AAAA,IAClP;AAAA,EACF;AAEA,aAAW,EAAE,KAAK,KAAK,MAAM;AAC3B,eAAW,OAAO,KAAK,cAAc;AACnC,YAAM,QAAQ,UAAU,IAAI,GAAG;AAC/B,UAAI,CAAC,SAAS,UAAU,IAAI,KAAK,EAAE,MAAM,MAAO;AAChD,YAAM,OAAO,KAAK,IAAI,GAAG,EAAG;AAC5B,YAAM,UAAU,KAAK,OAAO,MAAM,KAC9B,SAAS,KAAK,KAAK,iBAAiB,KAAK,KAAK,+FAC9C,SAAS,KAAK,KAAK,iBAAiB,KAAK,KAAK,+BAA+B,MAAM,KAAK,8BAA8B,MAAM,KAAK,uBAAuB,MAAM,KAAK;AACvK,aAAO,KAAK,EAAE,QAAQ,KAAK,IAAI,OAAO,gBAAgB,QAAQ,CAAC;AAAA,IACjE;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,mBAAmB,MAAmD;AACpF,SAAO,KAAK,OAAO,IAAI,KAAK,KAAK,uHAAuH;AAC1J;AAGO,SAAS,mBAAmB,OAAoD,QAAsD,QAA2C;AAEtL,MAAI,OAAO,SAAS,YAAa,QAAO,IAAI,OAAO,KAAK,uCAAuC,MAAM;AACrG,MAAI,OAAO,KAAM,QAAO,IAAI,OAAO,KAAK,qCAAqC,MAAM;AACnF,SAAO,QAAQ,OAAO,OAAO,EAAE,IAAI,IAAI,OAAO,KAAK,uCAAuC,MAAM,oCAAoC;AACtI;;;AC/MA,IAAM,SAAS;AACf,IAAM,aAAa,IAAI,OAAO,WAAW,MAAM,GAAG;AAG3C,IAAM,WAAW,IAAI,OAAO,MAAM,MAAM,KAAK;AAE7C,SAAS,WAAWA,OAAwB;AACjD,SAAOA,MAAK,MAAM,UAAU;AAC9B;AAGO,SAAS,WAAWA,OAAsB;AAC/C,SAAO,KAAK,UAAUA,KAAI,EAAE,QAAQ,yBAAyB,CAAC,SAAS,MAAM,KAAK,WAAW,CAAC,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE;AACjI;AAGO,SAAS,UAAUA,OAAsB;AAC9C,SAAO,SAAS,KAAKA,KAAI,IAAIA,QAAO,WAAWA,KAAI;AACrD;;;ACtBO,IAAM,oBAAoB;AAE1B,IAAM,wBAAwB;AAE9B,IAAM,0BAA0B;AAGhC,IAAM,iBAAN,cAA6B,MAAM;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA,EACT,YAAY,SAAiB,KAAa,MAAoD;AAC5F,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,MAAM;AACX,SAAK,YAAY,MAAM,aAAa;AACpC,SAAK,WAAW,MAAM,YAAY;AAAA,EACpC;AACF;AAQO,SAAS,gBAAgB,KAAqB;AACnD,SAAO,IACJ,QAAQ,8BAA8B,EAAE,EACxC,QAAQ,gBAAgB,EAAE,EAC1B,QAAQ,WAAW,EAAE,EACrB,KAAK;AACV;AAEA,IAAM,aAAa;AACnB,IAAM,cAAc;AACpB,IAAM,QAAQ;AACd,IAAM,iBAAiB;AAShB,SAAS,oBAAoB,QAAqC;AACvE,MAAI,OAAO;AACX,aAAS;AACP,WAAO,KAAK,UAAU;AACtB,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,OAAO,KAAK,MAAM,GAAG,WAAW,MAAM,EAAE,YAAY;AAC1D,QAAI,SAAS,YAAY;AACvB,YAAM,QAAQ,KAAK,YAAY,EAAE,QAAQ,WAAW;AACpD,UAAI,QAAQ,EAAG,QAAO;AACtB,aAAO,KAAK,MAAM,QAAQ,YAAY,MAAM;AAC5C;AAAA,IACF;AACA,QAAI,KAAK,WAAW,KAAK,GAAG;AAC1B,aAAO,KAAK,MAAM,MAAM,MAAM;AAC9B,YAAM,MAAM,KAAK,MAAM,GAAG,eAAe,MAAM,EAAE,YAAY;AAC7D,UAAI,QAAQ,eAAgB,QAAO,KAAK,MAAM,eAAe,MAAM;AAAA,eAC1D,QAAQ,KAAK,YAAY,KAAK,eAAe,WAAW,GAAG,EAAG,QAAO;AAC9E;AAAA,IACF;AACA,QAAI,WAAW,WAAW,IAAI,KAAK,MAAM,WAAW,IAAI,EAAG,QAAO;AAClE,WAAO,KAAK,WAAW,GAAG;AAAA,EAC5B;AACF;AAOA,SAAS,iBAAiBC,OAAc,OAAoD;AAC1F,MAAI,QAAQ;AACZ,MAAI,WAAW;AACf,MAAIC,WAAU;AACd,WAAS,IAAI,OAAO,IAAID,MAAK,QAAQ,KAAK;AACxC,UAAM,KAAKA,MAAK,CAAC;AACjB,QAAI,UAAU;AACZ,UAAIC,SAAS,CAAAA,WAAU;AAAA,eACd,OAAO,KAAM,CAAAA,WAAU;AAAA,eACvB,OAAO,IAAK,YAAW;AAChC;AAAA,IACF;AACA,QAAI,OAAO,IAAK,YAAW;AAAA,aAClB,OAAO,IAAK;AAAA,aACZ,OAAO,KAAK;AACnB;AACA,UAAI,UAAU,EAAG,QAAO,EAAE,MAAMD,MAAK,MAAM,OAAO,IAAI,CAAC,GAAG,UAAU,KAAK;AAAA,IAC3E;AAAA,EACF;AACA,SAAO,EAAE,MAAMA,MAAK,MAAM,KAAK,GAAG,UAAU,MAAM;AACpD;AAWO,SAAS,sBAAsB,KAAa,KAMjD;AACA,QAAM,WAAW,gBAAgB,GAAG;AACpC,QAAM,QAAQ,IAAI,OAAO,IAAI,GAAG,QAAQ;AAExC,QAAM,UAAoB,CAAC;AAC3B,MAAI,cAA6B;AACjC,MAAI,WAAW;AACf,MAAI,gBAAgB;AACpB,MAAI,WAAW;AACf,MAAIC,WAAU;AACd,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,UAAM,KAAK,SAAS,CAAC;AACrB,QAAI,UAAU;AACZ,UAAIA,SAAS,CAAAA,WAAU;AAAA,eACd,OAAO,KAAM,CAAAA,WAAU;AAAA,eACvB,OAAO,IAAK,YAAW;AAChC;AAAA,IACF;AACA,QAAI,OAAO,KAAK;AAAE,iBAAW;AAAM;AAAA,IAAU;AAC7C,QAAI,OAAO,IAAK;AAEhB,eAAW;AACX,UAAM,MAAM,iBAAiB,UAAU,CAAC;AAGxC,QAAI,IAAI,YAAY,MAAM,KAAK,IAAI,IAAI,GAAG;AACxC,cAAQ,KAAK,IAAI,IAAI;AACrB,WAAK,IAAI,KAAK,SAAS;AACvB;AAAA,IACF;AACA,QAAI,CAAC,IAAI,SAAU,iBAAgB;AACnC,QAAI,CAAC,eAAe,IAAI,SAAU,eAAc,IAAI;AAAA,EACtD;AAEA,SAAO;AAAA,IACL;AAAA,IACA,UAAU,gBAAgB,OAAO,EAAE,MAAM,aAAa,UAAU,KAAK,IAAI,EAAE,MAAM,UAAU,UAAU,MAAM;AAAA,IAC3G;AAAA,IACA;AAAA,EACF;AACF;AAUO,SAAS,yBAAyB,KAAqE;AAC5G,QAAM,EAAE,SAAS,UAAU,SAAS,IAAI,sBAAsB,KAAK,iBAAiB;AACpF,MAAI,QAAQ,SAAS,EAAG,QAAO,EAAE,MAAM,QAAQ,CAAC,GAAG,UAAU,MAAM,SAAS;AAC5E,SAAO,EAAE,GAAG,UAAU,SAAS;AACjC;AAQO,SAAS,kBAAkB,KAAqB;AACrD,SAAO,yBAAyB,GAAG,EAAE;AACvC;AAGO,SAAS,oBAAoB,MAAsB;AACxD,SAAO,KAAK,QAAQ,gBAAgB,IAAI;AAC1C;AAQO,SAAS,4BAA4B,MAAsB;AAChE,MAAI,MAAM;AACV,MAAI,WAAW;AACf,MAAIA,WAAU;AACd,aAAW,MAAM,MAAM;AACrB,QAAI,UAAU;AACZ,UAAIA,UAAS;AAAE,eAAO;AAAI,QAAAA,WAAU;AAAO;AAAA,MAAU;AACrD,UAAI,OAAO,MAAM;AAAE,eAAO;AAAI,QAAAA,WAAU;AAAM;AAAA,MAAU;AACxD,UAAI,OAAO,KAAK;AAAE,eAAO;AAAI,mBAAW;AAAO;AAAA,MAAU;AACzD,UAAI,OAAO,MAAM;AAAE,eAAO;AAAO;AAAA,MAAU;AAC3C,UAAI,OAAO,MAAM;AAAE,eAAO;AAAO;AAAA,MAAU;AAC3C,UAAI,OAAO,KAAM;AAAE,eAAO;AAAO;AAAA,MAAU;AAC3C,aAAO;AACP;AAAA,IACF;AACA,QAAI,OAAO,IAAK,YAAW;AAC3B,WAAO;AAAA,EACT;AACA,SAAO;AACT;;;ACjMO,SAAS,gBAAgB,UAA0B,SAAyD;AACjH,SAAO,OAAO,YAAY,QAAQ,IAAI,CAAC,MAAM,CAAC,GAAG,SAAS,YAAY,CAAC,GAAG,SAAS,CAAC,CAAC,CAAU,CAAC;AAClG;AAQO,SAAS,mBACd,OACA,oBAAoB,OACA;AACpB,MAAI,CAAC,SAAS,MAAM,WAAW,EAAG,QAAO;AACzC,QAAM,MAA6B,oBAAoB,eAAe;AACtE,QAAM,SAAS,MAAM,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC;AACvC,MAAI,OAAQ,QAAO,OAAO;AAC1B,WAAS,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK;AAC1C,QAAI,CAAC,MAAM,CAAC,EAAE,YAAY,MAAM,CAAC,EAAE,OAAO,OAAQ,QAAO,MAAM,CAAC,EAAE;AAAA,EACpE;AACA,SAAO;AACT;AAGO,SAAS,mBAAmB,YAAyC;AAC1E,SAAO,aAAa,SAAS;AAC/B;AAGO,SAAS,mBAAmB,KAAyC;AAC1E,UAAQ,KAAK,KAAK,EAAE,YAAY,GAAG;AAAA,IACjC,KAAK;AAAA,IAAQ,KAAK;AAAM,aAAO;AAAA,IAC/B,KAAK;AAAA,IAAW,KAAK;AAAA,IAAQ,KAAK;AAAO,aAAO;AAAA,IAChD;AAAS,aAAO;AAAA,EAClB;AACF;AAQO,SAAS,kBAAkB,OAAgD;AAChF,QAAM,aAAa,OAAO,KAAK,EAAE,YAAY;AAC7C,MAAI,CAAC,WAAY,QAAO;AACxB,MAAI,eAAe,UAAU,eAAe,IAAK,QAAO;AACxD,MAAI,eAAe,WAAW,eAAe,IAAK,QAAO;AACzD,SAAO,mBAAmB,UAAU,KAAK;AAC3C;AAQO,SAAS,mBAAmB,OAAkE;AACnG,SAAO,OAAO,KAAK,CAAC,MAAM,EAAE,QAAQ,GAAG;AACzC;AAGO,SAAS,aAAa,OAAkE;AAC7F,QAAM,OAAO,OAAO,KAAK,CAAC,MAAM,EAAE,QAAQ;AAC1C,SAAO,QAAQ,CAAC,KAAK,cAAc,KAAK,KAAK;AAC/C;AAGO,SAAS,sBAAsB,OAA8C,IAA4C;AAC9H,SAAO,OAAO,SAAY,SAAY,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG;AACzE;AAEA,SAAS,qBAAqB,QAAkB,IAAY,QAAwB;AAClF,SAAO,SAAS,EAAE,gBAAgB,MAAM,kCAAkC,MAAM;AAClF;AAGO,SAAS,2BACd,UACA,MACoB;AACpB,QAAM,SAAS,sBAAsB,SAAS,OAAO,IAAI;AACzD,SAAO,SAAS,SAAS,IAAI,QAAQ,SAAS,WAAW,iCAAiC,MAAM,KAAK;AACvG;AAkBO,SAAS,YACd,QACA,aACA,EAAE,UAAU,QAAQ,GACpB,oBAAoB,OACP;AACb,MAAI,CAAC,YAAa,QAAO,EAAE,IAAI,MAAM,MAAM,OAAU;AACrD,QAAM,QAAQ,YAAY,MAAM,KAAK,CAAC;AACtC,QAAM,aAAa,aAAa,KAAK;AACrC,MAAI,aAAa,MAAM;AACrB,QAAI,WAAY,QAAO,EAAE,IAAI,MAAM,MAAM,WAAW;AACpD,UAAM,OAAO,gBAAgB,WAAW;AACxC,UAAMC,UAAS,sBAAsB,OAAO,mBAAmB,KAAK,CAAC;AACrE,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,OAAO,WAAW,MAAM,0BAA0BA,UAAS,4BAA4B,EAAE,gCAAgC,KAAK,SAAS,IAAI,WAAW,KAAK,KAAK,IAAI,CAAC,KAAK,gDAAgD,uBAAuBA,UAAS,KAAKA,OAAM,KAAK,EAAE;AAAA,IAC9Q;AAAA,EACF;AACA,QAAM,OAAO,YAAY,UAAa,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO,KAAK,EAAE,aAAa,SAAS,YAAY,mBAAmB,KAAK;AACzI,QAAM,OAAO,OAAO,UAAU,mBAAmB,OAAO,iBAAiB;AAGzE,QAAM,SAAS,sBAAsB,OAAO,IAAI;AAChD,MAAI,SAAS,UAAa,OAAQ,QAAO,EAAE,IAAI,OAAO,OAAO,qBAAqB,QAAQ,MAAM,MAAM,EAAE;AACxG,SAAO,EAAE,IAAI,MAAM,KAAK;AAC1B;AASO,SAAS,kBACd,QACA,SACA,SACQ;AACR,QAAM,QAAQ,IAAI,IAAI,aAAa,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAChE,QAAM,QAAQ,CAAC,MAAkB;AAC/B,UAAM,YAAY,EAAE,YAAY,CAAC,GAAG,IAAI,KAAK;AAC7C,UAAM,MAAM,MAAM,IAAI,EAAE,EAAE;AAC1B,QAAI,EAAE,SAAS,QAAQ,CAAC,OAAO,IAAI,SAAS,QAAQ,EAAE,aAAa,mBAAmB,QAAQ,YAAY,EAAE,cAAc,CAAC,EAAG,QAAO,EAAE,GAAG,GAAG,SAAS;AACtJ,UAAM,OAAO,YAAY,EAAE,gBAAgB,QAAQ,aAAa,EAAE,UAAU,OAAO,SAAS,IAAI,SAAS,GAAG,QAAQ,qBAAqB,KAAK;AAC9I,WAAO,EAAE,GAAG,GAAG,UAAU,GAAI,KAAK,MAAM,KAAK,SAAS,SAAY,EAAE,UAAU,KAAK,KAAK,IAAI,CAAC,EAAG;AAAA,EAClG;AACA,SAAO,QAAQ,IAAI,KAAK;AAC1B;AAGO,SAAS,gBAAgB,aAA+E;AAC7G,SAAO,OAAO,QAAQ,WAAW,EAAE,OAAO,CAAC,CAAC,EAAE,EAAE,MAAM,aAAa,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE;AAC1F;;;AC/JO,SAAS,mBACd,WACA,QACA,gBACsB;AACtB,MAAI,CAAC,aAAa,UAAU,WAAW,EAAG,QAAO;AACjD,MAAI,CAAC,eAAgB,QAAO;AAE5B,QAAM,MAAM,IAAI,KAAK,eAAe,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;AACxE,QAAM,YAAY,oBAAI,IAAY;AAClC,aAAW,CAAC,OAAO,MAAM,KAAK,OAAO,QAAQ,cAAc,GAAG;AAC5D,QAAI,UAAU,OAAQ;AACtB,eAAW,KAAK,UAAU,CAAC,EAAG,WAAU,IAAI,EAAE,OAAO;AAAA,EACvD;AAEA,QAAM,OAAO,UAAU,OAAO,CAAC,OAAO,IAAI,IAAI,EAAE,KAAK,CAAC,UAAU,IAAI,EAAE,CAAC;AACvE,SAAO,KAAK,SAAS,IAAI,OAAO;AAClC;AAEO,SAAS,sBACd,gBACA,oBAC8C;AAC9C,QAAM,SAAuD,CAAC;AAC9D,aAAW,CAAC,QAAQ,MAAM,KAAK,OAAO,QAAQ,cAAc,GAAG;AAC7D,QAAI,CAAC,OAAQ;AACb,UAAM,UAAU,mBAAmB,mBAAmB,MAAM,GAAG,QAAQ,cAAc;AACrF,QAAI,CAAC,SAAS;AACZ,aAAO,MAAM,IAAI;AACjB;AAAA,IACF;AACA,UAAM,aAAa,IAAI,IAAI,OAAO;AAClC,UAAM,eAAe,OAAO,OAAO,CAAC,MAAM,WAAW,IAAI,EAAE,OAAO,CAAC;AAInE,UAAM,UAAU,IAAI,IAAI,aAAa,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;AAC1D,UAAM,UAAU,QACb,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,EAC/B,IAAI,CAAC,QAAQ,EAAE,SAAS,IAAI,YAAY,GAAG,MAAM,GAAG,EAAE,IAAI,KAAK,IAAI,UAAU,CAAC,EAAE,EAAE;AACrF,WAAO,MAAM,IAAI,CAAC,GAAG,cAAc,GAAG,OAAO;AAAA,EAC/C;AACA,SAAO;AACT;AAGA,IAAM,gBAAgB,CAAC,QAAQ,WAAW,OAAO,UAAU,QAAQ,SAAS,OAAO,OAAO;AAE1F,IAAM,iBAAyC,EAAE,UAAU,QAAQ,UAAU,SAAS;AAY/E,SAAS,oBACd,QACA,UACoB;AACpB,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,SAAS,WAAW,EAAG,QAAO;AAClC,QAAM,MAAM,IAAI,IAAI,SAAS,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AAC7C,MAAI,IAAI,IAAI,MAAM,EAAG,QAAO;AAC5B,QAAM,QAAQ,eAAe,MAAM,KAAK;AACxC,MAAI,IAAI,IAAI,KAAK,EAAG,QAAO;AAC3B,QAAM,MAAM,cAAc,QAAQ,KAAK;AACvC,MAAI,MAAM,EAAG,QAAO;AACpB,WAAS,IAAI,GAAG,IAAI,cAAc,QAAQ,KAAK;AAC7C,UAAM,QAAQ,cAAc,MAAM,CAAC;AACnC,QAAI,SAAS,IAAI,IAAI,KAAK,EAAG,QAAO;AACpC,UAAM,SAAS,cAAc,MAAM,CAAC;AACpC,QAAI,UAAU,IAAI,IAAI,MAAM,EAAG,QAAO;AAAA,EACxC;AACA,SAAO;AACT;;;AC3FO,IAAM,SAAS,CAAC,WAAW,SAAS,WAAW,UAAU,WAAW,YAAY,UAAU,YAAY,OAAO;AAM7G,IAAM,eAAiC,CAAC,WAAW,SAAS,WAAW,UAAU,WAAW,OAAO;AAGnG,IAAM,eAAe;AAAA,EAC1B,OAAO,EAAE,SAAS,GAAG,MAAM,EAAE;AAAA,EAC7B,gBAAgB,EAAE,SAAS,GAAG,MAAM,GAAG;AAAA,EACvC,cAAc,EAAE,SAAS,IAAI,MAAM,IAAI;AACzC;AAGO,IAAM,8BAA8B,KAAK,KAAK,KAAK;AA6EnD,SAAS,mBAAmB,EAAE,OAAO,OAAO,OAAO,MAAM,GAA2B;AACzF,SAAO,SAAS,KAAK,YAAY,KAAK,WAAW,KAAK,kBAAkB,KAAK;AAC/E;AAGA,IAAM,eAA0D;AAAA,EAC9D,KAAK,CAAC,UAAU;AAAA,EAChB,OAAO,CAAC,WAAW,UAAU;AAAA,EAC7B,KAAK,CAAC,WAAW,SAAS,WAAW,UAAU,YAAY,OAAO;AACpE;AAGA,IAAM,mBAAqC,CAAC,GAAG,cAAc,YAAY,UAAU;AAO5E,SAAS,YAAY,UAAiC;AAC3D,QAAM,UAAU,SAAS,SAAS,MAAM,UAAU,KAAK;AACvD,QAAM,aAAa,SAAS,mBAAmB;AAC/C,QAAM,cAAc,SAAS,UAAU,CAAC,SAAS,OAAO,IAAI,CAAC;AAC7D,SAAO;AAAA,IACL,QAAQ,oBAAI,IAAW;AAAA,MACrB,GAAG,aAAa,SAAS,KAAK;AAAA,MAC9B,GAAI,SAAS,UAAU,CAAC,SAAkB,IAAI,CAAC;AAAA,MAC/C,GAAI,SAAS,CAAC,QAAiB,IAAI,CAAC;AAAA,MACpC,GAAI,aAAa,CAAC,UAAmB,IAAI,CAAC;AAAA,IAC5C,CAAC;AAAA,IACD,WAAW,IAAI,IAAW,aAAa,CAAC,GAAG,kBAAkB,GAAI,SAAS,CAAC,QAAiB,IAAI,CAAC,CAAE,IAAI,CAAC,CAAC;AAAA,IACzG,UAAU,SAAS,aAAa,SAAS;AAAA,IACzC,QAAQ;AAAA,MACN,QAAQ,SAAS;AAAA,MACjB,aAAa;AAAA,MACb,OAAO,aAAa,MAAM;AAAA,MAC1B,gBAAgB,aAAa,eAAe;AAAA,MAC5C,cAAc,aAAa,aAAa;AAAA,MACxC,SAAS,SAAS;AAAA,MAClB,QAAQ,SAAS;AAAA,IACnB;AAAA,IACA,YAAY,EAAE,gBAAgB,CAAC,EAAE;AAAA,IACjC;AAAA,IACA,gBAAgB;AAAA,EAClB;AACF;AASO,SAAS,YAAY,OAAgB,WAAwC;AAClF,QAAM,SAAS,CAAC,WAA+B,IAAI,IAAI,CAAC,GAAG,MAAM,EAAE,OAAO,CAAC,UAAU,UAAU,MAAM,CAAC,aAAa,SAAS,UAAU,IAAI,KAAK,CAAC,CAAC,CAAC;AAClJ,QAAM,cAAc,CAAC,GAAG,UAAU,QAAQ,CAAC,aAAa,SAAS,WAAW,GAAG,GAAG,MAAM,cAAc;AACtG,SAAO,EAAE,GAAG,OAAO,QAAQ,OAAO,MAAM,MAAM,GAAG,WAAW,OAAO,MAAM,SAAS,GAAG,YAAY;AACnG;AAMA,IAAM,SAAS,CAAC,WAAoC,CAAC,GAAG,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI,KAAK;AAErF,IAAM,SAAS,CAAC,UAA6C,CAAC,QAAuB,YAA2C;AAC9H,QAAM,EAAE,KAAK,IAAI,aAAa,KAAK;AACnC,QAAM,QAAQ,QAAQ,KAAK;AAC3B,MAAI,UAAU,UAAa,QAAQ,KAAM,QAAO,EAAE,SAAS,EAAE,OAAO,UAAU,KAAK,IAAI,OAAO,OAAO,KAAK,GAAG,OAAO,mBAAmB,IAAI,GAAG,EAAE;AAChJ,SAAO,EAAE,OAAO,KAAK,IAAI,OAAO,KAAK,GAAG,SAAS,OAAO,KAAK,CAAC,EAAE;AAClE;AAEA,SAAS,gBAAgB,QAAiC,QAAiC,CAAC,GAA4B;AACtH,QAAM,SAA8C,EAAE,GAAG,OAAO,GAAG,OAAO;AAC1E,aAAW,UAAU,OAAO,KAAK,MAAM,GAAG;AACxC,QAAI,MAAM,MAAM,EAAG,QAAO,MAAM,IAAI,OAAO,MAAM,EAAE,OAAO,CAAC,UAAU,MAAM,MAAM,EAAE,SAAS,KAAK,CAAC;AAAA,EACpG;AACA,SAAO;AACT;AAEA,IAAM,cAAmD;AAAA,EACvD,QAAQ,CAAC,EAAE,OAAO,GAAG,EAAE,QAAQ,MAAM,MAAM;AACzC,QAAI,UAAU,UAAa,SAAS,KAAK,QAAQ,OAAQ,QAAO,EAAE,SAAS,EAAE,OAAO,iBAAiB,OAAO,UAAU,SAAY,SAAS,OAAO,KAAK,GAAG,OAAO,OAAO,MAAM,EAAE,EAAE;AAClL,WAAO,EAAE,OAAO,MAAM;AAAA,EACxB;AAAA,EACA,aAAa,CAAC,EAAE,aAAa,KAAK,GAAG,EAAE,aAAa,MAAM,MAAM;AAC9D,QAAI,UAAU,OAAW,QAAO,EAAE,OAAO,SAAS,OAAO,8BAA8B,KAAK,IAAI,MAAM,2BAA2B,EAAE;AACnI,QAAI,SAAS,KAAM,SAAS,QAAQ,QAAQ,KAAO,QAAO,EAAE,SAAS,EAAE,OAAO,sBAAsB,OAAO,OAAO,KAAK,GAAG,OAAO,SAAS,OAAO,aAAa,OAAO,IAAI,EAAE,EAAE;AAC7K,WAAO,EAAE,OAAO,MAAM;AAAA,EACxB;AAAA,EACA,OAAO,CAAC,EAAE,MAAM,GAAG,EAAE,OAAO,MAAM,MAAM;AACtC,QAAI,SAAS,EAAG,QAAO,EAAE,SAAS,EAAE,OAAO,gBAAgB,OAAO,WAAW,OAAO,gBAAgB,EAAE;AACtG,UAAM,EAAE,KAAK,IAAI,aAAa;AAC9B,QAAI,UAAU,UAAa,QAAQ,KAAM,QAAO,EAAE,SAAS,EAAE,OAAO,gBAAgB,OAAO,OAAO,KAAK,GAAG,OAAO,mBAAmB,IAAI,GAAG,EAAE;AAC7I,WAAO,EAAE,OAAO,KAAK,IAAI,QAAQ,GAAG,SAAS,QAAQ,CAAC,EAAE;AAAA,EAC1D;AAAA,EACA,gBAAgB,OAAO,gBAAgB;AAAA,EACvC,cAAc,OAAO,cAAc;AAAA,EACnC,SAAS,CAAC,EAAE,QAAQ,GAAG,EAAE,SAAS,MAAM,OAAO,EAAE,OAAO,QAAQ,QAAQ,OAAO,CAAC,WAAW,MAAM,SAAS,MAAM,CAAC,IAAI,QAAQ;AAAA,EAC7H,QAAQ,CAAC,EAAE,OAAO,GAAG,EAAE,QAAQ,MAAM,OAAO,EAAE,OAAO,gBAAgB,QAAQ,KAAK,EAAE;AACtF;AAGA,SAAS,SAAS,QAAiB,SAAoD;AACrF,QAAM,QAAQ,oBAAI,IAAW,CAAC,GAAG,cAAc,GAAI,QAAQ,UAAU,CAAC,CAAE,CAAC;AACzE,QAAM,OAAO,aAAa,KAAK,CAAC,UAAU,CAAC,OAAO,UAAU,IAAI,KAAK,CAAC;AACtE,MAAI,KAAM,QAAO,EAAE,SAAS,EAAE,OAAO,UAAU,OAAO,OAAO,KAAK,GAAG,OAAO,OAAO,OAAO,SAAS,EAAE,EAAE;AACvG,SAAO,EAAE,OAAO,IAAI,IAAI,CAAC,GAAG,KAAK,EAAE,OAAO,CAAC,UAAU,OAAO,UAAU,IAAI,KAAK,CAAC,CAAC,EAAE;AACrF;AAGA,IAAM,gBAAyC;AAAA,EAC7C,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,UAAU,CAAC,EAAE,SAAS,GAAG,EAAE,UAAU,MAAM,OAAO,EAAE,OAAO,aAAa,aAAa,UAAU,YAAY,YAAY,OAAO;AAAA,EAC9H,QAAQ,CAAC,EAAE,OAAO,GAAG,YAAY,WAAyC,aAAa,QAAQ,OAAO;AAAA,EACtG,YAAY,CAAC,EAAE,WAAW,GAAG,EAAE,eAAe,OAAO,EAAE,OAAO,EAAE,gBAAgB,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,WAAW,gBAAgB,GAAI,kBAAkB,CAAC,CAAE,CAAC,CAAC,EAAE,EAAE;AAAA,EAC1J,aAAa,CAAC,EAAE,YAAY,GAAG,EAAE,aAAa,MAAM,OAAO,EAAE,OAAO,QAAQ,CAAC,GAAG,aAAa,KAAK,IAAI,YAAY;AAAA,EAClH,gBAAgB,CAAC,SAAS,EAAE,aAAa,MAAM,OAAO,EAAE,OAAO,QAAQ,CAAC,KAAK,IAAI,CAAC,EAAE;AACtF;AAEA,SAAS,WAAoC,OAAwB,QAAc,SAAoC;AACrH,QAAM,QAAQ,CAAC;AACf,aAAW,OAAO,OAAO,KAAK,KAAK,GAAmB;AACpD,UAAM,QAAQ,MAAM,GAAG,EAAE,QAAQ,OAAO;AACxC,QAAI,aAAa,MAAO,QAAO;AAC/B,UAAM,GAAG,IAAI,MAAM;AAAA,EACrB;AACA,SAAO,EAAE,MAAM;AACjB;AAQO,SAAS,OAAO,QAAiB,SAAmC;AACzE,QAAM,QAAQ,WAA6B,eAAe,QAAQ,OAAO;AACzE,SAAO,aAAa,QAChB,EAAE,IAAI,OAAO,SAAS,EAAE,OAAO,QAAQ,OAAO,GAAG,MAAM,QAAQ,EAAE,IACjE,EAAE,IAAI,MAAM,SAAS,MAAM,MAAM;AACvC;AAGO,SAAS,iBAAiB,MAA0D,OAA+B;AACxH,SAAO;AAAA,IACL;AAAA,IACA,GAAI,KAAK,SAAS,EAAE,QAAQ,KAAK,OAAO,IAAI,CAAC;AAAA,IAC7C,GAAI,KAAK,QAAQ,WAAW,SAAY,EAAE,QAAQ,KAAK,OAAO,OAAO,IAAI,CAAC;AAAA,IAC1E,GAAI,KAAK,QAAQ,gBAAgB,SAAY,EAAE,aAAa,KAAK,OAAO,YAAY,IAAI,CAAC;AAAA,IACzF,GAAI,KAAK,iBAAiB,EAAE,gBAAgB,KAAK,eAAe,IAAI,CAAC;AAAA,EACvE;AACF;AAGO,IAAM,iBAAuE;AAAA,EAClF,UAAU;AAAA,EACV,UAAU;AAAA,EACV,WAAW;AAAA,EACX,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,aAAa;AAAA,EACb,eAAe;AAAA,EACf,eAAe;AAAA,EACf,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,eAAe;AAAA,EACf,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB,gBAAgB;AAAA,EAChB,YAAY;AACd;AAGO,SAAS,cAAc,SAAkB,SAAwC;AACtF,QAAM,QAAQ,eAAe,OAAO;AACpC,SAAO,UAAU,QAAQ,QAAQ,OAAO,IAAI,KAAK;AACnD;AAGO,SAAS,aAAa,OAAe,SAAkB,QAAwB;AACpF,SAAO,SAAS,KAAK,+BAA+B,MAAM,+BAA+B,OAAO,QAAQ,MAAM,CAAC;AACjH;AAGO,IAAM,wBAAwB;AAGrC,IAAM,cAAqD;AAAA,EACzD,GAAG,OAAO,QAAQ,cAAc,EAAE,QAAQ,CAAC,CAAC,MAAM,KAAK,MAAO,QAAQ,CAAC,CAAC,MAAM,KAAK,CAAU,IAAI,CAAC,CAAE;AAAA,EACpG,CAAC,eAAe,QAAQ;AAAA,EACxB,CAAC,aAAa,QAAQ;AACxB;AAQO,SAAS,qBAAqB,SAA4B;AAC/D,SAAO,YAAY,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,QAAQ,OAAO,IAAI,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,MAAM,IAAI;AAC3F;AAcO,SAAS,aAAa,OAAkC,QAA0B;AACvF,SAAO,QAAQ,MAAM,QAAQ,KAAK,EAAE,aAAa,SAAS;AAC5D;AAGO,SAAS,cAAc,UAA4D;AACxF,SAAO,EAAE,OAAO,GAAG,SAAS,CAAC,UAAU,YAAY,EAAE,GAAG,SAAS,GAAG,MAAM,CAAC,EAAE;AAC/E;;;AClPO,SAAS,iBAAiB,MAAmC;AAClE,SAAO,IAAI,KAAK,KAAK;AACvB;AAOO,SAAS,kBAAkB,MAAmC;AACnE,SAAO,IAAI,KAAK,KAAK;AACvB;AAQO,SAAS,kBAAkB,QAA0B,SAAsD;AAChH,MAAI,WAAW,UAAU,WAAW,OAAQ,QAAO,CAAC,GAAG,OAAO;AAC9D,SAAO;AACT;AAEA,SAAS,eAAe,GAAoC,GAA6C;AACvG,SAAO,GAAG,YAAY,GAAG,WAAW,GAAG,mBAAmB,GAAG;AAC/D;AAGA,SAAS,WAAW,MAA0B,QAAkB,SAAqC;AACnG,SAAO,SAAS,UAAa,SAAS,mBAAmB,QAAQ,cAAc,MAAM,CAAC;AACxF;AAUA,SAAS,QAAQ,OAAwB,MAAY,OAAuF;AAC1I,QAAM,EAAE,QAAQ,QAAQ,QAAQ,IAAI;AACpC,QAAM,QAAQ,UAAU,MAAM;AAC9B,QAAM,SAAS,KAAK;AACpB,QAAM,QAAQ,QAAQ,cAAc,MAAM;AAC1C,QAAM,UAAU,WAAW,UAAU,WAAW,cAAc,KAAK,aAAa,UAAa,KAAK,aAAa,OAAO;AACtH,MAAI,QAAQ;AACV,QAAI,SAAS,MAAM,SAAS,KAAK,CAAC,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,QAAQ,GAAG;AAC3E,aAAO,EAAE,IAAI,OAAO,OAAO,WAAW,MAAM,uBAAuB,KAAK,QAAQ,mBAAmB,MAAM,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,IAAI,CAAC,GAAG;AAAA,IACzI;AACA,UAAM,cAAc,sBAAsB,OAAO,KAAK,QAAQ;AAC9D,QAAI,YAAa,QAAO,EAAE,IAAI,OAAO,OAAO,SAAS,KAAK,QAAQ,gBAAgB,MAAM,kCAAkC,WAAW,GAAG;AACxI,WAAO,EAAE,IAAI,MAAM,MAAM,KAAK,SAAS;AAAA,EACzC;AACA,QAAM,WAAW,WAAW,UAAa,OAAO,SAAS;AACzD,MAAI,WAAW,YAAY,CAAC,QAAQ,eAAgB,UAAU,CAAC,SAAS,CAAC,YAAY,MAAM,aAAa,OAAY,QAAO,EAAE,IAAI,MAAM,MAAM,KAAK,SAAS;AAE3J,QAAM,UAAU,UAAU,UAAa,KAAK,aAAa,MAAM,YAAY,WAAW,MAAM,UAAU,MAAM,gBAAgB,OAAO;AACnI,QAAM,WAAW,MAAM,aAAa,WAAW,WAAW,KAAK,UAAU,QAAQ,OAAO;AACxF,MAAI,YAAY,CAAC,aAAa,KAAK,KAAK,WAAW,UAAU,WAAW,QAAQ;AAC9E,UAAM,SAAS,sBAAsB,OAAO,mBAAmB,KAAK,CAAC;AACrE,UAAM,OAAO,gBAAgB,QAAQ,WAAW,EAAE,OAAO,CAAC,MAAM,MAAM,MAAM;AAC5E,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,OAAO,IAAI,KAAK,KAAK,+BAA+B,MAAM,0BAA0B,SAAS,4BAA4B,EAAE,+BAA+B,KAAK,SAAS,IAAI,2BAA2B,KAAK,KAAK,IAAI,CAAC,KAAK,EAAE,GAAG,SAAS,KAAK,MAAM,KAAK,EAAE;AAAA,IAC7P;AAAA,EACF;AACA,QAAM,OAAO,YAAY,QAAQ,QAAQ,aAAa,EAAE,UAAU,SAAS,KAAK,SAAS,GAAG,QAAQ,qBAAqB,KAAK;AAC9H,SAAO,KAAK,KAAK,EAAE,IAAI,MAAM,MAAM,KAAK,QAAQ,KAAK,SAAS,IAAI;AACpE;AAqCO,SAAS,kBAAkB,OAA2C;AAC3E,QAAM,EAAE,QAAQ,QAAQ,QAAQ,IAAI;AACpC,QAAM,UAAU,MAAM;AACtB,QAAM,QAAQ,UAAU,MAAM;AAC9B,QAAM,QAAQ,UAAU,UAAa,MAAM,mBAAmB,QAAQ;AACtE,QAAM,SAAS,UAAU,SAAS;AAElC,QAAM,OAAO,WAAW,YAAY,CAAC,CAAC,UAAU,CAAC,CAAC,QAAQ,aAAa,OAAO,EAAE;AAChF,MAAI,QAAQ,MAAO,QAAO,EAAE,IAAI,OAAO,OAAO,kBAAkB,OAAO,kBAAkB,EAAE,MAAM,CAAC,EAAE;AACpG,MAAI,QAAQ,CAAC,eAAe,QAAQ,eAAe,QAAQ,aAAa,EAAG,QAAO,EAAE,IAAI,OAAO,OAAO,iBAAiB,OAAO,iBAAiB,EAAE,MAAM,CAAC,EAAE;AAE1J,MAAI,QAAQ,SAAS,QAAQ,QAAQ,SAAS,YAAa,QAAO,EAAE,IAAI,MAAM,MAAM,SAAS,aAAa,CAAC,EAAE;AAG7G,QAAM,OAAO,QAAQ,SAAS,cAAc,EAAE,IAAI,MAAe,MAAM,OAAU,IAAI,QAAQ,OAAO,SAAS,KAAK;AAClH,MAAI,CAAC,KAAK,GAAI,QAAO,EAAE,IAAI,OAAO,OAAO,YAAY,OAAO,KAAK,MAAM;AAGvE,QAAM,QAAqB,OAAO,EAAE,IAAI,MAAM,YAAY,QAAQ,cAAc,IAAI,SAAS,OAAO,KAAK;AACzG,MAAI,CAAC,MAAM,GAAI,QAAO,EAAE,IAAI,OAAO,OAAO,iBAAiB,OAAO,MAAM,MAAM;AAE9E,QAAM,OAAO,MAAM,eAAe,QAAQ,iBAAiB,KAAK,SAAS,QAAQ,WAC7E,UACA,EAAE,GAAG,SAAS,eAAe,MAAM,YAAY,UAAU,KAAK,KAAK;AACvE,QAAM,cAAsC,CAAC;AAC7C,QAAM,OAAO,CAAC,OAAsC,MAA0B,OAA2B;AACvG,SAAK,QAAQ,WAAW,MAAM,MAAO,aAAY,KAAK,EAAE,QAAQ,QAAQ,IAAI,OAAO,QAAQ,OAAO,OAAO,MAAM,QAAQ,MAAM,IAAI,MAAM,KAAK,CAAC;AAAA,EAC/I;AACA,OAAK,iBAAiB,QAAQ,eAAe,SAAS,KAAK,eAAe,OAAO;AACjF,OAAK,kBAAkB,QAAQ,eAAe,gBAAgB,KAAK,eAAe,cAAc;AAChG,SAAO,EAAE,IAAI,MAAM,MAAM,YAAY;AACvC;AAKA,SAAS,SAAS,OAAwB,OAA6B;AACrE,QAAM,EAAE,QAAQ,QAAQ,QAAQ,IAAI;AACpC,QAAM,QAAQ,UAAU,MAAM;AAC9B,QAAM,UAAU,MAAM,KAAK;AAC3B,QAAM,SAAS,MAAM,KAAK;AAC1B,QAAM,SAAS,QAAQ;AACvB,QAAM,MAAM,OAAO,MAAM,KAAK,CAAC;AAC/B,QAAM,UAAU,CAACC,QAAe,IAAI,KAAK,CAAC,MAAM,EAAE,YAAYA,GAAE;AAEhE,QAAM,cAAc,SAAS,WAAW,OAAO,eAAe,YAAY,QAAQ,UAAU,MAAM,iBAAiB;AACnH,QAAM,OAAO,eAAe,WAAW,CAAC,OAAO,WAAW,GAAG,KAAK,CAAC,MAAM,EAAE,YAAY,QAAQ,OAAO,IAClG,EAAE,GAAG,QAAQ,CAAC,WAAW,GAAG,CAAC,GAAI,OAAO,WAAW,KAAK,CAAC,GAAI,EAAE,SAAS,QAAQ,SAAS,YAAY,QAAQ,YAAY,UAAU,CAAC,EAAE,CAAC,EAAE,IACzI;AACJ,QAAM,UAAU,mBAAmB,QAAQ,qBAAqB,MAAM,GAAG,QAAQ,IAAI;AACrF,QAAM,SAAS,CAACA,QAAe,CAAC,WAAW,QAAQ,SAASA,GAAE;AAG9D,QAAM,UAAU,CAAC,eAAyD;AACxE,UAAM,QAAQ,QAAQ,WAAW,OAAO;AACxC,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,iBAAiB,oBAAoB,WAAW,gBAAgB,MAAM,QAAQ;AACpF,UAAM,oBAAoB,MAAM,SAAS,IAAI,CAAC,MAAM,EAAE,EAAE;AACxD,QAAI,mBAAmB,WAAW,kBAAkB,WAAW,mBAAmB,KAAK,MAAM,kBAAkB,KAAK,EAAG,QAAO;AAC9H,UAAM,OAA4B,EAAE,GAAG,YAAY,kBAAkB;AACrE,QAAI,mBAAmB,OAAW,QAAO,KAAK;AAAA,QACzC,MAAK,iBAAiB;AAC3B,WAAO;AAAA,EACT;AAGA,QAAM,SAAS,CAAC,WAAgE;AAC9E,UAAMA,MAAK,SAAS,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC,KAAK,UAAU,CAAC,KAAK,IAAI,CAAC,GAAG;AACvE,QAAIA,QAAO,OAAW,QAAO;AAC7B,UAAM,QAAQ,QAAQA,GAAE;AACxB,UAAM,iBAAiB,oBAAoB,QAAQ,OAAO,YAAY,CAAC,CAAC;AACxE,WAAO;AAAA,MACL,SAASA;AAAA,MACT,YAAY,OAAO,cAAcA;AAAA,MACjC,GAAI,mBAAmB,SAAY,EAAE,eAAe,IAAI,CAAC;AAAA,MACzD,GAAI,QAAQ,EAAE,mBAAmB,MAAM,SAAS,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC;AAAA,IACxE;AAAA,EACF;AAEA,MAAI,CAAC,QAAS,QAAO,EAAE,IAAI,MAAM,YAAY,WAAW,WAAW,SAAY,OAAO,MAAS,EAAE;AACjG,MAAI,WAAW,SAAU,QAAO,EAAE,IAAI,MAAM,YAAY,QAAQ,OAAO,EAAE;AAEzE,QAAM,KAAK,QAAQ;AACnB,QAAM,OAAO,OAAO,eAAe,YAAY;AAC/C,MAAI,UAAU,QAAQ,CAAC,MAAO,QAAO,EAAE,IAAI,MAAM,YAAY,QAAQ,OAAO,EAAE;AAE9E,QAAM,kBAAkB,OAAO,QAAQ,MAAM,EAAE,KAAK,CAAC,CAAC,OAAO,IAAI,MAAM,UAAU,UAAU,MAAM,KAAK,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC;AAC9H,MAAI,MAAM;AAGR,UAAM,OAAO,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,KAAM,IAAI,WAAW,KAAK,CAAC;AAC9D,WAAO,EAAE,IAAI,MAAM,YAAY,QAAQ,OAAO,EAAE,IAAI,QAAQ,OAAO,IAAI,OAAO,QAAQ,cAAc,EAAE;AAAA,EACxG;AAEA,MAAI,WAAW,UAAU,WAAW,QAAQ;AAE1C,UAAM,UAAU,IAAI,WAAW,KAAK,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,SAAS,SAAS,EAAE;AAC3E,QAAI,CAAC,QAAS,QAAO,EAAE,IAAI,OAAO,OAAO,WAAW,MAAM,2BAA2B,EAAE,IAAI;AAC3F,QAAI,CAAC,OAAO,EAAE,EAAG,QAAO,EAAE,IAAI,OAAO,OAAO,UAAU,EAAE,8CAA8C,MAAM,IAAI;AAChH,WAAO,EAAE,IAAI,MAAM,YAAY,QAAQ,OAAO,EAAE;AAAA,EAClD;AAEA,QAAM,WAAW,CAAC,QAAQ,EAAE,KAAK;AACjC,SAAO,EAAE,IAAI,MAAM,YAAY,YAAY,CAAC,OAAO,EAAE,IAAI,OAAO,QAAQ,cAAc,IAAI,QAAQ,OAAO,EAAE;AAC7G;AAYO,SAAS,mBACd,OACA,SACA,SACwD;AACxD,QAAM,QAAQ,oBAAI,IAAkB;AACpC,QAAM,QAAQ,CAAC,SAA0B,KAAK,QAAQ,CAAC,MAAM;AAAE,UAAM,IAAI,EAAE,IAAI,CAAC;AAAG,UAAM,EAAE,YAAY,CAAC,CAAC;AAAA,EAAG,CAAC;AAC7G,QAAM,OAAO;AACb,QAAM,SAAS,EAAE,GAAG,SAAS,aAAa,OAAU;AACpD,QAAM,cAAsC,CAAC;AAC7C,QAAM,OAAO,CAAC,SAAkC,KAAK,IAAI,CAAC,SAAS;AACjE,UAAM,UAAU,kBAAkB,EAAE,QAAQ,QAAQ,MAAM,QAAQ,MAAM,IAAI,KAAK,EAAE,GAAG,SAAS,OAAO,CAAC;AACvG,UAAM,WAAW,QAAQ,KAAK,QAAQ,OAAO;AAC7C,QAAI,QAAQ,GAAI,aAAY,KAAK,GAAG,QAAQ,WAAW;AACvD,WAAO,EAAE,GAAG,UAAU,UAAU,KAAK,KAAK,YAAY,CAAC,CAAC,EAAE;AAAA,EAC5D,CAAC;AACD,SAAO,EAAE,OAAO,KAAK,KAAK,GAAG,YAAY;AAC3C;;;ACxSO,SAAS,gBAAgB,UAAsD;AACpF,QAAM,SAA0B,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,EAAE;AAC1G,aAAW,UAAU,UAAU;AAC7B,QAAI,WAAW,YAAa,QAAO,aAAa;AAAA,aACvC,WAAW,cAAe,QAAO,WAAW;AAAA,aAC5C,WAAW,gBAAiB,QAAO,WAAW;AAAA,aAC9C,WAAW,SAAU,QAAO,UAAU;AAAA,aACtC,WAAW,UAAW,QAAO,WAAW;AAAA,QAC5C,QAAO,WAAW;AAAA,EACzB;AACA,SAAO;AACT;AAUO,IAAM,eAAe,EAAE,MAAM,KAAK,OAAO,GAAG;AAG5C,IAAM,+BAA+B,CAAC,UAAU,YAAY,UAAU,aAAa,OAAO,YAAY,UAAU,aAAa,UAAU;AAGvI,IAAM,mBAAmB,CAAC,QAAQ,UAAU,UAAU,kBAAkB,OAAO;AAG/E,IAAM,yBAAyB;AAE/B,SAAS,uBAAuB,QAAmC;AACxE,SAAO,uEAAuE,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC;AACtH;AAeA,SAAS,SAAS,OAA0C;AAC1D,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,EAAE,OAAO,IAAI;AACnB,SAAO,OAAO,WAAW,YAAY,OAAO,UAAU,MAAM,KAAK,SAAS;AAC5E;AAGA,SAAS,YAAY,QAAkC;AACrD,QAAM,EAAE,YAAY,IAAI;AACxB,SAAO,gBAAgB,UAAc,OAAO,UAAU,WAAW,KAAK,cAAc;AACtF;AAGA,SAAS,UAAU,MAAY,aAAsD;AACnF,MAAI,KAAK,SAAS,KAAM,QAAO;AAC/B,QAAM,OAAO,cAAc,mBAAmB,YAAY,KAAK,cAAc,CAAC,IAAI;AAClF,SAAO,SAAS,UAAa,KAAK,aAAa;AACjD;AAGA,SAAS,aAAa,MAAY,aAAsD;AACtF,SAAO,KAAK,SAAS,QAAQ,gBAAgB,UAAa,YAAY,KAAK,cAAc,MAAM;AACjG;AAGA,SAAS,QAAQ,MAAqB;AACpC,SAAQ,KAAK,SAAS,YAAY,CAAC,KAAK,YAAa,KAAK,QAAQ;AACpE;AAGA,SAAS,QAAQ,OAAwB,MAAY,QAA0C;AAC7F,QAAM,OAAO,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAChD,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,OAAO,CAAC,SAAwB,KAAK,aAAa,KAAK,CAAC,OAAO;AACnE,QAAI,KAAK,IAAI,EAAE,EAAG,QAAO;AACzB,SAAK,IAAI,EAAE;AACX,UAAM,MAAM,KAAK,IAAI,EAAE;AACvB,WAAO,QAAQ,WAAc,OAAO,GAAG,KAAK,KAAK,GAAG;AAAA,EACtD,CAAC;AACD,SAAO,KAAK,IAAI;AAClB;AAUO,SAAS,iBAAiB,OAAwB,QAAyB,CAAC,GAAsB;AACvG,QAAM,SAA4B,CAAC;AACnC,QAAM,YAAY,MAAM,OAAO,CAAC,MAAM,EAAE,SAAS,WAAW;AAC5D,QAAM,OAAO,CAAC,MAAY,OAAe,YAAoB,OAAO,KAAK,EAAE,QAAQ,KAAK,IAAI,OAAO,QAAQ,CAAC;AAE5G,aAAW,QAAQ,WAAW;AAC5B,UAAM,QAAQ,SAAS,KAAK,KAAK;AACjC,QAAI,OAAO,KAAK,SAAS,YAAY,CAAC,KAAK,KAAK,KAAK,EAAG,MAAK,MAAM,QAAQ,GAAG,KAAK,2EAA2E;AAC9J,QAAI,CAAC,SAAS,KAAK,MAAM,EAAG,MAAK,MAAM,UAAU,GAAG,KAAK,uHAAuH;AAAA,aACvK,CAAC,YAAY,KAAK,MAAM,EAAG,MAAK,MAAM,UAAU,GAAG,KAAK,yEAAyE;AAC1I,UAAM,QAAQ,KAAK;AACnB,QAAI,CAAC,KAAK,aAAa,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,KAAK,CAAC,MAAM,MAAM,CAAC,MAAM,OAAO,MAAM,YAAY,EAAE,KAAK,CAAC,IAAI;AAC7H,WAAK,MAAM,kBAAkB,GAAG,KAAK,4JAA4J;AAAA,IACnM;AACA,QAAI,KAAK,UAAU,UAAa,CAAC,QAAQ,KAAK,KAAK,EAAG,MAAK,MAAM,SAAS,GAAG,KAAK,yFAAyF,aAAa,KAAK,0BAA0B,aAAa,IAAI,kBAAkB;AAC1P,UAAM,WAAW,KAAK,UAAU,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,SAAS,KAAc,CAAC;AACtF,QAAI,QAAQ,SAAS,EAAG,MAAK,MAAM,UAAU,GAAG,KAAK,yBAAyB,QAAQ,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC,+BAA+B,OAAO,KAAK,IAAI,CAAC,EAAE;AAEvK,UAAM,aAAa,MAAM,OAAO,CAAC,MAAM,EAAE,aAAa,SAAS,KAAK,EAAE,CAAC;AACvE,QAAI,KAAK,UAAU;AACjB,iBAAW,UAAU,WAAW,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ,GAAG;AAClE,aAAK,QAAQ,gBAAgB,SAAS,OAAO,KAAK,iBAAiB,KAAK,KAAK,6JAA6J;AAAA,MAC5O;AAAA,IACF;AACA,QAAI,CAAC,WAAW,KAAK,CAAC,MAAM,OAAO,GAAG,MAAM,MAAM,WAAW,CAAC,GAAG;AAC/D,WAAK,MAAM,gBAAgB,GAAG,KAAK,8DAA8D,KAAK,WAAW,+BAA+B,uCAAuC,8BAA8B;AAAA,IACvN;AAAA,EACF;AAEA,aAAW,QAAQ,MAAM,OAAO,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,QAAQ,GAAG;AACzE,QAAI,MAAM,YAAY,MAAO,MAAK,MAAM,YAAY,SAAS,KAAK,KAAK,kHAAkH;AAAA,EAC3L;AAGA,aAAW,SAAS,MAAM,OAAO,CAAC,MAAM,EAAE,IAAI,GAAG;AAC/C,QAAI,CAAC,QAAQ,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,WAAW,EAAG;AAC3D,eAAW,MAAM,MAAM,MAAM,QAAQ,CAAC,GAAG;AACvC,YAAM,OAAO,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAC1C,UAAI,QAAQ,QAAQ,IAAI,GAAG;AACzB,aAAK,MAAM,QAAQ,SAAS,MAAM,KAAK,YAAY,KAAK,KAAK,4JAA4J;AAAA,MAC3N;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,QAAQ,OAAyB;AACxC,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,EAAE,OAAO,UAAU,SAAS,IAAI;AACtC,QAAM,SAAS,CAAC,SAAkB,OAAO,SAAS,YAAY,KAAK,KAAK,EAAE,SAAS,KAAK,KAAK,UAAU,aAAa,QAAQ,SAAS,KAAK,IAAI;AAC9I,SAAO,CAAC,OAAO,UAAU,QAAQ,EAAE,MAAM,CAAC,SAAS,SAAS,UAAc,MAAM,QAAQ,IAAI,KAAK,KAAK,UAAU,aAAa,SAAS,KAAK,MAAM,MAAM,CAAE;AAC3J;AAGA,SAAS,OAAO,MAAY,WAAiB,aAAsD;AACjG,SAAO,UAAU,MAAM,WAAW,KAAM,CAAC,UAAU,YAAY,KAAK,SAAS,YAAY,KAAK,aAAa;AAC7G;AAQO,SAAS,SAAS,OAAwB,WAAiB,QAA8C,CAAC,GAAW;AAC1H,SAAO,MAAM,OAAO,CAAC,MAAM,EAAE,aAAa,SAAS,UAAU,EAAE,MAAM,OAAO,GAAG,WAAW,MAAM,WAAW,KAAK,aAAa,GAAG,MAAM,WAAW,EAAE;AACrJ;AAQO,SAAS,mBAAmB,OAAwB,aAA0C,QAA8C,CAAC,GAAW;AAC7J,SAAO,MACJ,OAAO,CAAC,MAAM,EAAE,SAAS,eAAe,YAAY,EAAE,EAAE,CAAC,EACzD,QAAQ,CAAC,MAAM,SAAS,OAAO,GAAG,KAAK,CAAC,EACxC,OAAO,CAAC,UAAU,MAAM,WAAW,eAAe,MAAM,WAAW,SAAS;AACjF;AASA,SAAS,WAAW,EAAE,QAAQ,SAAS,GAAmB;AACxD,QAAM,UAAU,WAAW,UAAU,EAAE,EAAE,QAAQ,CAAC,SAAS,KAAK,MAAM,QAAQ,CAAC,EAAE,IAAI,CAAC,YAAY,QAAQ,KAAK,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,QAAQ,WAAW,GAAG,CAAC;AAC9J,SAAO,CAAC,GAAG,SAAS,IAAI,YAAY,CAAC,GAAG,IAAI,CAAC,SAAS,KAAK,KAAK,GAAG,CAAC,CAAC,EAAE,OAAO,OAAO;AACvF;AAOO,SAAS,WAAW,OAAqC;AAC9D,QAAM,YAAY,IAAI,IAAI,MAAM,OAAO,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AACtF,SAAO,MAAM,OAAO,CAAC,MAAM,EAAE,aAAa,KAAK,CAAC,OAAO,UAAU,IAAI,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM;AAAA,IACxF,GAAG,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,IAAI,CAACC,WAAU,EAAE,MAAAA,OAAM,SAAS,MAAM,EAAE;AAAA,IACrE,GAAG,WAAW,CAAC,EAAE,IAAI,CAACA,WAAU,EAAE,MAAAA,OAAM,SAAS,KAAK,EAAE;AAAA,EAC1D,CAAC;AACH;AAGO,SAAS,oBAAoB,OAAwB,MAAY,QAA8C,CAAC,GAAY;AACjI,MAAI,CAAC,UAAU,MAAM,MAAM,WAAW,KAAK,CAAC,aAAa,MAAM,MAAM,WAAW,KAAK,EAAE,KAAK,SAAS,YAAY,KAAK,UAAW,QAAO;AACxI,SAAO,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,eAAe,KAAK,aAAa,SAAS,EAAE,EAAE,CAAC;AACrF;AAGO,SAAS,SAAS,OAAgC;AACvD,SAAO,aAAa,KAAK,EAAE;AAC7B;AAQO,SAAS,mBAAmB,MAAc,eAAgC;AAC/E,QAAM,OAAO,cAAc,KAAK,EAAE,QAAQ,SAAS,EAAE,EAAE,QAAQ,OAAO,GAAG;AACzE,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,KAAK,SAAS,GAAG,EAAG,QAAO,WAAW,IAAI,EAAE,KAAK,IAAI;AACzD,QAAM,OAAO,KAAK,QAAQ,QAAQ,EAAE;AACpC,SAAO,SAAS,QAAQ,KAAK,WAAW,GAAG,IAAI,GAAG;AACpD;AAGA,SAAS,WAAW,MAAsB;AACxC,QAAM,OAAO,KAAK,KAAK,EAAE,QAAQ,SAAS,EAAE,EAAE,QAAQ,OAAO,GAAG;AAChE,QAAM,OAAO,KAAK,QAAQ,GAAG;AAC7B,SAAO,SAAS,KAAK,OAAO,KAAK,MAAM,GAAG,IAAI;AAChD;AAGO,SAAS,UAAU,GAAW,GAAoB;AACvD,MAAI,mBAAmB,EAAE,QAAQ,QAAQ,EAAE,GAAG,CAAC,KAAK,mBAAmB,EAAE,QAAQ,QAAQ,EAAE,GAAG,CAAC,EAAG,QAAO;AACzG,MAAI,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC,EAAE,SAAS,GAAG,EAAG,QAAO;AACjD,QAAM,CAAC,KAAK,KAAK,IAAI,CAAC,WAAW,CAAC,GAAG,WAAW,CAAC,CAAC;AAClD,SAAO,IAAI,WAAW,KAAK,KAAK,MAAM,WAAW,GAAG;AACtD;AAGA,SAAS,SAAS,GAAW,GAAmB;AAC9C,SAAO,EAAE,SAAS,GAAG,KAAM,CAAC,EAAE,SAAS,GAAG,KAAK,EAAE,UAAU,EAAE,SAAU,IAAI;AAC7E;AAGA,SAAS,QAAQ,OAAwB,GAAS,GAAkB;AAClE,SAAO,QAAQ,OAAO,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,KAAK,QAAQ,OAAO,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE;AAC1F;AAOO,SAAS,cAAc,OAAkC;AAC9D,QAAM,SAAS,MAAM,OAAO,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,KAAK;AACpE,QAAM,OAAiB,CAAC;AACxB,SAAO,QAAQ,CAAC,GAAG,MAAM;AACvB,eAAW,KAAK,OAAO,MAAM,IAAI,CAAC,GAAG;AACnC,UAAI,QAAQ,OAAO,GAAG,CAAC,EAAG;AAC1B,YAAM,YAAY,EAAE,OAAO,SAAS,CAAC,GAAG,QAAQ,CAAC,SAAS,EAAE,OAAO,SAAS,CAAC,GAAG,OAAO,CAAC,UAAU,UAAU,KAAK,KAAK,CAAC,EAAE,IAAI,CAAC,UAAU,SAAS,KAAK,KAAK,CAAC,CAAC;AAC7J,UAAI,SAAS,SAAS,EAAG,MAAK,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,kBAAkB,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC,EAAE,KAAK,IAAI,CAAC,kFAAkF;AAC1M,iBAAW,QAAQ,EAAE,OAAO,YAAY,CAAC,GAAG;AAC1C,YAAI,EAAE,OAAO,UAAU,SAAS,IAAI,EAAG,MAAK,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,KAAK,mBAAmB,IAAI,6CAA6C;AAAA,MACzJ;AACA,iBAAW,CAAC,UAAU,QAAQ,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAY;AAC5D,mBAAW,QAAQ,SAAS,OAAO,YAAY,CAAC,GAAG;AACjD,cAAI,SAAS,OAAO,UAAU,SAAS,IAAI,EAAG,MAAK,KAAK,SAAS,SAAS,KAAK,eAAe,IAAI,aAAa,SAAS,KAAK,+GAA+G,SAAS,KAAK,UAAU;AAAA,QACtQ;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAEA,SAAS,WAAW,MAAsB;AACxC,QAAM,UAAU,KAAK,QAAQ,qBAAqB,MAAM,EAAE,QAAQ,eAAe,CAAC,SAAU,SAAS,MAAM,UAAU,UAAW;AAChI,SAAO,IAAI,OAAO,IAAI,OAAO,WAAW;AAC1C;;;AChUA,SAAS,MAAM,cAAc;AA0EtB,IAAM,wBAAwB;AAG9B,IAAM,uBAAuB;AAG7B,IAAM,oBAAoB;AAEjC,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,KAAK,OAAoC;AAChD,SAAO,OAAO,UAAU,YAAY,OAAO,UAAU,WAAW,OAAO,KAAK,IAAI;AAClF;AAOA,IAAM,kBAAkB,CAAC,kBAAkB,iBAAiB,kBAAkB,YAAY,YAAY,UAAU,UAAU,aAAa,OAAO,UAAU;AAGjJ,SAAS,aAAa,KAAwC;AACnE,SAAO,gBAAgB,OAAO,CAAC,MAAM;AACnC,UAAM,QAAQ,IAAI,CAAC;AACnB,WAAO,UAAU,UAAa,UAAU,QAAQ,UAAU,SAAS,EAAE,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW;AAAA,EAChH,CAAC;AACH;AAGA,SAAS,gBAAgB,KAAwC;AAC/D,SAAO,6BAA6B,OAAO,CAAC,MAAM;AAChD,UAAM,QAAQ,IAAI,CAAC;AACnB,WAAO,UAAU,UAAa,UAAU,QAAQ,UAAU,SAAS,EAAE,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW;AAAA,EAChH,CAAC;AACH;AAGA,SAAS,gBAAgB,KAA8B,MAAkH;AACvK,QAAM,OAAO,CAAC,UAA0C,MAAM,QAAQ,KAAK,IAAI,MAAM,IAAI,MAAM,IAAI;AACnG,QAAM,OAAO,KAAK,IAAI,IAAI,KAAK,KAAK;AACpC,QAAM,UAAU,SAAS,IAAI,MAAM,IAAI,IAAI,SAAuC,WAAc,KAAK;AACrG,QAAM,SAAU,KAAK,IAAI,MAAM,KAAK,KAAK;AACzC,QAAM,iBAAiB,KAAK,IAAI,cAAc,KAAK,KAAK;AACxD,QAAM,SAAS,SAAS,IAAI,KAAK,IAAI,IAAI,QAAqB,WAAc,KAAK;AACjF,SAAO;AAAA,IACL,GAAI,SAAS,SAAY,EAAE,KAAK,IAAI,CAAC;AAAA,IACrC,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,iBAAiB,EAAE,eAAe,IAAI,CAAC;AAAA,IAC3C,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;AAAA,IACzB,GAAI,IAAI,aAAa,QAAS,IAAI,aAAa,UAAa,KAAK,WAAY,EAAE,UAAU,KAAc,IAAI,CAAC;AAAA,EAC9G;AACF;AAGO,SAAS,oBAAoB,QAAmC;AACrE,SAAO,oFAAoF,OAAO,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI,CAAC;AACnI;AAOO,SAAS,oBAAoB,MAAoB,WAAmC;AACzF,MAAI,SAAS,SAAU,QAAO;AAC9B,MAAI,SAAS,KAAM,QAAO;AAC1B,MAAI,UAAW,QAAO;AACtB,SAAO;AACT;AAGO,SAAS,UAAU,OAAe,aAA8B;AACrE,SAAO,gBAAgB,SAAY,YAAY,KAAK,SAAS,WAAW,MAAM,SAAS,KAAK;AAC9F;AAQA,IAAM,cAAc,oBAAI,QAAyB;AAG1C,SAAS,gBAAgB,MAA4C;AAC1E,SAAO,YAAY,IAAI,IAAI;AAC7B;AAGA,SAAS,QAAQ,KAA8B,MAAwE;AACrH,QAAM,SAAS,KAAK,IAAI,cAAc;AACtC,MAAI,SAAS,IAAI,aAAa,GAAG;AAC/B,UAAM,IAAI,IAAI;AACd,WAAO;AAAA,MACL,SAAS,KAAK,EAAE,OAAO,KAAK;AAAA,MAC5B,YAAY,KAAK,EAAE,UAAU,KAAK;AAAA,MAClC,gBAAgB,KAAK,EAAE,cAAc,KAAK;AAAA,IAC5C;AAAA,EACF;AACA,SAAO,QAAQ,WAAW,SAAY,EAAE,GAAG,MAAM,gBAAgB,OAAO,IAAI;AAC9E;AAQA,SAAS,WAAW,KAA8B,MAIhD;AACA,QAAM,OAAO,CAAC,UAAyD,IAAI,KAAK,MAAM,UAAa,IAAI,KAAK,MAAM,OAAO,IAAI,KAAK,IAAI,KAAK,KAAK;AAChJ,QAAM,SAAS,EAAE,UAAU,KAAK,UAAU,GAAG,QAAQ,KAAK,QAAQ,GAAG,WAAW,KAAK,WAAW,EAAE;AAClG,QAAM,YAAY,oBAAI,IAAY;AAClC,QAAM,WAAW,WAAW,OAAO,QAAQ,IAAI,OAAO,WAAW;AACjE,MAAI,OAAO,aAAa,UAAa,CAAC,SAAU,WAAU,IAAI,UAAU;AACxE,QAAM,SAAS,OAAO,OAAO,WAAW,WAAW,OAAO,SAAS;AACnE,MAAI,OAAO,WAAW,UAAa,WAAW,OAAW,WAAU,IAAI,QAAQ;AAC/E,QAAM,YAAY,OAAO,OAAO,cAAc,WAAW,OAAO,YAAY;AAC5E,MAAI,OAAO,cAAc,UAAa,cAAc,OAAW,WAAU,IAAI,WAAW;AACxF,SAAO;AAAA,IACL,QAAQ,EAAE,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC,GAAI,GAAI,WAAW,SAAY,EAAE,OAAO,IAAI,CAAC,GAAI,GAAI,cAAc,SAAY,EAAE,UAAU,IAAI,CAAC,EAAG;AAAA,IAC5I,KAAK;AAAA,IACL;AAAA,EACF;AACF;AAEA,SAAS,WAAW,OAAqC;AACvD,SAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,MAAM,CAAC,SAAS,MAAM,QAAQ,IAAI,KAAK,KAAK,MAAM,CAAC,SAAS,OAAO,SAAS,QAAQ,CAAC;AAC5H;AAqBO,SAAS,YAAY,MAAe,SAAwB,KAAgB,CAAC,GAAgB;AAClG,QAAM,MAAM,SAAS,IAAI,IAAI,OAAO,CAAC;AACrC,QAAM,EAAE,QAAQ,MAAM,UAAU,QAAQ,OAAO,IAAI;AACnD,QAAM,OAAO,MAAM,UAAU,CAAC;AAC9B,QAAM,SAA0B,CAAC;AACjC,QAAM,UAA2B,CAAC;AAClC,QAAM,UAAU,oBAAI,IAAoB;AACxC,QAAM,cAAsC,CAAC;AAE7C,QAAM,QAAQ,KAAK,IAAI,KAAK,KAAK;AACjC,QAAM,QAAQ,UAAU,OAAO,QAAQ,KAAK;AAC5C,QAAM,YAAY,KAAK,IAAI,EAAE;AAC7B,QAAM,KAAK,YAAY,CAAC,YAAY,MAAM,IAAI;AAC9C,MAAI,YAAY,UAAW,SAAQ,IAAI,WAAW,EAAE;AAEpD,QAAM,aAAa,QAAQ,sBAAsB;AACjD,QAAM,OAAqB,IAAI,SAAS,UAAU,IAAI,SAAS,QAAQ,IAAI,SAAS,YAAY,IAAI,SAAS,cAAc,IAAI,OAAO,KAAK,QAAQ;AACnJ,QAAM,KAAK,SAAS;AACpB,QAAM,SAAS,SAAS;AACxB,QAAM,YAAY,SAAS;AAE3B,QAAM,eAAe,WAAW,QAAQ,eAAe,EAAE,GAAI,MAAM,QAAQ,IAAI,QAAQ,IAAI,EAAE,UAAU,IAAI,SAAuB,IAAI,CAAC,GAAI,GAAI,OAAO,IAAI,WAAW,WAAW,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC,GAAI,GAAI,OAAO,IAAI,cAAc,WAAW,EAAE,WAAW,IAAI,UAAU,IAAI,CAAC,EAAG,CAAC,MAAM,QAAS,cAAc,IAAI,aAAa;AACxU,QAAM,iBAAiB,KAAK,IAAI,cAAc,KAAK,KAAK,kBAAkB,QAAQ,QAAQ,CAAC,KAAK,gBAAgB,CAAC;AACjH,QAAM,cAAc,KAAK,IAAI,WAAW,KAAK,KAAK,eAAe;AAIjE,QAAM,aAAa,SAAS,aAAa,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE,gBAAgB,MAAM,WAAW,IAAI,CAAC;AACpG,MAAI,WAAW,SAAS,EAAG,QAAO,KAAK,EAAE,QAAQ,IAAI,OAAO,WAAW,CAAC,GAAG,SAAS,GAAG,KAAK,IAAI,oBAAoB,UAAU,CAAC,GAAG,CAAC;AACnI,MAAI,WAAW;AACb,QAAI,CAAC,WAAY,QAAO,KAAK,EAAE,QAAQ,IAAI,OAAO,QAAQ,SAAS,QAAQ,qBAAqB,GAAG,KAAK,6BAA6B,sBAAsB,IAAI,CAAC;AAChK,UAAM,QAAQ,gBAAgB,GAAG;AACjC,QAAI,MAAM,SAAS,EAAG,QAAO,KAAK,EAAE,QAAQ,IAAI,OAAO,MAAM,CAAC,GAAG,SAAS,GAAG,KAAK,IAAI,uBAAuB,KAAK,CAAC,GAAG,CAAC;AAAA,EACzH;AAEA,QAAM,OAAO,WAAW,KAAK,IAAI;AACjC,QAAM,cAAc,iBAAiB,EAAE,MAAM,GAAG,KAAK,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,KAAK,UAAU,IAAI,EAAE,KAAK,CAAC;AACrG,aAAW,KAAK,YAAa,QAAO,KAAK,EAAE,QAAQ,IAAI,OAAO,EAAE,OAAO,SAAS,GAAG,KAAK,IAAI,EAAE,OAAO,GAAG,CAAC;AAEzG,QAAM,OAAO,SAAS,IAAI,IAAI;AAC9B,MAAI,WAAW,KAAM,QAAO,KAAK,EAAE,QAAQ,IAAI,OAAO,QAAQ,SAAS,GAAG,KAAK,IAAI,KAAK,KAAK,GAAG,CAAC;AAEjG,MAAI,IAAI,QAAQ,QAAQ,CAAC,MAAM,CAAC,OAAQ,QAAO,KAAK,EAAE,QAAQ,IAAI,OAAO,OAAO,SAAS,GAAG,KAAK,IAAI,oBAAoB,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;AAC5I,MAAI,IAAI,aAAa,UAAa,CAAC,UAAU,CAAC,UAAW,SAAQ,KAAK,EAAE,QAAQ,IAAI,OAAO,YAAY,SAAS,GAAG,KAAK,KAAK,qBAAqB,GAAG,CAAC;AACtJ,MAAI,SAAS,UAAU,IAAI,aAAa,KAAM,SAAQ,KAAK,EAAE,QAAQ,IAAI,OAAO,YAAY,SAAS,GAAG,KAAK,KAAK,oBAAoB,GAAG,CAAC;AAC1I,QAAM,MAAM,IAAI,QAAQ,SAAY,IAAI,QAAQ,OAAO,KAAK;AAC5D,MAAI,MAAM,OAAO,IAAI,aAAa,KAAM,SAAQ,KAAK,EAAE,QAAQ,IAAI,OAAO,YAAY,SAAS,GAAG,KAAK,KAAK,iBAAiB,GAAG,CAAC;AAGjI,QAAM,QAAQ,OAAO,IAAI,aAAa,YAAY,IAAI,WAAW;AACjE,QAAM,WAAW,MAAM,CAAC,QAAQ,SAAS,MAAM,YAAY,QAAQ,YAAY;AAC/E,MAAI,IAAI,aAAa,UAAa,OAAO,IAAI,aAAa,UAAW,QAAO,KAAK,EAAE,QAAQ,IAAI,OAAO,YAAY,SAAS,GAAG,KAAK,iCAAiC,CAAC;AAErK,QAAM,gBAAgB,MAAM,YAAY,QAAQ,KAAK,KAAK,aAAa,IAAI;AAC3E,QAAM,QAAQ,CAAC,UAAgD,UAAU,SAAS,UAAU,SAAS,QAAQ;AAE7G,QAAM,WAAW,KAAK,MAAM,IAAI,QAAQ,KAAK,KAAK,YAAY,QAAQ,WAAW;AACjF,QAAM,YAAY,MAAM,IAAI,SAAS,KAAK,KAAK,cAAc,KAAK,QAAQ,YAAY;AAEtF,QAAM,WAAmB,CAAC;AAC1B,MAAI,MAAM,QAAQ,IAAI,QAAQ,GAAG;AAC/B,eAAW,KAAK,IAAI,UAAU;AAC5B,YAAM,QAAQ,YAAY,GAAG,SAAS,EAAE,QAAQ,EAAE,OAAO,WAAW,UAAU,SAAS,GAAG,UAAU,MAAM,CAAC;AAC3G,eAAS,KAAK,MAAM,IAAI;AACxB,aAAO,KAAK,GAAG,MAAM,MAAM;AAC3B,cAAQ,KAAK,GAAG,MAAM,OAAO;AAC7B,kBAAY,KAAK,GAAG,MAAM,WAAW;AACrC,iBAAW,CAAC,KAAK,GAAG,KAAK,MAAM,QAAS,SAAQ,IAAI,KAAK,GAAG;AAAA,IAC9D;AAAA,EACF;AAEA,QAAM,SAAS;AAAA,IACb;AAAA,IACA,OAAO,OAAO,IAAI,SAAS,CAAC;AAAA,IAC5B;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc,MAAM,QAAQ,IAAI,YAAY,IAAI,IAAI,aAAa,IAAI,MAAM,IAAI,KAAK,gBAAgB,CAAC;AAAA;AAAA,IAErG,QAAQ,UAAU,YAAY,SAAY,KAAK,IAAI,MAAM,KAAK,KAAK,WAAW,KAAK,eAAe,SAAS,SAAY;AAAA,IACvH,WAAW,MAAM,QAAQ,IAAI,SAAS,IAClC,IAAI,UAAU,IAAI,CAAC,MAAO,SAAS,CAAC,IAAI,IAAI,CAAC,CAAE,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,OAAO,EAAE,SAAS,CAAC,GAAG,aAAa,OAAO,EAAE,eAAe,EAAE,GAAG,WAAW,MAAM,EAAE,IACzJ,KAAK;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,oBAAoB,MAAM,QAAQ,IAAI,kBAAkB,IAAI,IAAI,mBAAmB,IAAI,MAAM,IAAI,KAAK;AAAA,IACtG,KAAK,UAAU,YAAY,SAAY;AAAA,IACvC,UAAU,OAAO,IAAI,aAAa,YAAY,IAAI,WAAW,KAAK;AAAA,IAClE,QAAQ,UAAU,YAAY,SAAY,OAAO,gBAAgB,IAAI,QAAQ,KAAK,MAAM,IAAI,WAAW,IAAI,MAAM;AAAA,IACjH,GAAG,KAAK;AAAA,IACR,GAAI,UAAU,QAAQ,KAAK,OAAO,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;AAAA,IACzD,GAAI,YAAY,gBAAgB,KAAK,IAAI,IAAI,CAAC;AAAA,IAC9C,GAAI,eAAe,EAAE,UAAU,KAAc,IAAI,CAAC;AAAA,EACpD;AACA,MAAI,WAAW,UAAU,YAAY,SAAY,KAAK;AACtD,MAAI,cAAc;AAClB,OAAK,MAAM,cAAc,QAAQ,QAAQ,SAAS,cAAc,GAAG;AACjE,UAAM,WAAW,kBAAkB;AAAA,MACjC,QAAQ,QAAQ,SAAS,SAAS;AAAA,MAClC,MAAM,EAAE,GAAG,WAAW,MAAM,GAAG,SAAS;AAAA,MACxC,MAAM,OAAO,EAAE,gBAAgB,KAAK,kBAAkB,gBAAgB,eAAe,KAAK,eAAe,UAAU,KAAK,SAAS,IAAI;AAAA,MACrI;AAAA,MACA,SAAS,EAAE,gBAAgB,CAAC,GAAG,GAAG,QAAQ,QAAQ,aAAa,QAAQ,aAAa,mBAAmB,QAAQ,kBAAkB;AAAA,IACnI,CAAC;AACD,QAAI,CAAC,SAAS,IAAI;AAEhB,aAAO,KAAK,EAAE,QAAQ,IAAI,OAAO,SAAS,UAAU,aAAa,aAAa,SAAS,OAAO,SAAS,GAAG,KAAK,KAAK,SAAS,KAAK,GAAG,CAAC;AAAA,IACxI,OAAO;AAEL,iBAAW,YAAY,SAAY,SAAS,KAAK;AACjD,oBAAc,SAAS,KAAK;AAC5B,kBAAY,KAAK,GAAG,SAAS,WAAW;AAAA,IAC1C;AAAA,EACF;AAEA,MAAI,aAAa,UAAa,YAAY,CAAC,QAAQ,YAAa,YAAW;AAE3E,QAAM,OAAO,WAAW,EAAE,GAAG,QAAQ,eAAe,aAAa,SAAS,CAAC;AAC3E,MAAI,MAAM,QAAQ,IAAI,MAAM,EAAG,aAAY,IAAI,MAAM,IAAI,MAAM;AAC/D,SAAO,EAAE,MAAM,QAAQ,SAAS,SAAS,YAAY;AACvD;AAGO,SAAS,iBAAiB,OAAwB,SAA2D;AAClH,MAAI,CAAC,QAAS,QAAO,CAAC;AACtB,SAAO,wBAAwB,KAAK,EACjC,OAAO,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,QAAQ,EAAE,SAAS,gBAAgB,CAAC,QAAQ,SAAS,EAAE,cAAc,CAAC,EAC1G,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,OAAO;AAAA,IAC7B,QAAQ,EAAE;AAAA,IACV,OAAO;AAAA,IACP,SAAS,GAAG,UAAU,EAAE,OAAO,QAAQ,KAAK,CAAC,gCAAgC,EAAE,cAAc,uBAAuB,QAAQ,KAAK,IAAI,CAAC;AAAA,EACxI,EAAE;AACN;AAWO,SAAS,oBACd,OACA,SACA,aACA,aAA+C,CAAC,GAC/B;AACjB,QAAM,OAAO,wBAAwB,KAAK;AAC1C,QAAM,SAA0B,CAAC;AACjC,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,OAAO,IAAI,IAAI,MAAM,QAAQ,CAAC,MAAM,EAAE,MAAM,QAAQ,CAAC,CAAC,CAAC;AAC7D,aAAW,EAAE,MAAM,GAAG,OAAO,KAAK,MAAM;AACtC,UAAM,QAAQ,UAAU,EAAE,OAAO,QAAQ,KAAK;AAC9C,UAAM,OAAO,CAAC,OAAe,YAAoB,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,OAAO,QAAQ,CAAC;AAC7F,QAAI,KAAK,IAAI,EAAE,EAAE,EAAG,MAAK,MAAM,GAAG,KAAK,YAAY,EAAE,EAAE,kGAAkG;AACzJ,SAAK,IAAI,EAAE,EAAE;AACb,QAAI,EAAE,aAAa,UAAa,OAAO,EAAE,aAAa,UAAW,MAAK,YAAY,GAAG,KAAK,gCAAgC;AAE1H,UAAM,WAAW,cAAc,mBAAmB,YAAY,EAAE,cAAc,CAAC,IAAI;AACnF,QAAI,EAAE,aAAa,EAAE,SAAS,QAAQ,WAAW,QAAQ,EAAE,OAAO,KAAK,IAAI,EAAE,EAAE,KAC1E,aAAa,UAAa,EAAE,aAAa,WAAW;AACvD,WAAK,YAAY,GAAG,KAAK,0EAA0E;AAAA,IACrG;AACA,QAAI,EAAE,aAAa,SAAS,EAAE,aAAa,EAAE,UAAU,SAAS,GAAG;AACjE,WAAK,aAAa,GAAG,KAAK,uFAAuF;AAAA,IACnH;AACA,QAAI,EAAE,SAAS,UAAU,EAAE,aAAa,EAAE,cAAc,QAAQ;AAC9D,WAAK,aAAa,QAAQ,KAAK,mBAAmB,EAAE,SAAS,2CAA2C;AAAA,IAC1G;AACA,UAAM,aAAa,EAAE,OAAO,EAAE,SAAS,WAAW,oBAAoB,EAAE,MAAM,WAAW,IAAI,IAAI;AACjG,QAAI,WAAY,MAAK,OAAO,GAAG,KAAK,IAAI,UAAU,EAAE;AACpD,QAAI,EAAE,SAAS,UAAU;AAEvB,UAAI,WAAW,KAAM,MAAK,QAAQ,GAAG,KAAK,kGAAkG;AAC5I,UAAI,EAAE,UAAU,OAAQ,MAAK,YAAY,GAAG,KAAK,qGAAqG;AACtJ,YAAM,QAAQ,kBAAkB,CAAC;AACjC,UAAI,MAAM,SAAS,EAAG,MAAK,MAAM,CAAC,GAAG,GAAG,KAAK,IAAI,oBAAoB,KAAK,CAAC,EAAE;AAAA,IAC/E;AACA,QAAI,EAAE,SAAS,aAAa;AAE1B,UAAI,WAAW,KAAM,MAAK,QAAQ,GAAG,KAAK,8DAA8D;AACxG,UAAI,EAAE,UAAU,OAAQ,MAAK,YAAY,GAAG,KAAK,yFAAyF;AAAA,IAC5I;AACA,eAAW,KAAK,iBAAiB,CAAC,EAAG,MAAK,EAAE,OAAO,GAAG,KAAK,IAAI,EAAE,OAAO,EAAE;AAC1E,QAAI,EAAE,OAAO,EAAE,aAAa,UAAa,EAAE,aAAa,mBAAmB,cAAc,EAAE,cAAc,CAAC,GAAG;AAC3G,WAAK,YAAY,GAAG,KAAK,sFAAsF;AAAA,IACjH;AAAA,EACF;AACA,SAAO,KAAK,GAAG,iBAAiB,OAAO,OAAO,CAAC;AAC/C,SAAO,KAAK,GAAG,WAAW,KAAK,CAAC;AAChC,SAAO,KAAK,GAAG,iBAAiB,OAAO,EAAE,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC,GAAI,GAAG,WAAW,CAAC,CAAC;AAClG,aAAW,EAAE,MAAM,GAAG,OAAO,KAAK,MAAM;AAEtC,eAAW,SAAS,uBAAuB,OAAO,EAAE,IAAI,EAAE,aAAa,OAAO,CAAC,OAAO,OAAO,EAAE,EAAE,CAAC,GAAG;AACnG,aAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,OAAO,gBAAgB,SAAS,GAAG,UAAU,EAAE,OAAO,QAAQ,KAAK,CAAC,KAAK,KAAK,GAAG,CAAC;AAAA,IAChH;AAAA,EACF;AACA,QAAM,QAAQ,UAAU,KAAK,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AAG/C,MAAI,MAAO,QAAO,KAAK,EAAE,QAAQ,MAAM,CAAC,EAAE,IAAI,OAAO,gBAAgB,SAAS,8BAA8B,CAAC,GAAG,OAAO,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,IAAI,EAAE,KAAK,GAAG,EAAE,KAAK,UAAK,CAAC,GAAG,CAAC;AAC3K,SAAO;AACT;AAGO,SAAS,UAAU,OAAuC;AAC/D,SAAO,oBAAoB,KAAK;AAClC;AAGO,SAAS,YAAY,OAAuC;AACjE,SAAO,UAAU,KAAK,IAAI,CAAC,EAAE,SAAS;AACxC;","names":["text","text","escaped","reason","id","text"]}
|
|
@@ -5,12 +5,13 @@ import {
|
|
|
5
5
|
escapeControlCharsInStrings,
|
|
6
6
|
extractObjectsWithKey,
|
|
7
7
|
plannedTask,
|
|
8
|
+
scopeOverlaps,
|
|
8
9
|
stripTrailingCommas,
|
|
9
10
|
taskWhere
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-2IFKPYPO.mjs";
|
|
11
12
|
import {
|
|
12
13
|
flattenTasksWithParents
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-PKJTN2PD.mjs";
|
|
14
15
|
|
|
15
16
|
// src/services/PlanValidator.ts
|
|
16
17
|
function parsePlanJson(raw, runners, runnerModes, autonomousDefault = false) {
|
|
@@ -48,7 +49,7 @@ function parsePlanObject(json, raw, runners, runnerModes, autonomousDefault = fa
|
|
|
48
49
|
const [first] = result.errors;
|
|
49
50
|
throw new PlanParseError(first.message, raw, { semantic: first.taskId !== void 0 });
|
|
50
51
|
}
|
|
51
|
-
function validatePlanTasks(obj, runners, runnerModes, autonomousDefault = false) {
|
|
52
|
+
function validatePlanTasks(obj, runners, runnerModes, autonomousDefault = false, delegation = {}) {
|
|
52
53
|
const rawTasks = isRecord(obj) ? obj.tasks : void 0;
|
|
53
54
|
if (!Array.isArray(rawTasks)) {
|
|
54
55
|
return { ok: false, errors: [{ field: "tasks", message: "Invalid plan: missing tasks array" }] };
|
|
@@ -56,7 +57,7 @@ function validatePlanTasks(obj, runners, runnerModes, autonomousDefault = false)
|
|
|
56
57
|
if (rawTasks.length === 0) {
|
|
57
58
|
return { ok: false, errors: [{ field: "tasks", message: "Plan contained no tasks" }] };
|
|
58
59
|
}
|
|
59
|
-
const planned = rawTasks.map((t) => plannedTask(t, { runners, runnerModes, autonomousDefault }));
|
|
60
|
+
const planned = rawTasks.map((t) => plannedTask(t, { runners, runnerModes, autonomousDefault, ...delegation }));
|
|
60
61
|
const tasks = planned.map((p) => p.task);
|
|
61
62
|
const errors = [
|
|
62
63
|
...sliceRequired(tasks),
|
|
@@ -67,7 +68,8 @@ function validatePlanTasks(obj, runners, runnerModes, autonomousDefault = false)
|
|
|
67
68
|
const ignored = planned.flatMap((p) => p.ignored);
|
|
68
69
|
const warnings = [
|
|
69
70
|
...ignored.some((i) => i.field === "taskMode") ? [`"taskMode" is not yours to set and was ignored: each task runs in its runner's mode for the user's autonomy level, or its read-only mode when you set "readOnly": true.`] : [],
|
|
70
|
-
...ignored.filter((i) => i.field === "readOnly").map((i) => `${i.message}: it was ignored.`)
|
|
71
|
+
...ignored.filter((i) => i.field === "readOnly").map((i) => `${i.message}: it was ignored.`),
|
|
72
|
+
...scopeOverlaps(tasks)
|
|
71
73
|
];
|
|
72
74
|
return warnings.length > 0 ? { ok: true, tasks, warnings } : { ok: true, tasks };
|
|
73
75
|
}
|
|
@@ -94,4 +96,4 @@ export {
|
|
|
94
96
|
validatePlanTasks,
|
|
95
97
|
looksLikePlanAttempt
|
|
96
98
|
};
|
|
97
|
-
//# sourceMappingURL=chunk-
|
|
99
|
+
//# sourceMappingURL=chunk-FX33UKAD.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/services/PlanValidator.ts"],"sourcesContent":["import { Task, RunnerId, flattenTasksWithParents } from '../models/Task';\nimport { extractObjectsWithKey, stripTrailingCommas, escapeControlCharsInStrings, PlanParseError, PLAN_ENVELOPE_KEY } from './JsonExtractor';\nimport type { RunnerModeInfo } from './ModeResolver';\nimport { scopeOverlaps } from '../models/Delegation';\nimport { plannedTask, checkPlanInvariants, taskWhere, type IntakeCatalog, type PlanTaskError } from './PlannedTask';\n\nexport function parsePlanJson(\n raw: string,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = false,\n): Task[] {\n const { matches, fallback, sawUnbalanced } = extractObjectsWithKey(raw, PLAN_ENVELOPE_KEY);\n\n // A reply can carry several tasks-keyed objects — a schema echo from the\n // prompt, an inline draft, then the real plan. The model's LAST emission is\n // its final answer, so candidates are tried back to front and the first one\n // that fully parses and validates wins.\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 parsePlanObject(json, raw, runners, runnerModes, autonomousDefault);\n } catch (err) {\n if (!(err instanceof PlanParseError)) throw err;\n // Prefer surfacing the error from the most plan-like candidate: the\n // last one carrying a tasks key (tried first).\n if (!lastError) lastError = err;\n }\n }\n\n // No usable tasks object anywhere, but an object ran off the end of the\n // text: the plan was almost certainly cut off mid-stream.\n if (matches.length === 0 && sawUnbalanced) {\n throw new PlanParseError(\n 'Plan response appears truncated: the model likely hit its output length limit before finishing the JSON.',\n raw,\n { truncated: true },\n );\n }\n throw lastError ?? new PlanParseError('Invalid plan: missing tasks array', raw);\n}\n\nfunction parsePlanObject(\n json: string,\n raw: string,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = false,\n): Task[] {\n const cleaned = stripTrailingCommas(escapeControlCharsInStrings(json));\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(cleaned);\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n throw new PlanParseError(`Plan response was not valid JSON: ${detail}`, raw);\n }\n\n const result = validatePlanTasks(parsed, runners, runnerModes, autonomousDefault);\n if (result.ok) return result.tasks;\n const [first] = result.errors;\n // An envelope problem (no tasks array, an empty one) keeps the generic\n // re-emit; only a rule broken by a task is worth naming in the corrective.\n throw new PlanParseError(first.message, raw, { semantic: first.taskId !== undefined });\n}\n\nexport type { PlanTaskError } from './PlannedTask';\nexport { requestedSkills } from './PlannedTask';\n\n/** `warnings` name what was accepted but not used, for a channel that can tell the planner. */\nexport type PlanTasksResult = { ok: true; tasks: Task[]; warnings?: string[] } | { ok: false; errors: PlanTaskError[] };\n\n/**\n * Every check a plan's tasks must pass, on an already-parsed `{ tasks }`\n * object — what a plan is held to whichever channel it arrived on. All\n * problems are reported, the slice classification first, so the first is the\n * one the text path's corrective names.\n */\nexport function validatePlanTasks(\n obj: unknown,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = false,\n delegation: Pick<IntakeCatalog, 'delegationRefusal' | 'sealsScripts'> = {},\n): PlanTasksResult {\n const rawTasks = isRecord(obj) ? obj.tasks : undefined;\n if (!Array.isArray(rawTasks)) {\n return { ok: false, errors: [{ field: 'tasks', message: 'Invalid plan: missing tasks array' }] };\n }\n if (rawTasks.length === 0) {\n return { ok: false, errors: [{ field: 'tasks', message: 'Plan contained no tasks' }] };\n }\n\n const planned = rawTasks.map((t) => plannedTask(t, { runners, runnerModes, autonomousDefault, ...delegation }));\n const tasks = planned.map((p) => p.task);\n const errors = [\n ...sliceRequired(tasks),\n ...planned.flatMap((p) => p.errors),\n ...checkPlanInvariants(tasks, runners, runnerModes),\n ];\n\n if (errors.length > 0) return { ok: false, errors };\n const ignored = planned.flatMap((p) => p.ignored);\n const warnings = [\n ...(ignored.some((i) => i.field === 'taskMode')\n ? ['\"taskMode\" is not yours to set and was ignored: each task runs in its runner\\'s mode for the user\\'s autonomy level, or its read-only mode when you set \"readOnly\": true.']\n : []),\n ...ignored.filter((i) => i.field === 'readOnly').map((i) => `${i.message}: it was ignored.`),\n ...scopeOverlaps(tasks),\n ];\n return warnings.length > 0 ? { ok: true, tasks, warnings } : { ok: true, tasks };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Whether a reply that failed {@link parsePlanJson} actually LOOKED like a\n * plan attempt — a balanced tasks-keyed object, or JSON that got cut off.\n * Distinguishes \"the model tried to emit a plan and botched it\" (worth a\n * corrective retry) from prose that merely mentions `\"tasks\"` (leave alone).\n */\nexport function looksLikePlanAttempt(raw: string): boolean {\n const { matches, sawUnbalanced } = extractObjectsWithKey(raw, PLAN_ENVELOPE_KEY);\n if (matches.length > 0) return true;\n return sawUnbalanced && raw.includes(`\"${PLAN_ENVELOPE_KEY}\"`);\n}\n\n/**\n * A whole plan says how each task is sliced: an edit may leave it to the\n * task's parent or the tasks it was made from, a submitted plan may not.\n */\nfunction sliceRequired(tasks: readonly Task[]): PlanTaskError[] {\n return flattenTasksWithParents(tasks).flatMap(({ task: t, parent }) => {\n const where = taskWhere(t.title, parent?.title);\n const errors: PlanTaskError[] = [];\n if (!t.sliceType) errors.push({ taskId: t.id, field: 'sliceType', message: `${where} is missing sliceType. Every task must specify sliceType (\"AFK\" or \"HITL\").` });\n if (t.type === 'ai' && !t.autonomy) errors.push({ taskId: t.id, field: 'autonomy', message: `AI ${where} is missing autonomy. Every AI task must specify autonomy (\"AFK\" or \"HITL\").` });\n return errors;\n });\n}\n"],"mappings":"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","names":[]}
|