zidane 4.1.4 → 4.1.6
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/README.md +3 -3
- package/dist/{agent-BoV5Twdl.d.ts → agent-BAoqUvwA.d.ts} +27 -1
- package/dist/{agent-BoV5Twdl.d.ts.map → agent-BAoqUvwA.d.ts.map} +1 -1
- package/dist/{index-28otmfLX.d.ts → index-B8-yNSsk.d.ts} +2 -2
- package/dist/index-B8-yNSsk.d.ts.map +1 -0
- package/dist/{index-DPsd0qwm.d.ts → index-CqpNqjDy.d.ts} +2 -2
- package/dist/{index-DPsd0qwm.d.ts.map → index-CqpNqjDy.d.ts.map} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/mcp.d.ts +1 -1
- package/dist/{presets-Cs7_CsMk.js → presets-BzkJDW1K.js} +3 -3
- package/dist/presets-BzkJDW1K.js.map +1 -0
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/{providers-CX-R-Oy-.js → providers-CCDvIXGJ.js} +26 -5
- package/dist/providers-CCDvIXGJ.js.map +1 -0
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +1 -1
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/skills.d.ts +2 -2
- package/dist/{stats-DoKUtF5T.js → stats-BT9l57RS.js} +34 -2
- package/dist/stats-BT9l57RS.js.map +1 -0
- package/dist/{tools-DpeWKzP1.js → tools-C8kDot0H.js} +73 -23
- package/dist/tools-C8kDot0H.js.map +1 -0
- package/dist/tools.d.ts +2 -2
- package/dist/tools.js +1 -1
- package/dist/tui.d.ts +423 -80
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +1604 -250
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.js +1 -1
- package/package.json +1 -1
- package/dist/index-28otmfLX.d.ts.map +0 -1
- package/dist/presets-Cs7_CsMk.js.map +0 -1
- package/dist/providers-CX-R-Oy-.js.map +0 -1
- package/dist/stats-DoKUtF5T.js.map +0 -1
- package/dist/tools-DpeWKzP1.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools-C8kDot0H.js","names":["DEFAULT_LIMIT","readFile","writeFile"],"sources":["../src/aliasing.ts","../src/tools/read-state.ts","../src/dedup-tools.ts","../src/tools/validation.ts","../src/loop.ts","../src/prompt.ts","../src/tool-budgets.ts","../src/tools/binary-detect.ts","../src/tools/skills-read.ts","../src/tools/shell-quote.ts","../src/tools/skills-run-script.ts","../src/tools/skills-use.ts","../src/tools/tool-search.ts","../src/agent.ts","../src/tools/edit-utils.ts","../src/tools/path-suggest.ts","../src/tools/edit.ts","../src/tools/glob.ts","../src/tools/grep.ts","../src/tools/interaction.ts","../src/tools/list-files.ts","../src/tools/multi-edit.ts","../src/tools/binary-read.ts","../src/tools/read-file.ts","../src/tools/shell-semantics.ts","../src/tools/shell.ts","../src/tools/spawn.ts","../src/tools/write-file.ts"],"sourcesContent":["/**\n * Tool-name aliasing helpers.\n *\n * Aliasing is applied at the LLM boundary only: the provider sees the aliased\n * name, but hooks and persisted turns use canonical names. See `AgentOptions.toolAliases`.\n */\n\nimport type { SessionContentBlock, SessionMessage } from './types'\n\n/** Forward + reverse lookup between canonical and aliased tool names */\nexport interface AliasMaps {\n /** canonical → alias (only entries where alias !== canonical) */\n aliasByCanonical: Map<string, string>\n /** alias → canonical (only entries where alias !== canonical) */\n canonicalByAlias: Map<string, string>\n}\n\n/**\n * Build alias lookup maps from a `toolAliases` record.\n *\n * Validates:\n * - No two canonical names map to the same alias (collision).\n * - No alias collides with another canonical tool name (would shadow).\n *\n * Silently ignores alias entries whose canonical name isn't in `canonicalNames` —\n * preset/agent authors can declare aliases for tools that may be added later via MCP.\n *\n * @param aliases - The `toolAliases` map from the agent options.\n * @param canonicalNames - All tool canonical names currently in scope (agent + MCP).\n */\nexport function buildAliasMaps(\n aliases: Record<string, string> | undefined,\n canonicalNames: Iterable<string>,\n): AliasMaps {\n const aliasByCanonical = new Map<string, string>()\n const canonicalByAlias = new Map<string, string>()\n\n if (!aliases) {\n return { aliasByCanonical, canonicalByAlias }\n }\n\n const canonicalSet = new Set(canonicalNames)\n\n // A canonical name is \"genuinely remapped\" when it has an alias entry that is\n // both non-empty and different from itself. Identity aliases or missing keys\n // mean the tool still answers to its canonical name on the wire.\n function isRemappedAway(canonical: string): boolean {\n const mapped = aliases![canonical]\n return typeof mapped === 'string' && mapped.length > 0 && mapped !== canonical\n }\n\n for (const [canonical, alias] of Object.entries(aliases)) {\n if (typeof alias !== 'string' || alias.length === 0)\n throw new Error(`Tool alias for \"${canonical}\" must be a non-empty string`)\n\n if (alias === canonical)\n continue\n\n if (!canonicalSet.has(canonical))\n continue\n\n // When the alias matches an existing canonical tool name, only allow it if\n // that other canonical is itself being remapped away (i.e. a name swap).\n // Otherwise the wire name would shadow a real tool.\n if (canonicalSet.has(alias) && !isRemappedAway(alias)) {\n throw new Error(`Tool alias \"${canonical}\" -> \"${alias}\" collides with an existing canonical tool name`)\n }\n\n const existingCanonical = canonicalByAlias.get(alias)\n if (existingCanonical && existingCanonical !== canonical) {\n throw new Error(\n `Tool alias collision: both \"${existingCanonical}\" and \"${canonical}\" map to alias \"${alias}\"`,\n )\n }\n\n aliasByCanonical.set(canonical, alias)\n canonicalByAlias.set(alias, canonical)\n }\n\n return { aliasByCanonical, canonicalByAlias }\n}\n\n/** Return the alias for a canonical name, falling back to the canonical name itself. */\nexport function toWireName(canonical: string, maps: AliasMaps): string {\n return maps.aliasByCanonical.get(canonical) ?? canonical\n}\n\n/** Return the canonical name for a wire name, falling back to the wire name itself. */\nexport function toCanonicalName(wire: string, maps: AliasMaps): string {\n return maps.canonicalByAlias.get(wire) ?? wire\n}\n\n/**\n * Rewrite `tool_call` block names in a content array from canonical → wire for outbound\n * messages sent to the provider. Mutation is non-destructive (returns a new array).\n */\nexport function rewriteContentToWire(\n content: SessionContentBlock[],\n maps: AliasMaps,\n): SessionContentBlock[] {\n if (maps.aliasByCanonical.size === 0)\n return content\n return content.map((block) => {\n if (block.type !== 'tool_call')\n return block\n const wire = maps.aliasByCanonical.get(block.name)\n if (!wire || wire === block.name)\n return block\n return { ...block, name: wire }\n })\n}\n\n/**\n * Rewrite `tool_call` block names in a content array from wire → canonical for inbound\n * messages received from the provider. Non-destructive.\n */\nexport function rewriteContentToCanonical(\n content: SessionContentBlock[],\n maps: AliasMaps,\n): SessionContentBlock[] {\n if (maps.canonicalByAlias.size === 0)\n return content\n return content.map((block) => {\n if (block.type !== 'tool_call')\n return block\n const canonical = maps.canonicalByAlias.get(block.name)\n if (!canonical || canonical === block.name)\n return block\n return { ...block, name: canonical }\n })\n}\n\n/**\n * Rewrite every `SessionMessage.content` in an array from canonical → wire.\n * Returns a new array of new message objects — input messages are not mutated.\n * When the alias map is empty, returns the input by reference (no allocation).\n */\nexport function rewriteMessagesToWire(\n messages: SessionMessage[],\n maps: AliasMaps,\n): SessionMessage[] {\n if (maps.aliasByCanonical.size === 0)\n return messages\n return messages.map(msg => ({ ...msg, content: rewriteContentToWire(msg.content, maps) }))\n}\n","/**\n * Per-session file read tracking.\n *\n * Shared between `read_file` (dedup re-reads) and `edit` / `multi_edit`\n * (read-before-edit guard). Keyed by Session instance via a WeakMap so\n * the state lives as long as the session does and is GC'd along with it\n * — no public schema changes, no persistence.\n *\n * The state map records, per absolute file path:\n * - `contentHash` — a fast non-cryptographic hash of the bytes that the\n * model last saw (post-truncation). Identical re-reads with the same\n * slice (offset/limit/maxBytes) return a stub instead of re-emitting\n * the bytes; edits compare against this hash to detect stale content.\n * - `slice` — the (offset, limit, maxBytes) tuple for the last read so\n * we don't dedup a different slice as \"unchanged\".\n * - `mtimeMs` — wall-clock at last read, for diagnostics only.\n */\n\nimport type { Session } from '../session'\nimport type { ToolResultContent } from '../types'\n\nexport interface ReadStateEntry {\n contentHash: string\n /** Slice parameters for the last read. */\n offset: number\n limit: number\n maxBytes: number\n /**\n * Whether the prior read emitted line-number prefixes. Tracked so a\n * read with `lineNumbers: true` doesn't dedup against one with\n * `lineNumbers: false` (or vice versa) — the dedup stub would mislead\n * the model about the prior output's shape.\n */\n lineNumbers?: boolean\n /** Wall-clock at last read — diagnostic only, not used for invalidation. */\n mtimeMs: number\n}\n\nexport type ReadStateMap = Map<string, ReadStateEntry>\n\nconst STATE = new WeakMap<Session, ReadStateMap>()\n\n/**\n * Get or lazily create the per-session read-state map. Returns `undefined`\n * when no session is provided — tools should treat that as \"no dedup, no\n * guard\": the state has nowhere to live, so every read is fresh.\n */\nexport function getReadState(session: Session | undefined): ReadStateMap | undefined {\n if (!session)\n return undefined\n let map = STATE.get(session)\n if (!map) {\n map = new Map()\n STATE.set(session, map)\n }\n return map\n}\n\n/**\n * Per-tool dedup state — backs `behavior.dedupTools`. Records the most recent\n * `(hash, result)` per tool (canonical name) within a session. The same\n * WeakMap-keyed-on-Session pattern as the read-state map: state lives as long\n * as the session does and is GC'd along with it.\n */\nexport interface ToolDedupEntry {\n hash: string\n result: string | ToolResultContent[]\n}\n\nexport type ToolDedupMap = Map<string, ToolDedupEntry>\n\nconst TOOL_DEDUP_STATE = new WeakMap<Session, ToolDedupMap>()\n\n/**\n * Get or lazily create the per-session tool-dedup map. Returns `undefined`\n * when no session is provided — middleware should treat that as \"no dedup\".\n */\nexport function getToolDedupState(session: Session | undefined): ToolDedupMap | undefined {\n if (!session)\n return undefined\n let map = TOOL_DEDUP_STATE.get(session)\n if (!map) {\n map = new Map()\n TOOL_DEDUP_STATE.set(session, map)\n }\n return map\n}\n\n/**\n * FNV-1a 32-bit hash, hex-encoded. Fast, non-cryptographic — we only need\n * collision resistance against accidental matches between different file\n * contents within one session (~1 in 4 billion). Cheaper than allocating\n * a Buffer and pulling in `crypto`.\n */\nexport function hashContent(text: string): string {\n let h = 0x811C9DC5\n for (let i = 0; i < text.length; i++) {\n h ^= text.charCodeAt(i)\n h = (h + ((h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24))) >>> 0\n }\n return h.toString(16).padStart(8, '0')\n}\n","/**\n * `dedup-tools` middleware — generic per-tool argument deduplication on top\n * of the `tool:gate` writable-`result` slot.\n *\n * Mirrors the WeakMap-keyed-on-Session pattern that backs `read_file` dedup\n * (`src/tools/read-state.ts`), generalized to arbitrary tools whose hasher\n * is supplied by the consumer via `behavior.dedupTools`.\n *\n * Wiring:\n * 1. `tool:gate` — if a hasher is registered for the tool and produces a\n * string equal to the prior recorded hash, set `ctx.result` to the prior\n * payload. The Z20 substitute path takes over from there: skip execute,\n * fire `tool:after` / `tool:transform`, surface the substitute as a\n * successful tool_result.\n * 2. `tool:after` — record `(hash, result)` for the current input so the\n * NEXT identical call dedups. Recorded post-`tool:transform`, i.e. the\n * payload the model actually saw — replaying a pre-transform value\n * would give the model different content on the dedup hit than on the\n * original call.\n *\n * No-session runs are silent no-ops: there's nowhere to record state.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from './agent'\nimport type { Session } from './session'\nimport type { AgentBehavior, ToolHookContext, ToolResultContent } from './types'\nimport { getToolDedupState } from './tools/read-state'\n\n/**\n * Install the per-tool argument-dedup middleware on a hook bus.\n * `getDedupTools` returns the resolved per-tool hashers (run override merged\n * with agent defaults). `getSession` does the same for the session-bound\n * state. Both are called lazily so handlers attached after install (e.g. via\n * MCP bootstrap completion) can take effect.\n *\n * Returns an `uninstall` fn — the agent calls this in `finally` so handlers\n * never leak across runs.\n */\nexport function installDedupToolsGate(\n hooks: Hookable<AgentHooks>,\n getDedupTools: () => AgentBehavior['dedupTools'] | undefined,\n getSession: () => Session | undefined,\n): () => void {\n // Track the hash *we* selected per `(callId, name)` so the corresponding\n // `tool:after` records the right entry. Necessary because `ctx.input` on\n // `tool:after` could in principle differ from the gate snapshot if a\n // `tool:gate` mutation rewrote `input` — and re-hashing there would emit a\n // dedup entry against a different fingerprint than the model's input.\n //\n // Cleared in the same `tool:after` handler after recording. If `tool:after`\n // never fires (gate `block` path), the entry is left dangling — bounded by\n // the run lifetime since the hook bus tears down with the run.\n const pending = new Map<string, string>()\n\n function pendingKey(callId: string, name: string): string {\n return `${callId}::${name}`\n }\n\n function gateHandler(ctx: ToolHookContext & {\n block: boolean\n reason: string\n result?: string | ToolResultContent[]\n runToolCounts: Readonly<Record<string, number>>\n }) {\n // Don't override prior gate handlers (block, or another middleware that\n // already substituted a result).\n if (ctx.block || ctx.result !== undefined)\n return\n\n const dedupTools = getDedupTools()\n const hasher = dedupTools?.[ctx.name]\n if (!hasher)\n return\n\n const session = getSession()\n const state = getToolDedupState(session)\n if (!state)\n return\n\n let hash: string | undefined\n try {\n hash = hasher(ctx.input)\n }\n catch {\n // A throwing hasher disables dedup for this call only — never\n // surface it as a tool failure. The model still gets the real\n // execution, telemetry consumers see no surprise.\n return\n }\n if (typeof hash !== 'string' || hash.length === 0)\n return\n\n const prior = state.get(ctx.name)\n if (prior && prior.hash === hash) {\n // Hit — replay the prior result verbatim. The consumer's hasher is the\n // source of truth on \"still valid\"; we don't manufacture a stub message\n // that second-guesses that.\n ctx.result = prior.result\n return\n }\n\n // Miss — remember the hash so the matching `tool:after` records it.\n pending.set(pendingKey(ctx.callId, ctx.name), hash)\n }\n\n function afterHandler(ctx: ToolHookContext & {\n result: string | ToolResultContent[]\n outputBytes: number\n }) {\n const key = pendingKey(ctx.callId, ctx.name)\n const hash = pending.get(key)\n if (hash === undefined)\n return\n pending.delete(key)\n\n const session = getSession()\n const state = getToolDedupState(session)\n if (!state)\n return\n\n state.set(ctx.name, { hash, result: ctx.result })\n }\n\n const unregisterGate = hooks.hook('tool:gate', gateHandler)\n const unregisterAfter = hooks.hook('tool:after', afterHandler)\n\n return function uninstall() {\n unregisterGate()\n unregisterAfter()\n pending.clear()\n }\n}\n","/**\n * Tool argument validation against JSON Schema-style inputSchema.\n *\n * Two passes:\n * 1. Required-field presence. Missing or null/undefined required fields fail.\n * 2. Top-level type checks with **best-effort coercion**. Small/OSS models\n * routinely send `\"true\"` for a `boolean` field or `\"42\"` for a `number`,\n * and rejecting outright forces a confusing retry. Instead, we auto-heal\n * coerce when the conversion is unambiguous, fail only when the value\n * cannot be reasonably normalized to any of the declared types.\n *\n * Nested validation is intentionally out of scope — keep it cheap and let the\n * tool's `execute` body assert deeper invariants.\n */\n\nexport interface ValidationResult {\n valid: boolean\n /** Human-readable reason. Present on failure only. */\n error?: string\n /**\n * Possibly-coerced input. Present iff `valid: true`. Tools should call\n * `execute(coercedInput, ctx)` so auto-healed values reach the tool body.\n * When no coercion was applied, this is reference-equal to the input.\n */\n coercedInput?: Record<string, unknown>\n /**\n * Names of fields whose values were coerced. Empty when nothing changed.\n * Useful for telemetry (`validation:reject` on failure already carries the\n * reason; this is the success-path equivalent).\n */\n coercions?: readonly string[]\n}\n\ninterface PropertySchema {\n type?: string | string[]\n enum?: unknown[]\n}\n\nconst TRUE_STRINGS = new Set(['true', 'True', 'TRUE', '1', 'yes', 'Yes', 'YES'])\nconst FALSE_STRINGS = new Set(['false', 'False', 'FALSE', '0', 'no', 'No', 'NO'])\n\nexport function validateToolArgs(\n input: Record<string, unknown>,\n schema: Record<string, unknown>,\n): ValidationResult {\n const required = (schema.required ?? []) as string[]\n const properties = (schema.properties ?? {}) as Record<string, PropertySchema>\n\n // Pass 1: required-field presence.\n for (const field of required) {\n if (!(field in input) || input[field] === undefined || input[field] === null) {\n return { valid: false, error: `Missing required field: ${field}` }\n }\n }\n\n // Pass 2: per-property type check with auto-coercion. Walk the input keys\n // (rather than schema properties) so unknown keys flow through unchanged.\n let coerced: Record<string, unknown> | undefined\n const coercions: string[] = []\n\n for (const [key, value] of Object.entries(input)) {\n const propSchema = properties[key]\n if (!propSchema?.type)\n continue\n if (value === undefined || value === null)\n continue\n\n const outcome = coerceValue(value, propSchema)\n if (outcome.error) {\n return { valid: false, error: `Field \"${key}\": ${outcome.error}` }\n }\n if (outcome.changed) {\n if (!coerced)\n coerced = { ...input }\n coerced[key] = outcome.value\n coercions.push(key)\n }\n }\n\n return {\n valid: true,\n coercedInput: coerced ?? input,\n coercions,\n }\n}\n\ninterface CoerceOutcome {\n /** Coerced value; equal to input when `changed: false`. */\n value: unknown\n changed: boolean\n error?: string\n}\n\nfunction coerceValue(value: unknown, schema: PropertySchema): CoerceOutcome {\n const declaredTypes = Array.isArray(schema.type)\n ? schema.type as string[]\n : [schema.type as string]\n\n // Already matches one of the declared types? No coercion, just enum-check.\n for (const t of declaredTypes) {\n if (matchesType(value, t)) {\n if (schema.enum && !schema.enum.includes(value)) {\n return {\n value,\n changed: false,\n error: `must be one of ${JSON.stringify(schema.enum)}, got ${formatValue(value)}`,\n }\n }\n return { value, changed: false }\n }\n }\n\n // Try coercion to each declared type in order; first success wins.\n for (const t of declaredTypes) {\n const coerced = tryCoerce(value, t)\n if (coerced.ok) {\n if (schema.enum && !schema.enum.includes(coerced.value)) {\n return {\n value,\n changed: false,\n error: `must be one of ${JSON.stringify(schema.enum)}, got ${formatValue(coerced.value)}`,\n }\n }\n return { value: coerced.value, changed: true }\n }\n }\n\n const expected = declaredTypes.join(' | ')\n return {\n value,\n changed: false,\n error: `expected ${expected}, got ${jsonType(value)} ${formatValue(value)}`,\n }\n}\n\nfunction matchesType(value: unknown, type: string): boolean {\n switch (type) {\n case 'string': return typeof value === 'string'\n case 'number': return typeof value === 'number' && Number.isFinite(value)\n case 'integer': return typeof value === 'number' && Number.isInteger(value)\n case 'boolean': return typeof value === 'boolean'\n case 'array': return Array.isArray(value)\n case 'object': return value !== null && typeof value === 'object' && !Array.isArray(value)\n case 'null': return value === null\n default: return true\n }\n}\n\nfunction tryCoerce(value: unknown, type: string): { ok: true, value: unknown } | { ok: false } {\n // string → other\n if (typeof value === 'string') {\n if (type === 'boolean') {\n const trimmed = value.trim()\n if (TRUE_STRINGS.has(trimmed))\n return { ok: true, value: true }\n if (FALSE_STRINGS.has(trimmed))\n return { ok: true, value: false }\n return { ok: false }\n }\n if (type === 'number') {\n const n = Number(value.trim())\n return Number.isFinite(n) ? { ok: true, value: n } : { ok: false }\n }\n if (type === 'integer') {\n const n = Number(value.trim())\n return Number.isInteger(n) ? { ok: true, value: n } : { ok: false }\n }\n if (type === 'array' || type === 'object') {\n try {\n const parsed = JSON.parse(value)\n if (type === 'array' && Array.isArray(parsed))\n return { ok: true, value: parsed }\n if (type === 'object' && parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed))\n return { ok: true, value: parsed }\n return { ok: false }\n }\n catch {\n return { ok: false }\n }\n }\n if (type === 'null') {\n return value === '' || value === 'null' ? { ok: true, value: null } : { ok: false }\n }\n }\n\n // number → string / integer\n if (typeof value === 'number' && Number.isFinite(value)) {\n if (type === 'string')\n return { ok: true, value: String(value) }\n if (type === 'integer' && Number.isInteger(value))\n return { ok: true, value }\n }\n\n // boolean → string\n if (typeof value === 'boolean' && type === 'string')\n return { ok: true, value: String(value) }\n\n return { ok: false }\n}\n\nfunction jsonType(value: unknown): string {\n if (value === null)\n return 'null'\n if (Array.isArray(value))\n return 'array'\n return typeof value\n}\n\nfunction formatValue(value: unknown): string {\n let s: string\n try {\n s = JSON.stringify(value)\n }\n catch {\n s = String(value)\n }\n if (s === undefined)\n s = String(value)\n return s.length > 80 ? `${s.slice(0, 77)}...` : s\n}\n","/**\n * Agent turn execution loop.\n *\n * Handles streaming, tool execution (sequential/parallel),\n * steering injection, follow-up messages, and abort.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from './agent'\nimport type { AliasMaps } from './aliasing'\nimport type { ExecutionContext, ExecutionHandle } from './contexts'\nimport type { Provider, StreamOptions, ToolCall, ToolResult, ToolSpec } from './providers'\nimport type { Session } from './session'\nimport type { SkillsConfig } from './skills/types'\nimport type { ToolContext, ToolDef } from './tools/types'\nimport type { AgentBehavior, AgentStats, McpServerConfig, SessionMessage, SessionTurn, ThinkingLevel, ToolExecutionMode, ToolResultContent, TurnUsage } from './types'\nimport { rewriteContentToCanonical, rewriteMessagesToWire, toCanonicalName, toWireName } from './aliasing'\nimport { AgentAbortedError, AgentProviderError, toTypedError } from './errors'\nimport { validateToolArgs } from './tools/validation'\nimport { toolOutputByteLength } from './types'\n\nexport interface LoopContext {\n provider: Provider\n hooks: Hookable<AgentHooks>\n /** Agent display name — forwarded into `ToolContext.name`. */\n agentName?: string\n /** Agent default system prompt — forwarded into `ToolContext.system`. */\n agentSystem?: string\n /** Source agent tools (pre-MCP-merge) — forwarded into `ToolContext.tools`. */\n agentTools: Record<string, ToolDef>\n /** Agent tool aliases — forwarded into `ToolContext.toolAliases`. */\n agentToolAliases?: Record<string, string>\n /** Agent MCP servers — forwarded into `ToolContext.mcpServers`. */\n agentMcpServers?: McpServerConfig[]\n /** Agent skills config — forwarded into `ToolContext.skills`. */\n agentSkills?: SkillsConfig\n /** Agent behavior defaults — forwarded into `ToolContext.behavior`. */\n agentBehavior?: AgentBehavior\n tools: Record<string, ToolDef>\n formattedTools: unknown[]\n /**\n * Recompute the wire-level tool list from the current state of the agent's\n * `unlocked` set. Set when `behavior.toolDisclosure === 'lazy'` and at least\n * one MCP tool is lazy — every iteration the loop calls this so newly-\n * surfaced tools (via `tool_search`) advertise on the next provider request.\n * When `undefined`, the loop uses {@link LoopContext.formattedTools} verbatim.\n */\n rebuildFormattedTools?: () => unknown[]\n aliasMaps: AliasMaps\n model: string\n system: string\n thinking: ThinkingLevel\n toolExecution: ToolExecutionMode\n signal: AbortSignal\n execution: ExecutionContext\n handle: ExecutionHandle\n steeringQueue: string[]\n followUpQueue: string[]\n turns: SessionTurn[]\n runId: string\n generateTurnId: () => string | Promise<string>\n /** Max loop iterations (default: 50) */\n maxTurns?: number\n /** Max tokens per LLM turn (default: 16384) */\n maxTokens?: number\n /** Exact thinking token budget (overrides level-based default) */\n thinkingBudget?: number\n /** JSON Schema for structured output enforcement */\n schema?: Record<string, unknown>\n /** Enable provider prompt caching (default: true). See `AgentBehavior.cache`. */\n cache?: boolean\n /** Soft cap on cumulative tool-output bytes per turn. See `AgentBehavior.toolOutputBudget`. */\n toolOutputBudget?: number\n /** Client-side compaction strategy. See `AgentBehavior.compactStrategy`. */\n compactStrategy?: 'off' | 'tail'\n /** Bytes threshold that triggers tail compaction. See `AgentBehavior.compactThreshold`. */\n compactThreshold?: number\n /** Trailing turns kept intact during tail compaction. See `AgentBehavior.compactKeepTurns`. */\n compactKeepTurns?: number\n /**\n * Elide `read_file` tool_results whose corresponding read happened before\n * a later successful edit/write of the same path. See\n * `AgentBehavior.elideStaleReads`.\n */\n elideStaleReads?: boolean\n /**\n * Wall-clock start time of the run (`Date.now()` when `runLoop` was invoked).\n * Used to compute `AgentStats.timeTillFirstTokenMs`.\n */\n runStartMs: number\n /** Session bound to this run, if any. Forwarded into `ToolContext.session`. */\n session?: Session\n /** Subagent depth for this run. Forwarded into `ToolContext.depth`. */\n depth?: number\n /**\n * Per-tool call counter for this run. Mutated by the dispatch path; surfaced\n * (frozen snapshot) on `tool:*` and `turn:after` hook contexts. Counts every\n * call the model dispatched — including ones short-circuited by a `tool:gate`\n * `result` substitution. Excludes calls a gate explicitly `block`ed.\n *\n * Scope: per-`runId`. Resumed sessions start a fresh counter.\n */\n runToolCounts: Record<string, number>\n /** Per-run thinking-budget decay schedule. See `AgentBehavior.thinkingDecay`. */\n thinkingDecay?: AgentBehavior['thinkingDecay']\n}\n\nconst IMAGE_OMITTED_MARKER = '[image omitted — model does not support vision]'\n\n/**\n * Compute the effective thinking budget for a given run-relative turn, given\n * the configured decay schedule. Pure helper — exported for tests and so\n * downstream tooling can preview decay curves without spinning up the loop.\n *\n * - No `baseBudget` → returns `undefined`. Decay never invents a budget.\n * - No `decay` → identity (`baseBudget`).\n * - Function form → `decay(turn, baseBudget)`. The return is clamped to\n * `[0, baseBudget]` so a buggy curve can't request *more* budget than the\n * caller explicitly opted into.\n * - Struct form `{ afterTurn, factor, floor }` → for `turn <= afterTurn`,\n * returns `baseBudget`. For `turn > afterTurn`, returns\n * `max(floor, baseBudget * factor^(turn - afterTurn))` clamped to\n * `[floor, baseBudget]`.\n *\n * Result is rounded to the nearest integer (token counts are integers).\n */\nexport function applyThinkingDecay(\n baseBudget: number | undefined,\n decay: AgentBehavior['thinkingDecay'] | undefined,\n turn: number,\n): number | undefined {\n if (typeof baseBudget !== 'number' || baseBudget <= 0)\n return baseBudget\n if (!decay)\n return baseBudget\n\n let raw: number\n if (typeof decay === 'function') {\n raw = decay(turn, baseBudget)\n }\n else {\n if (turn <= decay.afterTurn)\n return baseBudget\n const k = turn - decay.afterTurn\n raw = Math.max(decay.floor, baseBudget * decay.factor ** k)\n }\n\n // Clamp into a sane envelope. Decay reduces; never raises above the caller's\n // explicit budget. NaN collapses to 0 (the curve is broken — silent zero is\n // safer than letting NaN propagate into the provider request). Negative also\n // collapses to 0. `+Infinity` is fine — it clamps to baseBudget below.\n if (Number.isNaN(raw) || raw <= 0)\n return 0\n return Math.round(Math.min(baseBudget, raw))\n}\n\n/** Convert turns to the SessionMessage[] format expected by providers */\nfunction turnsToMessages(turns: SessionTurn[]): SessionMessage[] {\n return turns\n .filter((t): t is SessionTurn & { role: 'user' | 'assistant' } => t.role !== 'system')\n .map(t => ({ role: t.role, content: t.content }))\n}\n\n/**\n * Flatten image blocks inside previously-stored `tool_result` outputs to text\n * markers when the provider reports no vision capability. This handles the\n * session-resume / mid-session-provider-switch case:\n *\n * - A session was produced with a vision-capable provider (e.g. Claude) and\n * contains structured tool_result content with images.\n * - The agent resumes with a text-only provider (e.g. Cerebras).\n * - Without this pass, the persisted image blocks would re-encode via the\n * provider's wire format and leak base64 payloads into a non-vision model's\n * context.\n *\n * Scope: stored tool_result outputs only. User-authored image blocks are left\n * alone — those are consumer-controlled and the consumer is responsible for\n * matching prompt parts to the provider's capabilities.\n */\nconst COMPACTION_STUB = '[…elided by client-side tail compaction; ask the user or re-run the tool to retrieve.]'\n\n/**\n * Tail-compaction for non-Anthropic providers: when the cumulative byte size\n * of `tool_result` content across the wire-level message list exceeds\n * `threshold`, replace older `tool_result` outputs with a short stub. The\n * newest `keepTurns` messages (user/assistant alike) are left untouched so\n * the model retains the freshest tool context.\n *\n * Only `tool_result` blocks are touched — text and image blocks pass through\n * unchanged. Mutates a shallow-cloned message array; original `messages` is\n * not modified.\n *\n * For Anthropic users, prefer the server-side `context-management-2025-06-27`\n * beta (token-accurate, no client-side approximation). This function is the\n * client-side fallback for OpenAI-compatible / OpenRouter / Cerebras runs\n * against OSS models that lack a server-side equivalent.\n */\nexport function applyTailCompaction(\n messages: SessionMessage[],\n threshold: number,\n keepTurns: number,\n): SessionMessage[] {\n if (messages.length === 0)\n return messages\n\n let totalBytes = 0\n for (const msg of messages) {\n for (const block of msg.content) {\n if (block.type === 'tool_result')\n totalBytes += toolOutputByteLength(block.output)\n }\n }\n if (totalBytes <= threshold)\n return messages\n\n // Index range eligible for elision: everything before the trailing\n // `keepTurns` messages. Negative result means there's nothing old enough\n // to elide — bail out.\n const keep = Math.max(0, keepTurns)\n const cutoff = messages.length - keep\n if (cutoff <= 0)\n return messages\n\n let changed = false\n const out = messages.slice()\n for (let i = 0; i < cutoff; i++) {\n const msg = out[i]\n let msgChanged = false\n const newContent = msg.content.map((block) => {\n if (block.type !== 'tool_result')\n return block\n // Already a short string — nothing to compact.\n const existingBytes = toolOutputByteLength(block.output)\n if (existingBytes <= COMPACTION_STUB.length)\n return block\n msgChanged = true\n changed = true\n return { ...block, output: COMPACTION_STUB }\n })\n if (msgChanged)\n out[i] = { ...msg, content: newContent }\n }\n return changed ? out : messages\n}\n\n/**\n * Replace `read_file` `tool_result` blocks with a short stub when a later\n * successful `edit` / `multi_edit` / `write_file` modified the same path.\n *\n * Eliminates the common waste pattern where the model carries the pre-edit\n * file body forward across many turns. Operates on the wire-level message\n * list only — the persisted session keeps the original content.\n *\n * Detection is conservative: success is gated on the corresponding\n * tool_result starting with `Edited ` (edit / multi_edit) or `Created ` /\n * `Updated ` (write_file). Failed edits and `No change needed` writes do\n * NOT invalidate prior reads — the file content is still what the read\n * returned.\n *\n * Pure function, exported for tests and so downstream tooling can preview\n * elision without spinning up the loop.\n */\nexport const STALE_READ_STUB = '[…elided: file edited later in this run; re-read if still needed.]'\n\nexport function applyStaleReadElision(messages: SessionMessage[]): SessionMessage[] {\n if (messages.length === 0)\n return messages\n\n // Map call_id → tool_result string (for success-marker checks).\n const resultByCallId = new Map<string, string>()\n for (const msg of messages) {\n for (const block of msg.content) {\n if (block.type === 'tool_result' && typeof block.output === 'string')\n resultByCallId.set(block.callId, block.output)\n }\n }\n\n // For each path, the highest message index where a successful mutation\n // landed. `read_file` tool_results whose corresponding read happened\n // BEFORE that index (for the same path) are stale.\n const maxMutationIdxByPath = new Map<string, number>()\n // call_id → { path, msgIdx } for read_file calls.\n const readCallInfo = new Map<string, { path: string, msgIdx: number }>()\n\n for (let i = 0; i < messages.length; i++) {\n for (const block of messages[i].content) {\n if (block.type !== 'tool_call')\n continue\n const path = (block.input as { path?: unknown }).path\n if (typeof path !== 'string')\n continue\n\n if (block.name === 'read_file') {\n readCallInfo.set(block.id, { path, msgIdx: i })\n continue\n }\n\n const isEdit = block.name === 'edit' || block.name === 'multi_edit'\n const isWrite = block.name === 'write_file'\n if (!isEdit && !isWrite)\n continue\n\n const result = resultByCallId.get(block.id)\n if (typeof result !== 'string')\n continue\n\n // Success markers — see edit.ts (`Edited ${target}: replaced …`),\n // multi-edit.ts (`Edited ${target}: applied …`), write-file.ts\n // (`Created … (N bytes)` / `Updated … (N bytes)`).\n const succeeded = isEdit\n ? result.startsWith('Edited ')\n : (result.startsWith('Created ') || result.startsWith('Updated '))\n if (!succeeded)\n continue\n\n const prior = maxMutationIdxByPath.get(path)\n if (prior === undefined || i > prior)\n maxMutationIdxByPath.set(path, i)\n }\n }\n\n if (maxMutationIdxByPath.size === 0)\n return messages\n\n // call_ids whose read happened before that path's last successful mutation.\n const staleCallIds = new Set<string>()\n for (const [callId, info] of readCallInfo) {\n const lastMutationIdx = maxMutationIdxByPath.get(info.path)\n if (typeof lastMutationIdx === 'number' && info.msgIdx < lastMutationIdx)\n staleCallIds.add(callId)\n }\n\n if (staleCallIds.size === 0)\n return messages\n\n let changed = false\n const out = messages.slice()\n for (let i = 0; i < out.length; i++) {\n const msg = out[i]\n let msgChanged = false\n const newContent = msg.content.map((block) => {\n if (block.type !== 'tool_result' || !staleCallIds.has(block.callId))\n return block\n // Idempotent: a second pass over an already-elided message must not\n // bump `changed`, otherwise the function would always allocate a new\n // array (no-op-but-not-stable). Match the exact stub string.\n if (block.output === STALE_READ_STUB)\n return block\n msgChanged = true\n changed = true\n return { ...block, output: STALE_READ_STUB }\n })\n if (msgChanged)\n out[i] = { ...msg, content: newContent }\n }\n return changed ? out : messages\n}\n\nfunction sanitizeStoredToolResults(\n provider: Provider,\n messages: SessionMessage[],\n): SessionMessage[] {\n if (provider.meta.capabilities?.vision !== false)\n return messages\n\n return messages.map((msg) => {\n let changed = false\n const newContent = msg.content.map((block) => {\n if (block.type !== 'tool_result' || typeof block.output === 'string')\n return block\n changed = true\n const flattened = block.output\n .map(b => b.type === 'image' ? IMAGE_OMITTED_MARKER : b.text)\n .join('\\n')\n return { ...block, output: flattened }\n })\n return changed ? { ...msg, content: newContent } : msg\n })\n}\n\nexport async function runLoop(ctx: LoopContext): Promise<AgentStats> {\n let totalIn = 0\n let totalOut = 0\n let totalCacheRead = 0\n let totalCacheCreation = 0\n const turnUsages: TurnUsage[] = []\n const startTime = Date.now()\n // Default to no cap — runs are bounded by `result.ended` and the abort\n // signal. Callers wanting a runaway-loop safety net set `behavior.maxTurns`.\n const maxTurns = ctx.maxTurns ?? Number.POSITIVE_INFINITY\n let turnsCompleted = 0\n\n // Track time-to-first-token across the entire run. Earliest of the first\n // stream:text, stream:thinking, or tool:before event latches the value.\n const ttft = { mark: undefined as number | undefined }\n const markTtft = () => {\n if (ttft.mark === undefined)\n ttft.mark = Date.now() - ctx.runStartMs\n }\n const unregisterTtftText = ctx.hooks.hook('stream:text', markTtft)\n const unregisterTtftThinking = ctx.hooks.hook('stream:thinking', markTtft)\n const unregisterTtftTool = ctx.hooks.hook('tool:before', markTtft)\n\n try {\n for (let turn = 0; turn < maxTurns; turn++) {\n if (ctx.signal.aborted) {\n await ctx.hooks.callHook('agent:abort', {})\n break\n }\n\n const result = await executeTurn(ctx, turn)\n turnsCompleted = turn + 1\n\n totalIn += result.usage.input\n totalOut += result.usage.output\n totalCacheRead += result.usage.cacheRead ?? 0\n totalCacheCreation += result.usage.cacheCreation ?? 0\n turnUsages.push(result.usage)\n\n await ctx.hooks.callHook('usage', { turn, turnId: result.turnId, usage: result.usage, totalIn, totalOut })\n\n // Check abort after turn completes\n if (ctx.signal.aborted) {\n await ctx.hooks.callHook('agent:abort', {})\n break\n }\n\n // Check steering queue after tool execution\n if (ctx.steeringQueue.length > 0) {\n const steerMsg = ctx.steeringQueue.shift()!\n await ctx.hooks.callHook('steer:inject', { message: steerMsg })\n const steerUserMsg = ctx.provider.userMessage(steerMsg)\n ctx.turns.push({\n id: await ctx.generateTurnId(),\n runId: ctx.runId,\n role: steerUserMsg.role,\n content: steerUserMsg.content,\n createdAt: Date.now(),\n })\n continue\n }\n\n if (result.ended) {\n // Check follow-up queue before finishing\n if (ctx.followUpQueue.length > 0) {\n const followUp = ctx.followUpQueue.shift()!\n await ctx.hooks.callHook('steer:inject', { message: followUp })\n const followUpMsg = ctx.provider.userMessage(followUp)\n ctx.turns.push({\n id: await ctx.generateTurnId(),\n runId: ctx.runId,\n role: followUpMsg.role,\n content: followUpMsg.content,\n createdAt: Date.now(),\n })\n continue\n }\n\n return {\n totalIn,\n totalOut,\n totalCacheRead,\n totalCacheCreation,\n turns: turn + 1,\n elapsed: Date.now() - startTime,\n turnUsage: turnUsages,\n output: result.output,\n ...(ttft.mark !== undefined ? { timeTillFirstTokenMs: ttft.mark } : {}),\n }\n }\n }\n\n return {\n totalIn,\n totalOut,\n totalCacheRead,\n totalCacheCreation,\n turns: turnsCompleted,\n elapsed: Date.now() - startTime,\n turnUsage: turnUsages,\n ...(ttft.mark !== undefined ? { timeTillFirstTokenMs: ttft.mark } : {}),\n }\n }\n finally {\n unregisterTtftText()\n unregisterTtftThinking()\n unregisterTtftTool()\n }\n}\n\n// ---------------------------------------------------------------------------\n// Single turn\n// ---------------------------------------------------------------------------\n\ninterface TurnResult {\n ended: boolean\n turnId: string\n usage: TurnUsage\n output?: Record<string, unknown>\n}\n\n/**\n * Wrap a caught provider error in the matching typed error class.\n *\n * Uses the provider's `classifyError` seam when implemented; otherwise falls back\n * to wrapping in `AgentProviderError`. Abort signals always produce `AgentAbortedError`\n * regardless of the provider classification.\n */\nfunction wrapProviderError(err: unknown, ctx: LoopContext): Error {\n if (ctx.signal.aborted || (err instanceof Error && err.name === 'AbortError'))\n return new AgentAbortedError('Agent run aborted', { cause: err })\n\n const classification = ctx.provider.classifyError?.(err)\n if (classification)\n return toTypedError(classification, ctx.provider.name, err)\n\n const message = err instanceof Error ? err.message : String(err)\n return new AgentProviderError(message, { provider: ctx.provider.name, cause: err })\n}\n\nasync function executeTurn(ctx: LoopContext, turn: number): Promise<TurnResult> {\n // Generate turn ID early so streaming hooks have access to it\n const turnId = await ctx.generateTurnId()\n\n // Build provider-bound messages: apply outbound alias rewrite so the LLM sees\n // tool_call blocks with their wire (aliased) names. Canonical names stay in ctx.turns.\n let canonicalMessages = turnsToMessages(ctx.turns)\n\n // Stale-read elision walks canonical names (alias-stable) so consumers\n // who renamed `read_file` → `Read` etc. still get the optimization. Runs\n // BEFORE alias rewrite so the function never has to learn about the\n // alias map. The elided stub is a plain `output` string — alias rewrite\n // passes it through unchanged.\n if (ctx.elideStaleReads === true)\n canonicalMessages = applyStaleReadElision(canonicalMessages)\n\n const wireMessages = rewriteMessagesToWire(canonicalMessages, ctx.aliasMaps)\n // Flatten any stored structured tool_result images to text markers when the\n // provider is non-vision. No-op on vision-capable providers and on sessions\n // without structured outputs. See `sanitizeStoredToolResults` for scope.\n let sanitizedMessages = sanitizeStoredToolResults(ctx.provider, wireMessages)\n\n // Client-side tail compaction. Non-Anthropic OSS-model fallback for what the\n // `context-management-2025-06-27` beta gives Anthropic users server-side.\n // Skipped when off, when no threshold-bearing context, or when the total is\n // under the threshold.\n if (ctx.compactStrategy === 'tail') {\n const threshold = typeof ctx.compactThreshold === 'number' && ctx.compactThreshold > 0\n ? ctx.compactThreshold\n : 131_072\n const keep = typeof ctx.compactKeepTurns === 'number' && ctx.compactKeepTurns >= 0\n ? ctx.compactKeepTurns\n : 4\n sanitizedMessages = applyTailCompaction(sanitizedMessages, threshold, keep)\n }\n\n const effectiveThinkingBudget = applyThinkingDecay(ctx.thinkingBudget, ctx.thinkingDecay, turn)\n\n // Lazy tool disclosure — when active, rebuild the tool list each turn so\n // tools surfaced through `tool_search` since the last provider call land\n // in this request. The set only grows within a run (entries are appended,\n // never reordered or removed), so the prefix-cache breakpoint advances\n // monotonically rather than thrashing.\n const formattedTools = ctx.rebuildFormattedTools\n ? ctx.rebuildFormattedTools()\n : ctx.formattedTools\n\n const streamOptions: StreamOptions = {\n model: ctx.model,\n system: ctx.system,\n tools: formattedTools,\n messages: sanitizedMessages,\n maxTokens: ctx.maxTokens ?? 16384,\n thinking: ctx.thinking,\n thinkingBudget: effectiveThinkingBudget,\n cache: ctx.cache ?? true,\n signal: ctx.signal,\n }\n\n // Context transform hook — lets consumers prune/modify messages before LLM call\n // ctx.messages here is the wire-level view (aliases applied) so transformations are\n // consistent with what the provider actually sees.\n const transformCtx = { messages: streamOptions.messages }\n await ctx.hooks.callHook('context:transform', transformCtx)\n streamOptions.messages = transformCtx.messages\n\n // System transform hook — runtime-derived system-prompt sections. Fires\n // after `context:transform` so handlers can branch on the wire-level\n // message list. Cache breakpoints are applied inside the provider after\n // this point, so mutations land in the cache key naturally.\n const systemCtx: {\n system: string\n messages: readonly SessionMessage[]\n turn: number\n turnId: string\n session?: Session\n } = {\n system: streamOptions.system,\n messages: streamOptions.messages,\n turn,\n turnId,\n ...(ctx.session ? { session: ctx.session } : {}),\n }\n await ctx.hooks.callHook('system:transform', systemCtx)\n streamOptions.system = systemCtx.system\n\n await ctx.hooks.callHook('turn:before', { turn, turnId, options: streamOptions })\n\n let currentText = ''\n let currentThinking = ''\n\n let result\n try {\n result = await ctx.provider.stream(\n streamOptions,\n {\n onText(delta) {\n currentText += delta\n ctx.hooks.callHook('stream:text', { delta, text: currentText, turnId })\n },\n onThinking(delta) {\n currentThinking += delta\n ctx.hooks.callHook('stream:thinking', { delta, thinking: currentThinking, turnId })\n },\n onOAuthRefresh(refreshCtx) {\n return ctx.hooks.callHook('oauth:refresh', refreshCtx)\n },\n },\n )\n }\n catch (err) {\n // Ensure turn:after fires even when the provider throws.\n //\n // Persisted turns must always carry at least one content block — both\n // Anthropic and OpenAI reject `content: []` on resume. When the\n // provider blew up before any text streamed, drop in a placeholder\n // text block so the turn round-trips cleanly through any session\n // store and a subsequent `agent.run()` doesn't reject the history.\n const errorUsage: TurnUsage = { input: 0, output: 0 }\n const errorContent = currentText\n ? [{ type: 'text' as const, text: currentText }]\n : [{ type: 'text' as const, text: '[provider error before any output]' }]\n const errorTurn: SessionTurn = {\n id: turnId,\n runId: ctx.runId,\n role: 'assistant',\n content: errorContent,\n usage: errorUsage,\n createdAt: Date.now(),\n }\n ctx.turns.push(errorTurn)\n await ctx.hooks.callHook('turn:after', {\n turn,\n turnId,\n usage: errorUsage,\n message: errorTurn,\n toolCounts: { turn: Object.freeze({}), run: Object.freeze({ ...ctx.runToolCounts }) },\n })\n throw wrapProviderError(err, ctx)\n }\n\n if (currentText) {\n await ctx.hooks.callHook('stream:end', { text: currentText, turnId })\n }\n\n // Inbound alias → canonical rewrite. After this, tool calls and assistant\n // content blocks use canonical names everywhere downstream (turns, dispatch, hooks).\n const canonicalToolCalls = result.toolCalls.map(tc => ({\n ...tc,\n name: toCanonicalName(tc.name, ctx.aliasMaps),\n }))\n const canonicalContent = rewriteContentToCanonical(\n result.assistantMessage?.content ?? [],\n ctx.aliasMaps,\n )\n\n // Build the assistant turn and push BEFORE firing turn:after\n const assistantTurn: SessionTurn = {\n id: turnId,\n runId: ctx.runId,\n role: 'assistant',\n content: result.done\n ? (canonicalContent.length > 0 ? canonicalContent : [{ type: 'text', text: currentText }])\n : canonicalContent,\n usage: result.usage,\n createdAt: Date.now(),\n }\n ctx.turns.push(assistantTurn)\n\n // Per-turn tool counts: how many of each tool the model emitted in this\n // assistant turn. Counts emissions, not dispatches — `turn:after` fires\n // before tool dispatch, so blocked calls are counted here too. For \"actually\n // dispatched\" cumulative numbers, use `toolCounts.run`.\n const turnCounts: Record<string, number> = {}\n for (const tc of canonicalToolCalls)\n turnCounts[tc.name] = (turnCounts[tc.name] ?? 0) + 1\n\n await ctx.hooks.callHook('turn:after', {\n turn,\n turnId,\n usage: result.usage,\n message: assistantTurn,\n toolCounts: { turn: Object.freeze(turnCounts), run: Object.freeze({ ...ctx.runToolCounts }) },\n })\n\n if (result.done) {\n // Schema enforcement: force one more call with a synthetic output tool\n if (ctx.schema && !ctx.signal.aborted) {\n const outputSpec: ToolSpec = {\n name: '__output__',\n description: 'Return the final structured output matching the required schema.',\n inputSchema: ctx.schema,\n }\n const schemaMessages = rewriteMessagesToWire(turnsToMessages(ctx.turns), ctx.aliasMaps)\n let schemaResult\n try {\n schemaResult = await ctx.provider.stream(\n {\n model: ctx.model,\n system: ctx.system,\n tools: ctx.provider.formatTools([outputSpec]),\n messages: schemaMessages,\n maxTokens: ctx.maxTokens ?? 16384,\n signal: ctx.signal,\n toolChoice: { type: 'tool', name: '__output__' },\n },\n {\n onText: () => {},\n onOAuthRefresh(refreshCtx) {\n return ctx.hooks.callHook('oauth:refresh', refreshCtx)\n },\n },\n )\n }\n catch (err) {\n throw wrapProviderError(err, ctx)\n }\n\n const output = schemaResult.toolCalls.find(tc => tc.name === '__output__')?.input\n\n if (output) {\n await ctx.hooks.callHook('output', { output, schema: ctx.schema })\n }\n\n const schemaTurn: SessionTurn = {\n id: await ctx.generateTurnId(),\n runId: ctx.runId,\n role: 'assistant',\n content: schemaResult.assistantMessage.content,\n usage: schemaResult.usage,\n createdAt: Date.now(),\n }\n ctx.turns.push(schemaTurn)\n\n return {\n ended: true,\n turnId,\n usage: {\n input: result.usage.input + schemaResult.usage.input,\n output: result.usage.output + schemaResult.usage.output,\n },\n output,\n }\n }\n\n return { ended: true, turnId, usage: result.usage }\n }\n\n // Pause-turn recovery (Anthropic 4.6+ `pause_turn`): the model stopped\n // mid-turn for a server-side pause but no tools were requested. Push a\n // synthetic continue prompt as a user message so the next turn resumes\n // with valid (non-empty) input — Anthropic rejects empty user content.\n // Gated on `finishReason === 'pause'` to avoid masking provider bugs that\n // legitimately produce zero tool calls and zero text.\n if (canonicalToolCalls.length === 0 && result.usage.finishReason === 'pause') {\n const continueMsg = ctx.provider.userMessage('Please continue.')\n ctx.turns.push({\n id: await ctx.generateTurnId(),\n runId: ctx.runId,\n role: continueMsg.role,\n content: continueMsg.content,\n createdAt: Date.now(),\n })\n return { ended: false, turnId, usage: result.usage }\n }\n\n // Execute tool calls (canonical names after inbound rewrite)\n const toolResults = ctx.toolExecution === 'parallel'\n ? await executeToolsParallel(ctx, canonicalToolCalls, turnId)\n : await executeToolsSequential(ctx, canonicalToolCalls, turnId)\n\n // Tool results as a user turn\n const toolResultMsg = ctx.provider.toolResultsMessage(toolResults)\n ctx.turns.push({\n id: await ctx.generateTurnId(),\n runId: ctx.runId,\n role: toolResultMsg.role,\n content: toolResultMsg.content,\n createdAt: Date.now(),\n })\n\n // Enforce per-turn tool-output budget. Sum the post-transform bytes of every\n // tool result; on overshoot, push a synthetic user message that nudges the\n // model toward summarization, and surface the event via `budget:exceeded`.\n if (typeof ctx.toolOutputBudget === 'number' && ctx.toolOutputBudget > 0) {\n const totalBytes = toolResults.reduce(\n (sum, r) => sum + toolOutputByteLength(r.content),\n 0,\n )\n if (totalBytes > ctx.toolOutputBudget) {\n const warning = `[Tool output budget exceeded: ${totalBytes} bytes returned in this turn (cap: ${ctx.toolOutputBudget}). Summarize the salient findings before calling more tools.]`\n const userMsg = ctx.provider.userMessage(warning)\n ctx.turns.push({\n id: await ctx.generateTurnId(),\n runId: ctx.runId,\n role: userMsg.role,\n content: userMsg.content,\n createdAt: Date.now(),\n })\n await ctx.hooks.callHook('budget:exceeded', {\n turn,\n turnId,\n bytes: totalBytes,\n budget: ctx.toolOutputBudget,\n })\n }\n }\n\n return { ended: false, turnId, usage: result.usage }\n}\n\n// ---------------------------------------------------------------------------\n// Tool execution\n// ---------------------------------------------------------------------------\n\n/**\n * Strip image blocks from a tool output when the provider is not vision-capable.\n * Each image is replaced with a short text marker so the model sees an honest\n * \"no image\" signal instead of JSON-stringified base64 it might confabulate over.\n *\n * Returns the output unchanged when:\n * - The provider reports `capabilities.vision: true` (native routing handles it),\n * - The provider omits `capabilities` entirely (we default to vision-capable\n * so third-party providers without the field aren't penalized),\n * - The output is a plain string (no image blocks to strip).\n *\n * With the current `text | image` union, replacing every image with a text marker\n * leaves an all-text array — collapse to a plain string to keep the downstream wire\n * shape as narrow as possible.\n */\nfunction stripImagesForNonVision(\n provider: Provider,\n output: string | ToolResultContent[],\n): string | ToolResultContent[] {\n if (typeof output === 'string')\n return output\n if (provider.meta.capabilities?.vision !== false)\n return output\n\n return output\n .map(b => b.type === 'image' ? IMAGE_OMITTED_MARKER : b.text)\n .join('\\n')\n}\n\nasync function executeSingleTool(\n ctx: LoopContext,\n call: ToolCall,\n turnId: string,\n): Promise<{ result: ToolResult }> {\n const toolDef = ctx.tools[call.name]\n const callId = call.id\n const displayName = toWireName(call.name, ctx.aliasMaps)\n\n // Frozen pre-call snapshot of run-cumulative tool counts. Shared across the\n // gate, tool:before, and tool:after hooks so consumers see a consistent view\n // for the lifecycle of this call. A consumer that wants the post-increment\n // count can add 1 to the entry for `ctx.name`.\n const runToolCounts: Readonly<Record<string, number>> = Object.freeze({ ...ctx.runToolCounts })\n\n // Gate hook — handlers can `block` (refuse the call), substitute a `result`\n // (skip execute, send the substitute back as a normal tool_result), or do\n // nothing (tool runs as usual).\n const gateCtx: {\n turnId: string\n callId: string\n name: string\n displayName: string\n input: Record<string, unknown>\n block: boolean\n reason: string\n result?: string | ToolResultContent[]\n runToolCounts: Readonly<Record<string, number>>\n } = {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: call.input,\n block: false,\n reason: 'Tool execution was blocked',\n runToolCounts,\n }\n await ctx.hooks.callHook('tool:gate', gateCtx)\n\n // Conflict resolution: block wins over result. This handles two cases\n // cleanly without forcing every middleware to defensively coordinate:\n //\n // - A consumer hook substitutes a `result` (e.g. dedup cache), then a\n // policy gate (skills allowed-tools, custom security) refuses the call\n // via `block`. The refusal must take precedence — security beats\n // convenience.\n // - A buggy single handler sets both. The call gets blocked; the spurious\n // `result` is dropped silently. The buggy code path can be caught with a\n // tool:gate observability hook downstream of the framework gates.\n if (gateCtx.block) {\n // Blocked calls do not count — the model \"asked\" but the framework refused\n // before any side effect could happen. Treating them as charged would make\n // budget guards self-defeating (block on N triggers Nth call to count).\n return { result: { id: callId, content: `Blocked: ${gateCtx.reason}` } }\n }\n\n // The call passed gate; record it in the run counter. Counted once here so\n // `result`-substituted calls still count — the model emitted the call.\n ctx.runToolCounts[call.name] = (ctx.runToolCounts[call.name] ?? 0) + 1\n\n // Z20 substitute path. Skip validate / `tool:before` / execute and emit a\n // synthetic successful `tool_result`. `tool:after` and `tool:transform`\n // still fire so byte-budgeting, telemetry, and post-mutation hooks see\n // the substitute consistently with executed calls.\n if (gateCtx.result !== undefined) {\n const substitute = await emitToolResult(ctx, {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: gateCtx.input,\n output: gateCtx.result,\n isError: false,\n runToolCounts,\n })\n return { result: { id: callId, content: substitute } }\n }\n\n // Input that downstream hooks + execute see, after any tool:gate mutation.\n let effectiveInput = gateCtx.input\n\n if (!toolDef) {\n // Hallucinated tool name (model invented it) or dangling reference (MCP\n // server dropped, alias removed). Give consumers a chance to substitute a\n // friendly response or suppress the companion `tool:error` so the trace\n // doesn't carry a noisy \"Unknown tool\" message back to the model.\n const unknownCtx: {\n turnId: string\n callId: string\n name: string\n displayName: string\n input: Record<string, unknown>\n result?: string | ToolResultContent[]\n suppressError: boolean\n } = {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: effectiveInput,\n suppressError: false,\n }\n await ctx.hooks.callHook('tool:unknown', unknownCtx)\n\n const content = unknownCtx.result ?? `Tool error: Unknown tool: ${call.name}`\n\n if (!unknownCtx.suppressError) {\n const err = new Error(`Unknown tool: ${call.name}`)\n await ctx.hooks.callHook('tool:error', {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: effectiveInput,\n error: err,\n })\n }\n return { result: { id: callId, content } }\n }\n\n // Validate arguments (respect mutations from tool:gate hook). Auto-coerces\n // string→boolean/number/etc. for OSS models that don't always honor types.\n const validation = validateToolArgs(effectiveInput, toolDef.spec.inputSchema)\n if (!validation.valid) {\n await ctx.hooks.callHook('validation:reject', {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: effectiveInput,\n reason: validation.error ?? 'invalid input',\n schema: toolDef.spec.inputSchema,\n })\n return { result: { id: callId, content: `Validation error: ${validation.error}` } }\n }\n // Pass the coerced input to the tool — `\"true\"` is now `true`, etc.\n effectiveInput = validation.coercedInput ?? effectiveInput\n\n // Surface successful coercions so consumers can count \"model wrongness rate\".\n // Only fires when at least one field was coerced; perfectly-typed inputs stay\n // silent so the hook bus isn't noisy on the happy path.\n const coercions = validation.coercions && validation.coercions.length > 0\n ? validation.coercions\n : undefined\n if (coercions) {\n await ctx.hooks.callHook('validation:coerce', {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: effectiveInput,\n coercions,\n schema: toolDef.spec.inputSchema,\n })\n }\n\n await ctx.hooks.callHook('tool:before', {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: effectiveInput,\n runToolCounts,\n ...(coercions ? { coercions } : {}),\n })\n\n let output: string | ToolResultContent[]\n let isError = false\n\n try {\n const toolCtx: ToolContext = {\n provider: ctx.provider,\n signal: ctx.signal,\n execution: ctx.execution,\n handle: ctx.handle,\n hooks: ctx.hooks,\n tools: ctx.agentTools,\n ...(ctx.agentName !== undefined ? { name: ctx.agentName } : {}),\n ...(ctx.agentSystem !== undefined ? { system: ctx.agentSystem } : {}),\n ...(ctx.agentToolAliases !== undefined ? { toolAliases: ctx.agentToolAliases } : {}),\n ...(ctx.agentMcpServers !== undefined ? { mcpServers: ctx.agentMcpServers } : {}),\n ...(ctx.agentSkills !== undefined ? { skills: ctx.agentSkills } : {}),\n ...(ctx.agentBehavior !== undefined ? { behavior: ctx.agentBehavior } : {}),\n turnId,\n callId,\n runId: ctx.runId,\n ...(ctx.session ? { session: ctx.session } : {}),\n ...(typeof ctx.depth === 'number' ? { depth: ctx.depth } : {}),\n }\n output = await toolDef.execute(effectiveInput, toolCtx)\n }\n catch (err) {\n const error = err instanceof Error ? err : new Error(String(err))\n // Hook can mutate `result` to substitute a custom payload for the model —\n // e.g. OSS-model error rewriting, collapsing stack traces. Default\n // `Tool error: <msg>` is used when no handler sets it.\n const errorCtx: {\n turnId: string\n callId: string\n name: string\n displayName: string\n input: Record<string, unknown>\n error: Error\n result?: string | ToolResultContent[]\n } = {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: effectiveInput,\n error,\n }\n await ctx.hooks.callHook('tool:error', errorCtx)\n output = errorCtx.result ?? `Tool error: ${error.message}`\n isError = true\n }\n\n const finalOutput = await emitToolResult(ctx, {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: effectiveInput,\n output,\n isError,\n runToolCounts,\n ...(coercions ? { coercions } : {}),\n })\n\n return { result: { id: callId, content: finalOutput } }\n}\n\n/**\n * Shared post-output emission: fire `tool:transform` (mutate-allowed), strip\n * images for non-vision providers, fire `tool:after`. Used by both the\n * gate-substitute (Z20) and post-execute paths so they stay byte-for-byte\n * identical from the consumer's perspective.\n */\nasync function emitToolResult(\n ctx: LoopContext,\n params: {\n turnId: string\n callId: string\n name: string\n displayName: string\n input: Record<string, unknown>\n output: string | ToolResultContent[]\n isError: boolean\n runToolCounts: Readonly<Record<string, number>>\n coercions?: readonly string[]\n },\n): Promise<string | ToolResultContent[]> {\n const { turnId, callId, name, displayName, input, runToolCounts, coercions } = params\n let output = params.output\n let isError = params.isError\n\n // Transform hook — mutate ctx.result / ctx.isError to modify output. The\n // `outputBytes` field is the byte-length of the result *before* any\n // consumer mutation, so a truncation hook can decide whether to act.\n const transformCtx = {\n turnId,\n callId,\n name,\n displayName,\n input,\n result: output,\n isError,\n outputBytes: toolOutputByteLength(output),\n ...(coercions ? { coercions } : {}),\n }\n await ctx.hooks.callHook('tool:transform', transformCtx)\n output = transformCtx.result\n isError = transformCtx.isError\n\n // Strip images for non-vision providers before they hit the wire. Done\n // after the transform hook so consumers can still observe the raw\n // structured output.\n output = stripImagesForNonVision(ctx.provider, output)\n\n // `tool:after` carries the post-mutation byte size — what actually goes\n // back to the model. Telemetry consumers should prefer this over\n // recomputing.\n await ctx.hooks.callHook('tool:after', {\n turnId,\n callId,\n name,\n displayName,\n input,\n result: output,\n outputBytes: toolOutputByteLength(output),\n runToolCounts,\n ...(coercions ? { coercions } : {}),\n })\n\n return output\n}\n\nasync function executeToolsSequential(\n ctx: LoopContext,\n toolCalls: ToolCall[],\n turnId: string,\n): Promise<ToolResult[]> {\n const results: ToolResult[] = []\n\n for (let i = 0; i < toolCalls.length; i++) {\n const call = toolCalls[i]\n\n // Abort between sequential calls: emit an `Aborted` tool_result for\n // every remaining call so the assistant turn's tool_use IDs all have\n // matching tool_result IDs. Providers (Anthropic loudly, OpenAI\n // implicitly) reject orphan tool_use/tool_result IDs — without these\n // synthetic results the next `agent.run()` from this session can't\n // make any API call until the dangling tool_use is purged.\n if (ctx.signal.aborted) {\n for (let j = i; j < toolCalls.length; j++)\n results.push({ id: toolCalls[j].id, content: 'Aborted: run was cancelled' })\n return results\n }\n\n // Steering between sequential tool calls: stop dispatching, but emit a\n // `Skipped` tool_result for every remaining call. Same orphan-ID\n // concern as above.\n //\n // Do NOT consume the steering queue or push turns here — the caller\n // pushes the tool_results turn from the returned list, and the outer\n // run loop drains the queue at the next steering checkpoint and pushes\n // the synthetic user message. Doing it twice (here + at the call-site)\n // previously produced an empty tool_results turn after the steer.\n if (ctx.steeringQueue.length > 0) {\n for (let j = i; j < toolCalls.length; j++)\n results.push({ id: toolCalls[j].id, content: 'Skipped: steering message received' })\n return results\n }\n\n const { result } = await executeSingleTool(ctx, call, turnId)\n results.push(result)\n }\n\n return results\n}\n\nasync function executeToolsParallel(\n ctx: LoopContext,\n toolCalls: ToolCall[],\n turnId: string,\n): Promise<ToolResult[]> {\n const executions = toolCalls.map(call => executeSingleTool(ctx, call, turnId))\n const settled = await Promise.allSettled(executions)\n return settled.map((s, i) => {\n if (s.status === 'fulfilled')\n return s.value.result\n return {\n id: toolCalls[i].id,\n content: `Error: ${s.reason instanceof Error ? s.reason.message : String(s.reason)}`,\n }\n })\n}\n","/**\n * Prompt canonicalization + default multimodal message builder.\n *\n * `agent.run({ prompt })` accepts either `string` or `PromptPart[]`. The\n * agent normalizes both to `PromptPart[]` before handing to the provider.\n *\n * Providers may implement `Provider.promptMessage` for native-format support\n * (e.g. Anthropic's document blocks). Providers that don't fall back to\n * `defaultPromptMessage`, which inlines text-encoded documents and throws on\n * base64-encoded documents.\n */\n\nimport type { Provider } from './providers'\nimport type { PromptPart, SessionContentBlock, SessionMessage } from './types'\n\n/**\n * Coerce the run-level prompt into a `PromptPart[]`.\n *\n * - `string` prompt → a single `text` part. Empty string returns `undefined`\n * so callers skip pushing an empty user turn.\n * - `PromptPart[]` prompt → validated and returned as-is. An empty array, or\n * an array whose text parts are all empty with no image/document parts,\n * returns `undefined`.\n * - `undefined` → `undefined` (promptless resume path).\n */\nexport function canonicalizePrompt(\n prompt: string | PromptPart[] | undefined,\n): PromptPart[] | undefined {\n if (prompt === undefined)\n return undefined\n\n if (typeof prompt === 'string') {\n if (prompt.length === 0)\n return undefined\n return [{ type: 'text', text: prompt }]\n }\n\n // Array path — drop if empty, or if every text part is empty and there are no\n // image/document parts (nothing meaningful to send).\n if (prompt.length === 0)\n return undefined\n\n // Reject malformed parts up front rather than letting them slip through to\n // `defaultPromptMessage` / `provider.promptMessage`, where the failure\n // mode is a confusing \"Cannot read property 'text' of undefined\" or a\n // base64-document throw far from the call-site. The check is cheap and\n // catches the common typo (wrong `type` field) loudly.\n for (const part of prompt) {\n if (!part || typeof part !== 'object' || typeof (part as { type?: unknown }).type !== 'string') {\n throw new Error('Invalid PromptPart: each part must be an object with a `type` field.')\n }\n const type = (part as { type: string }).type\n if (type !== 'text' && type !== 'image' && type !== 'document') {\n throw new Error(`Invalid PromptPart type \"${type}\". Expected \"text\" | \"image\" | \"document\".`)\n }\n }\n\n const hasMeaningfulPart = prompt.some(part => (\n (part.type === 'text' && part.text.length > 0)\n || part.type === 'image'\n || part.type === 'document'\n ))\n if (!hasMeaningfulPart)\n return undefined\n\n return prompt\n}\n\n/**\n * Build a user `SessionMessage` from prompt parts without provider-specific handling.\n *\n * - `text` parts map to `{ type: 'text', text }` blocks.\n * - `image` parts map to `{ type: 'image', mediaType, data }` blocks.\n * - `document` parts with `encoding: 'text'` are inlined as an attachment-tagged\n * text block so every provider can read them.\n * - `document` parts with `encoding: 'base64'` throw — the caller should switch\n * to a provider that implements `promptMessage` (e.g. Anthropic for PDFs).\n */\nexport function defaultPromptMessage(parts: PromptPart[]): SessionMessage {\n const content: SessionContentBlock[] = []\n\n for (const part of parts) {\n if (part.type === 'text') {\n if (part.text.length > 0)\n content.push({ type: 'text', text: part.text })\n continue\n }\n\n if (part.type === 'image') {\n content.push({ type: 'image', mediaType: part.mediaType, data: part.data })\n continue\n }\n\n // document\n if (part.encoding === 'text') {\n const header = part.name\n ? `<attachment name=\"${part.name}\" media_type=\"${part.mediaType}\">`\n : `<attachment media_type=\"${part.mediaType}\">`\n content.push({ type: 'text', text: `${header}\\n${part.data}\\n</attachment>` })\n continue\n }\n\n throw new Error(\n `Provider does not support base64 document parts (mediaType: ${part.mediaType}). `\n + `Use a text-encoded document or a provider that implements promptMessage (e.g. Anthropic).`,\n )\n }\n\n return { role: 'user', content }\n}\n\n/**\n * Build the prompt `SessionMessage` for a given provider.\n *\n * Prefers `provider.promptMessage` when defined, falling back to `defaultPromptMessage`.\n */\nexport function buildPromptMessage(provider: Provider, parts: PromptPart[]): SessionMessage {\n if (provider.promptMessage)\n return provider.promptMessage(parts)\n return defaultPromptMessage(parts)\n}\n","/**\n * `tool-budgets` middleware — per-tool soft call caps on top of the\n * `tool:gate` writable-`block`/`result` slots and the run-cumulative\n * `runToolCounts` (Z24).\n *\n * Two modes:\n *\n * - `'block'` — refuse the over-budget call via `ctx.block = true`. The model\n * sees a `Blocked: <message>` tool result.\n * - `'steer'` — let the call run, but enqueue a synthetic user message for\n * the NEXT turn so the model sees the budget warning before deciding to\n * call again. Reuses the existing `steeringQueue` plumbing.\n *\n * Either mode fires `tool-budget:exceeded` so observability layers can react.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from './agent'\nimport type { AgentBehavior, ToolHookContext, ToolResultContent } from './types'\n\n/**\n * Install the per-tool soft-budget middleware on a hook bus.\n * `getToolBudgets` returns the resolved per-tool budgets (run override merged\n * with agent defaults). `enqueueSteer` pushes a synthetic user message into\n * the run's steeringQueue so the loop drains it between turns.\n *\n * The middleware maintains its OWN approval counter (`approvedCounts`),\n * incremented at gate-time — independent of the loop's `runToolCounts`,\n * which is incremented after gate completes. This gives atomic per-call\n * reservation in parallel batches: when a batch of N calls all fire\n * `tool:gate` before any increments propagate, each gate handler still\n * sees the prior approvals and refuses past `max`.\n *\n * Returns an `uninstall` fn.\n */\nexport function installToolBudgetsGate(\n hooks: Hookable<AgentHooks>,\n getToolBudgets: () => AgentBehavior['toolBudgets'] | undefined,\n enqueueSteer: (message: string) => void,\n): () => void {\n // Per-run set of tools that have ALREADY had a steer fired. Without this,\n // every call past `max` queues another nudge and the conversation drowns\n // in identical reminders. Cleared on uninstall (run-end).\n const steeredOnce = new Set<string>()\n\n // Per-tool approval counter the middleware owns. Incremented synchronously\n // when a call passes gate, so within-batch ordering is preserved even when\n // the loop's `runToolCounts` lags (handlers across a parallel batch can\n // fire before any of the batch's calls have been incremented loop-side).\n const approvedCounts: Record<string, number> = {}\n\n async function gateHandler(ctx: ToolHookContext & {\n block: boolean\n reason: string\n result?: string | ToolResultContent[]\n runToolCounts: Readonly<Record<string, number>>\n }) {\n // Don't override prior gate handlers.\n if (ctx.block || ctx.result !== undefined)\n return\n\n const toolBudgets = getToolBudgets()\n const budget = toolBudgets?.[ctx.name]\n if (!budget)\n return\n\n const max = budget.max\n if (typeof max !== 'number' || max <= 0)\n return\n\n // Read our internal approval counter — independent of the loop's\n // `runToolCounts` so within-batch ordering is correct even in parallel\n // mode. Each gate that approves a call increments this synchronously.\n const count = approvedCounts[ctx.name] ?? 0\n if (count < max) {\n // Approve atomically: bump the counter now, before yielding to the\n // next handler in the chain. Subsequent calls in the same parallel\n // batch see this approval and may refuse if the budget is depleted.\n approvedCounts[ctx.name] = count + 1\n return\n }\n\n // Resolve mode + message. Function form runs untrusted consumer code —\n // a throw would crash the hook bus, so we fall back to the default\n // 'steer' shape on error rather than poisoning the run.\n const onExceed = budget.onExceed ?? 'steer'\n let mode: 'steer' | 'block'\n let message: string\n if (typeof onExceed === 'function') {\n try {\n const out = onExceed({ tool: ctx.name, count, max })\n mode = out.mode\n message = out.message\n }\n catch {\n mode = 'steer'\n message = defaultSteerMessage(ctx.name, count, max)\n }\n }\n else if (onExceed === 'block') {\n mode = 'block'\n message = defaultBlockMessage(ctx.name, max)\n }\n else {\n mode = 'steer'\n message = defaultSteerMessage(ctx.name, count, max)\n }\n\n if (mode === 'block') {\n ctx.block = true\n ctx.reason = message\n await hooks.callHook('tool-budget:exceeded', {\n tool: ctx.name,\n count,\n max,\n turnId: ctx.turnId,\n mode: 'block',\n })\n return\n }\n\n // Steer mode — let the call go through, but queue a single nudge per\n // tool so the model sees the budget warning before its next turn.\n if (!steeredOnce.has(ctx.name)) {\n steeredOnce.add(ctx.name)\n enqueueSteer(message)\n await hooks.callHook('tool-budget:exceeded', {\n tool: ctx.name,\n count,\n max,\n turnId: ctx.turnId,\n mode: 'steer',\n })\n }\n }\n\n const unregister = hooks.hook('tool:gate', gateHandler)\n\n return function uninstall() {\n unregister()\n steeredOnce.clear()\n }\n}\n\nfunction defaultSteerMessage(tool: string, count: number, max: number): string {\n return `[Tool budget reached: '${tool}' has been called ${count} times this run (cap: ${max}). Avoid calling it again unless strictly necessary; commit to a result and move on.]`\n}\n\nfunction defaultBlockMessage(tool: string, max: number): string {\n return `Tool '${tool}' has reached its per-run budget of ${max} calls; further invocations are refused.`\n}\n","/**\n * Heuristics for detecting binary content in UTF-8-decoded strings.\n *\n * `ExecutionContext.readFile` always returns text. Invalid bytes survive\n * decoding as U+FFFD (replacement char), and genuinely binary files often\n * contain NUL bytes — UTF-8 text legitimately should not. These helpers\n * give tools a cheap way to bail before drowning the model in mojibake.\n */\n\nconst SNIFF_BYTES = 8192\nconst REPLACEMENT_RATIO_THRESHOLD = 0.01\nconst REPLACEMENT_MIN_COUNT = 5\n\n/**\n * True if a NUL (`\\x00`) appears in the leading sample. Cheap, no false\n * positives on real text — UTF-8 never embeds NUL, so any NUL means the\n * source bytes were binary.\n */\nexport function containsNullByte(text: string, sniffBytes = SNIFF_BYTES): boolean {\n const sample = text.length > sniffBytes ? text.slice(0, sniffBytes) : text\n for (let i = 0; i < sample.length; i++) {\n if (sample.charCodeAt(i) === 0)\n return true\n }\n return false\n}\n\n/**\n * Heavier check used by `read_file`:\n * - NUL byte ⇒ binary,\n * - or U+FFFD count ≥ minimum AND ratio over threshold ⇒ binary.\n *\n * The replacement-char ratio + minimum guards against tripping on a\n * one-or-two-stray-replacement-char text file (config dumps, editor logs).\n */\nexport function looksBinary(text: string, sniffBytes = SNIFF_BYTES): boolean {\n const sample = text.length > sniffBytes ? text.slice(0, sniffBytes) : text\n if (sample.length === 0)\n return false\n\n let replacementCount = 0\n for (let i = 0; i < sample.length; i++) {\n const code = sample.charCodeAt(i)\n if (code === 0)\n return true\n if (code === 0xFFFD)\n replacementCount++\n }\n return replacementCount >= REPLACEMENT_MIN_COUNT\n && replacementCount / sample.length > REPLACEMENT_RATIO_THRESHOLD\n}\n","/**\n * `skills_read` tool — reads a bundled resource file from an active skill.\n *\n * Requires the skill to be active (model must have called `skills_use` first).\n * Paths are validated against the skill's `baseDir` to prevent directory\n * traversal. File I/O goes through `ctx.execution.readFile` so docker/sandbox\n * execution contexts work identically to in-process.\n */\n\nimport type { SkillActivationState } from '../skills/activation'\nimport type { SkillConfig } from '../skills/types'\nimport type { ToolContext, ToolDef } from './types'\nimport { validateResourcePath } from '../skills/validate'\nimport { containsNullByte } from './binary-detect'\n\nexport interface SkillsReadToolOptions {\n catalog: readonly SkillConfig[]\n state: SkillActivationState\n}\n\nexport function createSkillsReadTool(options: SkillsReadToolOptions): ToolDef {\n const byName = new Map(options.catalog.map(s => [s.name, s]))\n\n return {\n spec: {\n name: 'skills_read',\n description:\n 'Read a bundled resource file from an active skill. '\n + 'The skill must have been activated via skills_use first. '\n + 'Path is relative to the skill\\'s directory (e.g. \"references/REFERENCE.md\", \"assets/template.txt\").',\n inputSchema: {\n type: 'object',\n properties: {\n name: {\n type: 'string',\n enum: options.catalog.map(s => s.name),\n description: 'The name of the active skill.',\n },\n path: {\n type: 'string',\n description: 'Path to the resource, relative to the skill root. Cannot escape the skill directory.',\n },\n },\n required: ['name', 'path'],\n additionalProperties: false,\n },\n },\n\n async execute(input, ctx: ToolContext): Promise<string> {\n const skillName = input.name as string\n const relPath = input.path as string\n\n const skill = byName.get(skillName)\n if (!skill)\n return `Error: unknown skill \"${skillName}\".`\n\n if (!options.state.isActive(skillName))\n return `Error: skill \"${skillName}\" is not active. Call skills_use with name: \"${skillName}\" first.`\n\n if (!skill.baseDir) {\n return (\n `Error: skill \"${skillName}\" has no base directory `\n + '(likely an inline skill without bundled resources); cannot read files.'\n )\n }\n\n const validated = validateResourcePath(relPath, skill.baseDir)\n if (!validated.valid)\n return `Error: ${validated.error}`\n\n let content: string\n try {\n content = await ctx.execution.readFile(ctx.handle, validated.absolutePath)\n }\n catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return `Error reading \"${relPath}\" in skill \"${skillName}\": ${message}`\n }\n\n if (containsNullByte(content)) {\n // `ExecutionContext.readFile` returns a UTF-8 string — invalid UTF-8\n // bytes get replacement chars, so a round-trip through base64 would\n // corrupt the payload. Instead of pretending we can deliver binary\n // bytes, return a descriptor that tells the agent where the file is.\n // A future `readFileBytes(handle, path)` API on ExecutionContext\n // would unlock proper inline delivery; until then, host adapters\n // needing binaries should stream them out-of-band.\n return JSON.stringify({\n kind: 'binary-unsupported',\n path: validated.absolutePath,\n note:\n 'This file appears to be binary. The skills_read tool returns text only; '\n + 'binary files are not delivered through the execution context\\'s text-based readFile API.',\n })\n }\n\n return content\n },\n }\n}\n","/**\n * Shared shell-argument quoter for tool implementations.\n *\n * Single source of truth so `grep`, `binary-read`, and `skills-run-script`\n * don't drift on the POSIX `'\\''` escape pattern.\n */\n\nconst SAFE_TOKEN_RE = /^[\\w@%+=:,./-]+$/\nconst SINGLE_QUOTE_RE = /'/g\n\n/**\n * Wrap an argument in single quotes, escaping embedded single quotes via the\n * standard POSIX `'\\''` close-escape-reopen trick. Tokens that are already\n * shell-safe pass through unchanged so command lines stay readable in logs.\n *\n * NOT a sandbox — only safe when the caller controls the surrounding shell\n * context. Use it for arguments only, never for the verb / subcommand.\n */\nexport function shellQuote(arg: string): string {\n if (SAFE_TOKEN_RE.test(arg))\n return arg\n return `'${arg.replace(SINGLE_QUOTE_RE, '\\'\\\\\\'\\'')}'`\n}\n\n/**\n * Variant that always quotes — useful when the caller doesn't want a\n * conditional `unquoted-when-safe` branch (consistent log shape, paranoid\n * inputs that contain whitespace by construction).\n */\nexport function alwaysQuote(arg: string): string {\n return `'${arg.replace(SINGLE_QUOTE_RE, '\\'\\\\\\'\\'')}'`\n}\n","/**\n * `skills_run_script` tool — executes a script from an active skill's\n * `scripts/` directory via the agent's execution context.\n *\n * Path is validated against the skill's `baseDir` and constrained to the\n * `scripts/` subdirectory. Timeout is configurable via\n * `SkillsConfig.scriptTimeoutMs` (default 60 s).\n */\n\nimport type { SkillActivationState } from '../skills/activation'\nimport type { SkillConfig } from '../skills/types'\nimport type { ToolContext, ToolDef } from './types'\nimport { validateResourcePath } from '../skills/validate'\nimport { alwaysQuote } from './shell-quote'\n\nexport interface SkillsRunScriptToolOptions {\n catalog: readonly SkillConfig[]\n state: SkillActivationState\n /** Script timeout in milliseconds. Default 60000. */\n scriptTimeoutMs?: number\n}\n\nconst ABS_WINDOWS_RE = /^[a-z]:[\\\\/]/i\nconst COLLAPSE_SLASHES_RE = /\\/+/g\n\nexport function createSkillsRunScriptTool(options: SkillsRunScriptToolOptions): ToolDef {\n const byName = new Map(options.catalog.map(s => [s.name, s]))\n const timeoutMs = options.scriptTimeoutMs ?? 60_000\n\n return {\n spec: {\n name: 'skills_run_script',\n description:\n 'Execute a script bundled with an active skill (from its scripts/ directory). '\n + 'The skill must have been activated via skills_use first. '\n + 'Returns stdout, stderr, and the exit code. Honors the script\\'s shebang.',\n inputSchema: {\n type: 'object',\n properties: {\n name: {\n type: 'string',\n enum: options.catalog.map(s => s.name),\n description: 'The name of the active skill.',\n },\n script: {\n type: 'string',\n description: 'Path to the script relative to the skill\\'s scripts/ directory (e.g. \"extract.py\", \"merge.sh\").',\n },\n args: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional argv array passed to the script.',\n },\n },\n required: ['name', 'script'],\n additionalProperties: false,\n },\n },\n\n async execute(input, ctx: ToolContext): Promise<string> {\n const skillName = input.name as string\n const scriptRel = input.script as string\n const args = (input.args as string[] | undefined) ?? []\n\n const skill = byName.get(skillName)\n if (!skill)\n return `Error: unknown skill \"${skillName}\".`\n\n if (!options.state.isActive(skillName))\n return `Error: skill \"${skillName}\" is not active. Call skills_use with name: \"${skillName}\" first.`\n\n if (!skill.baseDir)\n return `Error: skill \"${skillName}\" has no base directory (likely an inline skill); cannot run scripts.`\n\n // Reject absolute script paths up front — otherwise they'd be spuriously\n // \"normalized\" under scripts/ by the join below.\n if (scriptRel.startsWith('/') || ABS_WINDOWS_RE.test(scriptRel))\n return `Error: Absolute paths are not allowed (\"${scriptRel}\").`\n\n // Resolve under scripts/ and validate — rejects escapes via `..`.\n const joinedPath = `scripts/${scriptRel}`.replace(COLLAPSE_SLASHES_RE, '/')\n const validated = validateResourcePath(joinedPath, skill.baseDir)\n if (!validated.valid)\n return `Error: ${validated.error}`\n\n // Build a shell command that honors shebang (via POSIX exec). For\n // languages without shebang (e.g. Python on Windows-authored files),\n // the script's first-line `#!/usr/bin/env python3` handles it.\n const cmd = [validated.absolutePath, ...args].map(alwaysQuote).join(' ')\n try {\n const result = await ctx.execution.exec(ctx.handle, cmd, {\n timeout: Math.max(1, Math.round(timeoutMs / 1000)),\n })\n return JSON.stringify({\n exitCode: result.exitCode,\n stdout: result.stdout,\n stderr: result.stderr,\n })\n }\n catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return `Error running script \"${scriptRel}\" for skill \"${skillName}\": ${message}`\n }\n },\n }\n}\n","/**\n * `skills_use` tool — activates a skill and returns its full instructions.\n *\n * Implements tier 2 of progressive disclosure per the Agent Skills spec.\n * Body is frontmatter-stripped (the model gets the markdown only, wrapped in\n * `<skill_content>` tags so downstream context management can identify it).\n * Shell-interpolation (`!` `` `cmd` ``) runs per-activation rather than once\n * per agent, so values like `gh pr diff` reflect the current state.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from '../agent'\nimport type { SkillActivationState } from '../skills/activation'\nimport type { SkillConfig } from '../skills/types'\nimport type { ToolContext, ToolDef } from './types'\nimport { interpolateShellCommands } from '../skills/interpolate'\nimport { escapeXml } from '../xml'\n\nexport interface SkillsUseToolOptions {\n /** Resolved skills catalog for this run. */\n catalog: readonly SkillConfig[]\n /** Per-agent activation state the tool mutates. */\n state: SkillActivationState\n /** Agent hooks — used to fire `skills:activate` on first activation. */\n hooks: Hookable<AgentHooks>\n}\n\nconst MAX_RESOURCE_LIST = 50\n\nfunction buildSkillContentWrapper(skill: SkillConfig, body: string): string {\n const parts: string[] = []\n parts.push(`<skill_content name=\"${escapeXml(skill.name)}\" spec_version=\"0.1\">`)\n parts.push(body)\n\n if (skill.baseDir) {\n parts.push('')\n parts.push(`Skill directory: ${skill.baseDir}`)\n parts.push('Relative paths resolve against this directory.')\n }\n\n if (skill.resources?.length) {\n parts.push('')\n parts.push('<skill_resources>')\n const shown = skill.resources.slice(0, MAX_RESOURCE_LIST)\n for (const res of shown) {\n parts.push(` <file type=\"${res.type}\">${escapeXml(res.path)}</file>`)\n }\n if (skill.resources.length > MAX_RESOURCE_LIST) {\n parts.push(` <!-- …(${skill.resources.length - MAX_RESOURCE_LIST} more) -->`)\n }\n parts.push('</skill_resources>')\n }\n\n if (skill.compatibility) {\n parts.push('')\n parts.push(`Compatibility: ${skill.compatibility}`)\n }\n\n if (skill.allowedTools?.length) {\n parts.push(`Allowed tools: ${skill.allowedTools.join(' ')}`)\n }\n\n parts.push('</skill_content>')\n return parts.join('\\n')\n}\n\n/**\n * Factory for `skills_use`. Auto-injected into the agent's tool set by the\n * agent runtime when a non-empty skills catalog is available (unless\n * `SkillsConfig.tool === false`).\n *\n * The tool schema's `name` property is `enum`-constrained to the resolved\n * catalog so the LLM cannot hallucinate a skill that doesn't exist.\n */\nexport function createSkillsUseTool(options: SkillsUseToolOptions): ToolDef {\n const byName = new Map(options.catalog.map(s => [s.name, s]))\n // Cache interpolated bodies for the lifetime of this tool instance. The\n // agent rebuilds skills tools per-run, so this cache naturally resets on\n // each run boundary — avoiding stale shell output from a prior run.\n const interpolatedBodyCache = new Map<string, string>()\n\n return {\n spec: {\n name: 'skills_use',\n description:\n 'Activate a specialized skill and load its full instructions. '\n + 'Call this when a task matches a skill\\'s description from the catalog. '\n + 'After calling, follow the returned instructions; use skills_read to load '\n + 'referenced files and skills_run_script to execute bundled scripts.',\n inputSchema: {\n type: 'object',\n properties: {\n name: {\n type: 'string',\n enum: options.catalog.map(s => s.name),\n description: 'The name of the skill to activate (must be in the available skills catalog).',\n },\n },\n required: ['name'],\n additionalProperties: false,\n },\n },\n\n async execute(input, ctx: ToolContext): Promise<string> {\n const skillName = input.name as string\n const skill = byName.get(skillName)\n if (!skill) {\n const available = [...byName.keys()].join(', ') || '<none>'\n return `Error: unknown skill \"${skillName}\". Available skills: ${available}.`\n }\n\n const wasActive = options.state.isActive(skillName)\n\n if (!wasActive) {\n const outcome = options.state.activate(skill, 'model')\n if (outcome === 'cap-reached') {\n const activeNames = options.state.active().map(a => a.skill.name).join(', ')\n return (\n `Error: cannot activate \"${skillName}\" — the maxActive skill cap has been reached. `\n + `Currently active: ${activeNames}. Deactivate an existing skill first.`\n )\n }\n await options.hooks.callHook('skills:activate', { skill, via: 'model' })\n }\n\n // Interpolate `!\\`cmd\\`` once per (skill, tool-instance). A second\n // `skills_use` call on the same skill returns the cached body.\n let body = interpolatedBodyCache.get(skillName)\n if (body === undefined) {\n body = skill.instructions.includes('!`')\n ? await interpolateShellCommands(skill.instructions, ctx.execution, ctx.handle)\n : skill.instructions\n interpolatedBodyCache.set(skillName, body)\n }\n\n return buildSkillContentWrapper(skill, body)\n },\n }\n}\n","/**\n * `tool_search` — progressive tool disclosure.\n *\n * Counterpart to `skills_use` for the MCP tool surface: the catalog (name +\n * description) lives in the system prompt; full `inputSchema` payloads load\n * lazily through this tool. After a successful match, the matched tools'\n * canonical names are added to the per-run \"unlocked\" set and become callable\n * immediately (the loop rebuilds `formattedTools` before the next provider\n * request, advertising the unlocked tools to the provider).\n *\n * Aliasing: the tool advertises and matches on the **wire** (alias-rewritten)\n * name — the only name the model ever sees. Internally each lazy entry also\n * carries its `canonicalName`, which is what gets added to the `unlocked` set\n * (the loop's tool registry is keyed by canonical name).\n *\n * Result shape: structured pseudo-XML wrapping a JSON `inputSchema` payload.\n * The schema is inlined verbatim (NOT XML-escaped) so the model can reuse it\n * directly when constructing arguments — escaping the JSON would force the\n * model to mentally un-escape `"` etc. when reasoning about field types.\n */\n\nimport type { ToolContext, ToolDef } from './types'\nimport { escapeXml } from '../xml'\n\nexport interface LazyToolEntry {\n /**\n * Wire name (after `toolAliases` rewrite). What the model sees in the\n * catalog, what `tool_search` matches against, and what the provider's\n * tool list will carry once the entry is unlocked.\n */\n name: string\n /**\n * Canonical (registry-key) name used for unlock-set membership and for the\n * loop's `ctx.tools[name]` dispatch lookup. Equal to `name` when no alias\n * is configured for this tool.\n */\n canonicalName: string\n description: string\n inputSchema: Record<string, unknown>\n /** Source MCP server, when applicable. Used for `server`-bulk unlock. */\n server?: string\n}\n\nexport interface ToolSearchToolOptions {\n /**\n * Snapshot of every lazy tool the model can discover. Built once per run by\n * the agent — the tool closes over this array and never mutates it.\n */\n catalog: readonly LazyToolEntry[]\n /**\n * Mutable per-run set of unlocked **canonical** tool names. The tool adds\n * matches in place; the loop reads the set when rebuilding the wire-level\n * tool list. Keyed by canonical (not wire) so dispatch lookups stay\n * alias-stable.\n */\n unlocked: Set<string>\n /** Default cap on returned matches when the model omits `limit`. */\n defaultLimit?: number\n}\n\nconst DEFAULT_LIMIT = 20\n\nfunction rankByQuery(catalog: readonly LazyToolEntry[], query: string): LazyToolEntry[] {\n const q = query.trim().toLowerCase()\n if (!q)\n return [...catalog]\n\n // Two-tier ranking: name hits beat description hits. Within each tier we\n // preserve registration order so deterministic catalogs produce\n // deterministic results.\n const nameHits: LazyToolEntry[] = []\n const descHits: LazyToolEntry[] = []\n for (const entry of catalog) {\n if (entry.name.toLowerCase().includes(q))\n nameHits.push(entry)\n else if (entry.description.toLowerCase().includes(q))\n descHits.push(entry)\n }\n return [...nameHits, ...descHits]\n}\n\n/**\n * Sanitise a JSON-stringified schema for embedding inside a pseudo-XML tag.\n *\n * The schema is inlined verbatim (NOT XML-escaped) so the model can reuse\n * field types directly when constructing arguments. The only transformation\n * we apply is replacing `<` with `\\u003c` inside string literals — this\n * keeps the JSON byte-equivalent for the model (JSON parsers decode the\n * escape) while preventing a hostile or buggy `inputSchema` from injecting\n * apparent XML tags (`</input_schema>`, `<evil>…`) that would muddle the\n * model's read of the surrounding result envelope.\n *\n * The substitution is safe because `<` is only meaningful when it appears\n * literally; the `\\u003c` form is not a tag character and is identical to\n * `<` after JSON parsing.\n */\nfunction sanitiseSchemaForXml(schemaJson: string): string {\n return schemaJson.replace(/</g, '\\\\u003c')\n}\n\nfunction formatMatch(entry: LazyToolEntry): string {\n const schema = sanitiseSchemaForXml(JSON.stringify(entry.inputSchema))\n const serverAttr = entry.server ? ` server=\"${escapeXml(entry.server)}\"` : ''\n return [\n ` <tool name=\"${escapeXml(entry.name)}\"${serverAttr}>`,\n ` <description>${escapeXml(entry.description)}</description>`,\n ` <input_schema>${schema}</input_schema>`,\n ` </tool>`,\n ].join('\\n')\n}\n\n/**\n * Factory for `tool_search`. Auto-injected by the agent when\n * `behavior.toolDisclosure === 'lazy'` and at least one MCP tool is in the\n * registry. Opt out via `behavior.toolSearch.tool === false`.\n */\nexport function createToolSearchTool(options: ToolSearchToolOptions): ToolDef {\n const defaultLimit = options.defaultLimit ?? DEFAULT_LIMIT\n\n // Index the catalog once for `names` / `server` lookups. Wire-name keyed\n // because the model only ever sees / sends wire names.\n const byName = new Map(options.catalog.map(e => [e.name, e]))\n const byServer = new Map<string, LazyToolEntry[]>()\n for (const entry of options.catalog) {\n if (!entry.server)\n continue\n const list = byServer.get(entry.server) ?? []\n list.push(entry)\n byServer.set(entry.server, list)\n }\n const maxLimit = Math.max(options.catalog.length, 1)\n\n return {\n spec: {\n name: 'tool_search',\n description:\n 'Discover and load schemas for additional tools listed in <searchable_tools>. '\n + 'Tools listed there are advertised by name + description only — their input '\n + 'schemas are not loaded into context until you surface them through this tool. '\n + 'Pass `query` for a substring search, `names` to load specific tools, or `server` '\n + 'to load every tool from one MCP server. Returned tools become callable for the '\n + 'rest of this run.',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Substring to match against tool name + description (case-insensitive).',\n },\n names: {\n type: 'array',\n items: { type: 'string' },\n description: 'Explicit tool names to load (bypasses ranking). Use the names shown in <searchable_tools>.',\n },\n server: {\n type: 'string',\n description: 'MCP server name — load every tool from this server.',\n },\n limit: {\n type: 'integer',\n minimum: 1,\n description: `Cap on returned matches. Default: ${defaultLimit}.`,\n },\n },\n additionalProperties: false,\n },\n },\n\n async execute(input, ctx: ToolContext): Promise<string> {\n // Cheap signal check — refuses cleanly if the run was aborted between\n // the model emitting the call and the executor running it.\n if (ctx.signal?.aborted)\n return '<tool_search_results matches=\"0\" aborted=\"true\">Run aborted.</tool_search_results>'\n\n // Coerce empty-string query to \"no query\"; otherwise it falls into the\n // query branch and trivially matches every entry, leaving a misleading\n // `query=\"\"` attribute in the result envelope.\n const rawQuery = typeof input.query === 'string' ? input.query.trim() : undefined\n const query = rawQuery || undefined\n const namesIn = Array.isArray(input.names)\n ? input.names.filter((n): n is string => typeof n === 'string' && n.length > 0)\n : undefined\n const server = typeof input.server === 'string' && input.server.length > 0 ? input.server : undefined\n const limitIn = typeof input.limit === 'number' && Number.isFinite(input.limit) && input.limit > 0\n ? Math.floor(input.limit)\n : defaultLimit\n const limit = Math.min(limitIn, maxLimit)\n\n if (options.catalog.length === 0)\n return '<tool_search_results matches=\"0\">No lazy tools registered for this run.</tool_search_results>'\n\n const matches: LazyToolEntry[] = []\n const seen = new Set<string>()\n const misses: string[] = []\n\n // `names` first so the model's explicit ask is never dropped by the\n // limit clamp when paired with a wide query.\n if (namesIn && namesIn.length > 0) {\n for (const n of namesIn) {\n if (seen.has(n))\n continue\n const entry = byName.get(n)\n if (entry) {\n matches.push(entry)\n seen.add(n)\n }\n else {\n misses.push(n)\n }\n }\n }\n\n if (server) {\n const list = byServer.get(server) ?? []\n for (const entry of list) {\n if (seen.has(entry.name))\n continue\n matches.push(entry)\n seen.add(entry.name)\n }\n }\n\n if (query !== undefined) {\n for (const entry of rankByQuery(options.catalog, query)) {\n if (seen.has(entry.name))\n continue\n matches.push(entry)\n seen.add(entry.name)\n }\n }\n\n // No criteria → list everything (capped). Lets a model bootstrap\n // discovery on the first call without guessing a query.\n if (!namesIn?.length && !server && query === undefined) {\n for (const entry of options.catalog) {\n matches.push(entry)\n seen.add(entry.name)\n }\n }\n\n const truncated = matches.length > limit\n const shown = truncated ? matches.slice(0, limit) : matches\n\n // Unlock by canonical name — the loop's tool registry is keyed on\n // canonical, so this is what `buildFormattedTools` checks.\n for (const entry of shown)\n options.unlocked.add(entry.canonicalName)\n\n const parts: string[] = []\n const queryAttr = query ? ` query=\"${escapeXml(query)}\"` : ''\n const serverAttr = server ? ` server=\"${escapeXml(server)}\"` : ''\n parts.push(`<tool_search_results matches=\"${shown.length}\" total=\"${matches.length}\"${queryAttr}${serverAttr}>`)\n if (shown.length === 0) {\n parts.push(' No matches. Try a broader query, or omit all parameters to list everything.')\n }\n else {\n for (const entry of shown)\n parts.push(formatMatch(entry))\n parts.push('')\n parts.push(' These tools are now callable. Invoke them by name in subsequent turns.')\n if (truncated) {\n parts.push(` ${matches.length - shown.length} additional matches were truncated — refine the query or raise \\`limit\\`.`)\n }\n }\n if (misses.length > 0) {\n parts.push(` <misses>${misses.map(escapeXml).join(', ')}</misses>`)\n }\n parts.push('</tool_search_results>')\n\n return parts.join('\\n')\n },\n }\n}\n","/**\n * Agent creation and state management.\n */\n\nimport type { Hookable } from 'hookable'\n\nimport type { ExecutionContext, ExecutionHandle } from './contexts'\nimport type { McpConnection } from './mcp'\nimport type { Provider, StreamOptions, ToolSpec } from './providers'\nimport type { Session } from './session'\nimport type { ActivationVia, ActiveSkill, DeactivationReason } from './skills/activation'\nimport type { SkillConfig, SkillsConfig } from './skills/types'\nimport type { LazyToolEntry } from './tools/tool-search'\nimport type { ToolDef } from './tools/types'\nimport type { AgentBehavior, AgentRunOptions, AgentStats, ChildRunStats, McpServerConfig, McpToolHookContext, OAuthRefreshHookContext, SessionEndStatus, SessionHookContext, SessionMessage, SessionTurn, SpawnHookContext, StreamHookContext, ToolHookContext, ToolResultContent, TurnUsage } from './types'\nimport { createHooks } from 'hookable'\nimport { buildAliasMaps } from './aliasing'\nimport { createProcessContext } from './contexts'\nimport { installDedupToolsGate } from './dedup-tools'\nimport { runLoop } from './loop'\nimport { connectMcpServers } from './mcp'\nimport { buildPromptMessage, canonicalizePrompt } from './prompt'\nimport { createSkillActivationState } from './skills/activation'\nimport { installAllowedToolsGate } from './skills/allowed-tools'\nimport { buildCatalog } from './skills/catalog'\nimport { resolveSkills } from './skills/resolve'\nimport { installToolBudgetsGate } from './tool-budgets'\nimport { createSkillsReadTool } from './tools/skills-read'\nimport { createSkillsRunScriptTool } from './tools/skills-run-script'\nimport { createSkillsUseTool } from './tools/skills-use'\nimport { createToolSearchTool } from './tools/tool-search'\nimport { escapeXml } from './xml'\n\n// ---------------------------------------------------------------------------\n// Hook definitions\n// ---------------------------------------------------------------------------\n\nexport interface AgentHooks {\n // System\n 'system:before': (ctx: { system: string }) => void\n\n // Turn lifecycle\n 'turn:before': (ctx: { turn: number, turnId: string, options: StreamOptions }) => void\n /**\n * Fires after each assistant turn (before its tool-result follow-up\n * dispatches; the loop iterates back to a fresh `turn:before` once the\n * tool results are produced).\n *\n * `toolCounts.turn` — calls **emitted** by the model in this assistant\n * turn, keyed by canonical tool name. Reflects what the model asked for,\n * regardless of downstream gate outcome. Most useful for spotting per-turn\n * spikes (\"the model called todowrite 4 times in one turn\").\n *\n * `toolCounts.run` — cumulative running counter of **dispatched** calls\n * scoped to this `runId`, captured at fire time. Excludes calls that were\n * `block`ed by `tool:gate` handlers. Includes calls short-circuited via\n * `tool:gate` `result` substitution (the model still asked, the framework\n * just answered without the tool running). Resumed sessions start a fresh\n * run with empty counts.\n *\n * Both fields are frozen snapshots; mutate-safe.\n */\n 'turn:after': (ctx: {\n turn: number\n turnId: string\n usage: TurnUsage\n message: SessionTurn\n toolCounts: {\n turn: Readonly<Record<string, number>>\n run: Readonly<Record<string, number>>\n }\n }) => void\n\n // Streaming\n 'stream:text': (ctx: StreamHookContext & { delta: string, text: string }) => void\n 'stream:end': (ctx: StreamHookContext & { text: string }) => void\n 'stream:thinking': (ctx: StreamHookContext & { delta: string, thinking: string }) => void\n 'oauth:refresh': (ctx: OAuthRefreshHookContext) => void\n\n // Tool execution\n /**\n * Fires before validation, `tool:before`, and `execute`. Two ways to\n * intercept:\n *\n * - Set `block = true` (with a `reason`) to refuse the call. The model\n * sees a `Blocked: <reason>` tool result; `tool:before` / `tool:after`\n * do **not** fire.\n * - Set `result` to substitute a successful tool_result and skip\n * execution. The model sees the substitute as a normal tool_result;\n * `tool:before` does not fire, but `tool:after` and `tool:transform`\n * do — so byte budgets, telemetry, and post-mutation hooks see the\n * substitute. Useful for cache hits, dedup, idempotency guards,\n * plan-mode synthetic acks.\n *\n * If multiple handlers along the chain set both `block` and `result`,\n * `block` wins — refusal beats substitution, so a policy gate\n * (skills allow-list, custom security) can always override an upstream\n * consumer's cache substitute. Mirrors the writable-`result` shape on\n * `tool:unknown` and `tool:error` so consumers learn one pattern.\n *\n * `runToolCounts` — frozen pre-call snapshot of per-tool dispatched\n * counts in this run. Use it to self-throttle, drive observability, or\n * implement budget guards. Counts every call that passed gate, including\n * dedup substitutes (Z19); excludes `block`ed calls.\n *\n * **Parallel mode** (`toolExecution: 'parallel'`, the default): the\n * snapshot is taken before any dispatches in the batch, so consumer\n * hooks reading `runToolCounts` see the pre-batch view. Built-in\n * budget / dedup middleware uses internal per-call reservation, so\n * `behavior.toolBudgets` enforces atomically even within a parallel\n * batch.\n */\n 'tool:gate': (ctx: ToolHookContext & {\n block: boolean\n reason: string\n result?: string | ToolResultContent[]\n runToolCounts: Readonly<Record<string, number>>\n }) => void\n 'tool:before': (ctx: ToolHookContext & {\n coercions?: readonly string[]\n runToolCounts: Readonly<Record<string, number>>\n }) => void\n 'tool:after': (ctx: ToolHookContext & {\n result: string | ToolResultContent[]\n outputBytes: number\n coercions?: readonly string[]\n runToolCounts: Readonly<Record<string, number>>\n }) => void\n /**\n * Fires when a tool throws during execution. Mutate `result` to substitute a\n * tool-output payload that gets sent back to the model in place of the\n * default `Tool error: <msg>` string — useful for OSS-model error rewriting\n * (collapse stack traces, hide internal paths, prepend recovery hints).\n *\n * The post-hook value flows through `tool:transform` like a normal output, so\n * downstream byte-budgeting and image-stripping still apply.\n */\n 'tool:error': (ctx: ToolHookContext & { error: Error, result?: string | ToolResultContent[] }) => void\n 'tool:transform': (ctx: ToolHookContext & { result: string | ToolResultContent[], isError: boolean, outputBytes: number, coercions?: readonly string[] }) => void\n /**\n * Fires before the generic \"Unknown tool\" error when the model invokes a tool\n * that isn't registered (hallucinated names, dropped MCP servers, dangling\n * aliases). Mutate `result` to substitute a friendly response or set\n * `suppressError: true` to skip the companion `tool:error` emission.\n *\n * Fires for any unknown tool name — including hallucinated MCP-style names\n * (`mcp_supabase_xxx`); branch on `name.startsWith('mcp_')` to differentiate.\n */\n 'tool:unknown': (ctx: ToolHookContext & {\n result?: string | ToolResultContent[]\n suppressError: boolean\n }) => void\n /**\n * Fires when `validateToolArgs` rejects an input that could not be auto-coerced\n * to satisfy the tool's `inputSchema`. Observational — the tool call still\n * surfaces a `Validation error: …` string back to the model. Useful for\n * counting validation failures separately from runtime tool errors.\n */\n 'validation:reject': (ctx: ToolHookContext & {\n reason: string\n schema: Record<string, unknown>\n }) => void\n /**\n * Fires when `validateToolArgs` successfully auto-coerced one or more input\n * fields to satisfy the tool's `inputSchema`. **Only fires when at least one\n * coercion happened** — never on perfectly-shaped inputs. Useful for counting\n * model \"wrongness rate\" without re-running validation downstream.\n *\n * `coercions` lists the field names that were coerced. The values landed in\n * the input that the tool actually received; consumers wanting before/after\n * comparison can re-run `validateToolArgs(ctx.input, ctx.schema)`.\n */\n 'validation:coerce': (ctx: ToolHookContext & {\n coercions: readonly string[]\n schema: Record<string, unknown>\n }) => void\n\n // Context\n 'context:transform': (ctx: { messages: SessionMessage[] }) => void\n /**\n * Fires per request, after `context:transform` and before the request goes\n * out. Mutating `ctx.system` updates the system prompt the provider sends\n * for this turn — useful for runtime-derived sections (e.g. listing files\n * already read in the session, surfacing live tool budgets, injecting\n * skill activation reminders).\n *\n * Cache breakpoints are applied inside the provider after this hook, so\n * mutations land in the cache key naturally — repeated turns with the\n * same derived system text still hit the cache.\n *\n * `messages` is read-only here; use `context:transform` for message\n * surgery. `session` is `undefined` when the run is sessionless.\n */\n 'system:transform': (ctx: { system: string, messages: readonly SessionMessage[], turn: number, turnId: string, session?: Session }) => void\n 'steer:inject': (ctx: { message: string }) => void\n\n // Spawn\n 'spawn:before': (ctx: SpawnHookContext) => void\n 'spawn:complete': (ctx: ChildRunStats) => void\n 'spawn:error': (ctx: SpawnHookContext & { error: Error }) => void\n\n // Child hook bubbling — re-fires of a subagent's in-turn events on the\n // parent's hook bus. Each context is the original child event payload\n // augmented with `childId` (spawn id) and `depth` (subagent depth). Parents\n // opt in by listening; default behavior is silent. Grandchildren bubble\n // through their immediate parent's spawn tool, so a top-level listener\n // sees the full transitive stream.\n 'child:stream:text': (ctx: StreamHookContext & { delta: string, text: string, childId: string, depth: number }) => void\n 'child:stream:thinking': (ctx: StreamHookContext & { delta: string, thinking: string, childId: string, depth: number }) => void\n 'child:stream:end': (ctx: StreamHookContext & { text: string, childId: string, depth: number }) => void\n /**\n * Gate-style child events. Unlike the other `child:*` events, the bubble\n * passes the **same `ctx` reference** the subagent's loop is awaiting on:\n * setting `ctx.block` / `ctx.reason` / `ctx.result` on a parent listener\n * propagates straight back to the child, refusing or substituting the call.\n *\n * Use these to gate subagent tool calls (native + MCP) from the parent\n * without registering listeners on every child agent. The parent's own\n * `tool:gate` / `mcp:tool:gate` listeners are NOT auto-shared with\n * children — that would also share their budgets and dedup state.\n */\n 'child:tool:gate': (ctx: ToolHookContext & {\n block: boolean\n reason: string\n result?: string | ToolResultContent[]\n runToolCounts: Readonly<Record<string, number>>\n childId: string\n depth: number\n }) => void\n 'child:mcp:tool:gate': (ctx: McpToolHookContext & {\n block: boolean\n reason: string\n result?: string | ToolResultContent[]\n childId: string\n depth: number\n }) => void\n 'child:tool:before': (ctx: ToolHookContext & {\n coercions?: readonly string[]\n runToolCounts: Readonly<Record<string, number>>\n childId: string\n depth: number\n }) => void\n 'child:tool:after': (ctx: ToolHookContext & {\n result: string | ToolResultContent[]\n outputBytes: number\n coercions?: readonly string[]\n runToolCounts: Readonly<Record<string, number>>\n childId: string\n depth: number\n }) => void\n 'child:tool:error': (ctx: ToolHookContext & { error: Error, childId: string, depth: number }) => void\n 'child:turn:after': (ctx: {\n turn: number\n turnId: string\n usage: TurnUsage\n message: SessionTurn\n toolCounts: { turn: Readonly<Record<string, number>>, run: Readonly<Record<string, number>> }\n childId: string\n depth: number\n }) => void\n\n // MCP server lifecycle\n 'mcp:connect': (ctx: { name: string, transport: string, tools: string[] }) => void\n 'mcp:error': (ctx: { name: string, error: Error }) => void\n 'mcp:close': (ctx: { name: string }) => void\n /**\n * Fires at the start of a per-server bootstrap attempt, before any network I/O.\n * Pairs with `mcp:bootstrap:end` and is always emitted, regardless of outcome.\n */\n 'mcp:bootstrap:start': (ctx: { name: string, transport: string }) => void\n /**\n * Fires at the end of a per-server bootstrap attempt. `durationMs` spans from\n * the matching `mcp:bootstrap:start`. On `ok: false` carries the originating\n * error so consumers can log / trace without relying on a separate `mcp:error`.\n */\n 'mcp:bootstrap:end': (ctx: { name: string, transport: string, durationMs: number } & ({ ok: true, toolCount: number } | { ok: false, error: Error })) => void\n /**\n * Fires once per server after `listTools()` and after the config-side filters\n * (`enabledTools` / `disabledTools` / `toolFilter`) have applied, but BEFORE\n * tools are registered. Handlers may mutate `ctx.tools` in place — splicing,\n * reordering, or replacing entries — to further narrow what the model sees.\n *\n * Composes with config-side filters: config drops tools the host's static\n * policy excludes; this hook is the runtime escape hatch for per-user, per-\n * environment, or capability-driven decisions that the config can't express.\n *\n * Items are upstream tool descriptors (NOT yet namespaced as `mcp_<server>_<tool>`).\n */\n 'mcp:tools:filter': (ctx: {\n server: string\n transport: 'stdio' | 'sse' | 'streamable-http'\n tools: Array<{ name: string, description?: string | null, inputSchema?: unknown }>\n }) => void\n\n // MCP tool execution\n /**\n * MCP-side counterpart of `tool:gate`. Same shape: set `block` to refuse,\n * set `result` to substitute a successful payload and skip the upstream\n * MCP `callTool`. When both are set across the handler chain, `block` wins.\n *\n * Fires INSIDE the MCP wrapper's `execute`, after the loop's `tool:gate`\n * already ran. Does **not** carry `runToolCounts` — those are loop-level\n * and already exposed on `tool:gate` for MCP tools (which are registered\n * as agent tools under their namespaced name `mcp_<server>_<tool>`). Use\n * `tool:gate` for budget / dedup logic; reserve `mcp:tool:gate` for\n * MCP-specific concerns (per-server routing, transport-aware refusals).\n */\n 'mcp:tool:gate': (ctx: McpToolHookContext & {\n block: boolean\n reason: string\n result?: string | ToolResultContent[]\n }) => void\n 'mcp:tool:before': (ctx: McpToolHookContext) => void\n 'mcp:tool:after': (ctx: McpToolHookContext & { result: string | ToolResultContent[], outputBytes: number }) => void\n 'mcp:tool:transform': (ctx: McpToolHookContext & { result: string | ToolResultContent[], outputBytes: number }) => void\n 'mcp:tool:error': (ctx: McpToolHookContext & { error: Error }) => void\n\n // Skills\n 'skills:resolve': (ctx: { skills: SkillConfig[] }) => void\n 'skills:catalog': (ctx: { catalog: string, skills: SkillConfig[] }) => void\n 'skills:activate': (ctx: { skill: SkillConfig, via: ActivationVia }) => void\n 'skills:deactivate': (ctx: { skill: SkillConfig, reason: DeactivationReason }) => void\n\n // Usage and output\n 'usage': (ctx: { turn: number, turnId: string, usage: TurnUsage, totalIn: number, totalOut: number }) => void\n 'output': (ctx: { output: Record<string, unknown>, schema: Record<string, unknown> }) => void\n /**\n * Fires when a turn's total tool-output bytes exceed `behavior.toolOutputBudget`.\n * Measured post-`tool:transform`. Loop injects a synthetic user message after\n * the tool-results turn instructing the model to summarize.\n */\n 'budget:exceeded': (ctx: { turn: number, turnId: string, bytes: number, budget: number }) => void\n /**\n * Fires when a per-tool budget configured via `behavior.toolBudgets` is\n * exceeded for a specific tool. `mode` reflects how the framework reacted:\n * `'steer'` lets the call run and queues a post-turn nudge; `'block'`\n * refuses the call outright with `Blocked: <message>`.\n *\n * `count` is the run-cumulative dispatched count just before this call.\n * Use `turnId` to correlate with `turn:after` if you need the integer turn\n * index. Distinct from `budget:exceeded` (byte-level) so consumers can\n * subscribe specifically; both can fire in the same turn.\n */\n 'tool-budget:exceeded': (ctx: {\n tool: string\n count: number\n max: number\n turnId: string\n mode: 'steer' | 'block'\n }) => void\n\n // Agent lifecycle\n 'agent:abort': (ctx: object) => void\n /**\n * Run finished — fires on all exit paths (completion, maxTurns, abort).\n *\n * Since 4.0 the `AgentStats` carried here is **cumulative** across the\n * parent agent loop and every recursively-spawned sub-agent\n * (`totalIn` / `totalOut` / `cost` / `totalCacheRead` / `totalCacheCreation`).\n * For parent-loop-only counts use `ctx.turnUsage` (parent-only array);\n * for tree-wide turn counts use `flattenTurns(ctx).length`.\n */\n 'agent:done': (ctx: AgentStats) => void\n\n // Session\n 'session:start': (ctx: SessionHookContext & { runId: string, prompt: string }) => void\n 'session:end': (ctx: SessionHookContext & { runId: string, status: SessionEndStatus, turnRange: [number, number] }) => void\n 'session:turns': (ctx: SessionHookContext & { turns: SessionTurn[], count: number }) => void\n 'session:meta': (ctx: SessionHookContext & { key: string, value: unknown }) => void\n 'session:save': (ctx: SessionHookContext) => void\n}\n\n/**\n * Authoritative list of hook event names. Kept in sync with `AgentHooks` at\n * compile time: the `satisfies` assertion below rejects any drift.\n */\nconst HOOK_EVENT_NAMES = [\n 'system:before',\n 'turn:before',\n 'turn:after',\n 'stream:text',\n 'stream:end',\n 'stream:thinking',\n 'oauth:refresh',\n 'tool:gate',\n 'tool:before',\n 'tool:after',\n 'tool:error',\n 'tool:transform',\n 'tool:unknown',\n 'validation:reject',\n 'validation:coerce',\n 'context:transform',\n 'system:transform',\n 'steer:inject',\n 'spawn:before',\n 'spawn:complete',\n 'spawn:error',\n 'child:stream:text',\n 'child:stream:thinking',\n 'child:stream:end',\n 'child:tool:gate',\n 'child:mcp:tool:gate',\n 'child:tool:before',\n 'child:tool:after',\n 'child:tool:error',\n 'child:turn:after',\n 'mcp:connect',\n 'mcp:error',\n 'mcp:close',\n 'mcp:bootstrap:start',\n 'mcp:bootstrap:end',\n 'mcp:tools:filter',\n 'mcp:tool:gate',\n 'mcp:tool:before',\n 'mcp:tool:after',\n 'mcp:tool:transform',\n 'mcp:tool:error',\n 'skills:resolve',\n 'skills:catalog',\n 'skills:activate',\n 'skills:deactivate',\n 'usage',\n 'output',\n 'budget:exceeded',\n 'tool-budget:exceeded',\n 'agent:abort',\n 'agent:done',\n 'session:start',\n 'session:end',\n 'session:turns',\n 'session:meta',\n 'session:save',\n] as const satisfies readonly (keyof AgentHooks)[]\n\nconst HOOK_EVENT_SET: ReadonlySet<string> = new Set(HOOK_EVENT_NAMES)\n\nfunction isKnownHookEvent(event: string): event is keyof AgentHooks {\n return HOOK_EVENT_SET.has(event)\n}\n\n// ---------------------------------------------------------------------------\n// Agent interface\n// ---------------------------------------------------------------------------\n\nexport interface AgentOptions {\n provider: Provider\n /** Display name for the agent (used in traces/logs). */\n name?: string\n /** Default system prompt injected when no system is provided at run time. */\n system?: string\n /** Tool definitions available to the agent. Defaults to no tools. */\n tools?: Record<string, ToolDef>\n /**\n * Map canonical tool names to LLM-facing (aliased) names.\n *\n * Aliasing is **LLM-boundary-only**: the alias is what the provider's tool spec\n * carries and what the model calls the tool; the canonical name is what lives in\n * `session.turns` and what the agent uses to look up the tool implementation.\n */\n toolAliases?: Record<string, string>\n /** Agent-level behavior defaults (overridden by run-level behavior) */\n behavior?: AgentBehavior\n /** Execution context: where tools run. Defaults to in-process. */\n execution?: ExecutionContext\n /** MCP servers to connect and expose as tools */\n mcpServers?: McpServerConfig[]\n /** Session for identity, turn persistence, and run tracking */\n session?: Session\n /** Skills configuration */\n skills?: SkillsConfig\n /**\n * Test seam — replaces the default MCP connector with a custom\n * implementation. Bypasses the `mcpServers` normalization layer entirely\n * and is **not** part of the supported public API. Subject to change or\n * removal in any release.\n *\n * @internal\n */\n mcpConnector?: (configs: McpServerConfig[]) => Promise<McpConnection>\n /**\n * Pre-connect MCP servers in the background as soon as `createAgent` returns,\n * instead of deferring the bootstrap to the first `agent.run()`.\n *\n * Useful when MCP latency is the dominant cost of a cold start: callers that\n * construct the agent early (e.g. at process init) can hide the bootstrap\n * behind other setup work. If bootstrap fails, the error is stored and\n * surfaced on the first `agent.run()` / `agent.warmup()`; the in-flight\n * promise is `await`ed by both paths so the error is never silently lost.\n *\n * No-op when `mcpServers` is empty. Default: `false`.\n */\n eager?: boolean\n}\n\nexport interface Agent {\n hooks: Hookable<AgentHooks>\n run: (options: AgentRunOptions) => Promise<AgentStats>\n abort: () => void\n steer: (message: string) => void\n followUp: (message: string) => void\n waitForIdle: () => Promise<void>\n /**\n * Clear the agent's in-memory state (turns, queues, skill activations).\n * Fires `skills:deactivate` with `reason: 'reset'` for each previously active\n * skill. Awaiting lets host apps observe listener rejections.\n */\n reset: () => Promise<void>\n /**\n * Destroy the execution context and clean up resources.\n * Idempotent — safe to call from both a `finally` block and a signal handler.\n */\n destroy: () => Promise<void>\n /**\n * Explicitly activate a skill by name. Fires `skills:activate` with\n * `via: 'explicit'`. Throws if the skill isn't in the resolved catalog or\n * if the `maxActive` cap is reached. Idempotent — activating an already-active\n * skill is a no-op.\n */\n activateSkill: (name: string) => Promise<void>\n /**\n * Deactivate a skill by name. Fires `skills:deactivate` with `reason: 'explicit'`.\n * No-op when the skill wasn't active.\n */\n deactivateSkill: (name: string) => Promise<void>\n /**\n * Pre-connect MCP servers without running a turn. Idempotent and concurrency-safe:\n * - No MCP servers configured → resolves immediately.\n * - Connection already established → resolves immediately.\n * - Another `warmup()` / `run()` is bootstrapping → awaits the in-flight promise.\n *\n * Use from host code that wants to hide MCP bootstrap latency behind other\n * startup work (UI init, auth, etc.). Safe to call multiple times and from\n * multiple callers concurrently.\n */\n warmup: () => Promise<void>\n readonly isRunning: boolean\n readonly turns: SessionTurn[]\n readonly execution: ExecutionContext\n readonly handle: ExecutionHandle | null\n readonly session: Session | null\n /** Snapshot of currently active skills. */\n readonly activeSkills: readonly ActiveSkill[]\n /**\n * Frozen view of the underlying `provider.meta`. Read-only to prevent\n * accidental cross-agent contamination — writes are rejected at runtime\n * (via `Object.freeze`) and at compile time (via `Readonly`). To override\n * model / capability defaults, construct a new provider.\n */\n readonly meta: Readonly<Record<string, unknown>>\n}\n\n// ---------------------------------------------------------------------------\n// Behavior resolution\n// ---------------------------------------------------------------------------\n\nfunction resolveBehavior(\n agentBehavior?: AgentBehavior,\n runBehavior?: AgentBehavior,\n) {\n return {\n toolExecution: runBehavior?.toolExecution ?? agentBehavior?.toolExecution ?? 'parallel' as const,\n maxTurns: runBehavior?.maxTurns ?? agentBehavior?.maxTurns,\n maxTokens: runBehavior?.maxTokens ?? agentBehavior?.maxTokens,\n thinkingBudget: runBehavior?.thinkingBudget ?? agentBehavior?.thinkingBudget,\n schema: runBehavior?.schema ?? agentBehavior?.schema,\n cache: runBehavior?.cache ?? agentBehavior?.cache ?? true,\n toolOutputBudget: runBehavior?.toolOutputBudget ?? agentBehavior?.toolOutputBudget,\n compactStrategy: runBehavior?.compactStrategy ?? agentBehavior?.compactStrategy ?? 'off' as const,\n compactThreshold: runBehavior?.compactThreshold ?? agentBehavior?.compactThreshold,\n compactKeepTurns: runBehavior?.compactKeepTurns ?? agentBehavior?.compactKeepTurns,\n thinkingDecay: runBehavior?.thinkingDecay ?? agentBehavior?.thinkingDecay,\n dedupReads: runBehavior?.dedupReads ?? agentBehavior?.dedupReads,\n dedupTools: runBehavior?.dedupTools ?? agentBehavior?.dedupTools,\n requireReadBeforeEdit: runBehavior?.requireReadBeforeEdit ?? agentBehavior?.requireReadBeforeEdit,\n toolBudgets: runBehavior?.toolBudgets ?? agentBehavior?.toolBudgets,\n readLineNumbers: runBehavior?.readLineNumbers ?? agentBehavior?.readLineNumbers,\n elideStaleReads: runBehavior?.elideStaleReads ?? agentBehavior?.elideStaleReads,\n toolDisclosure: runBehavior?.toolDisclosure ?? agentBehavior?.toolDisclosure ?? 'eager' as const,\n toolSearch: runBehavior?.toolSearch ?? agentBehavior?.toolSearch,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Tool disclosure (progressive)\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve which configured MCP server a namespaced tool name belongs to.\n *\n * Tools coming through {@link connectMcpServers} are keyed `mcp_<server>_<tool>`.\n * Server names may themselves contain underscores, so a naive `split('_')[1]`\n * would mis-attribute tools — instead, we test each configured server name as\n * a prefix candidate and pick the longest match. This is O(N×M) per lookup\n * but the loop runs once at run start; not on a hot path.\n */\nfunction resolveServerForTool(\n toolName: string,\n servers: readonly McpServerConfig[] | undefined,\n): McpServerConfig | undefined {\n if (!servers || servers.length === 0)\n return undefined\n let best: McpServerConfig | undefined\n let bestLen = -1\n for (const server of servers) {\n const prefix = `mcp_${server.name}_`\n if (toolName.startsWith(prefix) && server.name.length > bestLen) {\n best = server\n bestLen = server.name.length\n }\n }\n return best\n}\n\ninterface DisclosureResult {\n /** Canonical names of tools that get full schemas in every turn's wire-level tool list. */\n eagerCanonicalNames: Set<string>\n /** Canonical names of every lazy tool — kept as a `Set` for fast O(1) gate lookup. */\n lazyCanonicalNames: Set<string>\n /** Lazy entries the catalog + `tool_search` advertise to the model (wire names). */\n lazyEntries: LazyToolEntry[]\n}\n\n/**\n * Partition a tool registry into eager and lazy buckets.\n *\n * Native + skill tools always end up in the eager bucket — only MCP tools\n * are eligible for lazy disclosure. The `tool_search` tool itself, when\n * registered, must be eager (otherwise the model has no way to discover\n * anything).\n *\n * Lazy entries carry both the wire (`name`, alias-rewritten) and the\n * canonical (`canonicalName`) so:\n * - The catalog and `tool_search` results show wire names — the only names\n * the model ever sees on the provider side.\n * - The unlock set is keyed by canonical names — the loop's `ctx.tools` map\n * and the dispatch path are alias-stable.\n */\nfunction partitionToolDisclosure(\n toolsBySpecName: Record<string, ToolDef>,\n mcpToolNames: ReadonlySet<string>,\n servers: readonly McpServerConfig[] | undefined,\n globalMode: 'eager' | 'lazy',\n toolAliases: Record<string, string> | undefined,\n): DisclosureResult {\n const eagerCanonicalNames = new Set<string>()\n const lazyCanonicalNames = new Set<string>()\n const lazyEntries: LazyToolEntry[] = []\n\n function wireFor(canonical: string): string {\n const aliased = toolAliases?.[canonical]\n return typeof aliased === 'string' && aliased.length > 0 ? aliased : canonical\n }\n\n for (const [canonicalName, def] of Object.entries(toolsBySpecName)) {\n if (!mcpToolNames.has(canonicalName)) {\n eagerCanonicalNames.add(canonicalName)\n continue\n }\n const server = resolveServerForTool(canonicalName, servers)\n const mode = server?.disclosure ?? globalMode\n if (mode === 'lazy') {\n lazyCanonicalNames.add(canonicalName)\n lazyEntries.push({\n name: wireFor(canonicalName),\n canonicalName,\n description: def.spec.description || '',\n inputSchema: (def.spec.inputSchema ?? { type: 'object', properties: {} }) as Record<string, unknown>,\n ...(server ? { server: server.name } : {}),\n })\n }\n else {\n eagerCanonicalNames.add(canonicalName)\n }\n }\n\n return { eagerCanonicalNames, lazyCanonicalNames, lazyEntries }\n}\n\ninterface BuildCatalogOptions {\n /**\n * When `'tool_search'` (or another wire name), the catalog's preface tells\n * the model to call that tool. When `null`, no call-to-action is emitted —\n * useful when the host opted out of the auto-injected `tool_search` and\n * wants the catalog text to stay non-misleading.\n */\n discoveryToolName: string | null\n}\n\nfunction buildSearchableCatalog(\n entries: readonly LazyToolEntry[],\n options: BuildCatalogOptions,\n): string {\n // Group by server so the model sees a coherent \"what's available where\"\n // view. Tools without a server attribution (shouldn't happen for MCP, but\n // defensive) land in an \"ungrouped\" bucket at the end.\n const byServer = new Map<string, LazyToolEntry[]>()\n const ungrouped: LazyToolEntry[] = []\n for (const entry of entries) {\n if (!entry.server) {\n ungrouped.push(entry)\n continue\n }\n const list = byServer.get(entry.server) ?? []\n list.push(entry)\n byServer.set(entry.server, list)\n }\n\n // Stable alphabetical group order so the catalog text doesn't shift between\n // runs based on parallel-bootstrap completion ordering. The system-prompt\n // cache breakpoint depends on byte-stability across turns/runs; without\n // this, a re-bootstrap could thrash the cache for no semantic reason.\n const serverNames = [...byServer.keys()].sort()\n\n const parts: string[] = []\n if (options.discoveryToolName) {\n parts.push(\n 'The following tools are available but their input schemas are NOT loaded in your context.',\n `Call the \\`${options.discoveryToolName}\\` tool to load schemas before invoking them. Surfaced tools persist for the rest of the run.`,\n '',\n )\n }\n parts.push('<searchable_tools>')\n for (const server of serverNames) {\n parts.push(` <server name=\"${escapeXml(server)}\">`)\n for (const entry of byServer.get(server)!)\n parts.push(` <tool name=\"${escapeXml(entry.name)}\">${escapeXml(entry.description)}</tool>`)\n parts.push(' </server>')\n }\n for (const entry of ungrouped)\n parts.push(` <tool name=\"${escapeXml(entry.name)}\">${escapeXml(entry.description)}</tool>`)\n parts.push('</searchable_tools>')\n return parts.join('\\n')\n}\n\n/**\n * Install a `tool:gate` listener that refuses dispatch on lazy tools the\n * model hasn't surfaced via `tool_search` yet. Production providers\n * (Anthropic, OpenAI) already enforce this server-side because the model\n * can only emit `tool_use` for tools in the request's `tools` list — but\n * relying on that alone leaves custom / OSS / mock providers (and any\n * future lenient validator) able to bypass the gate by quoting a name from\n * the catalog. The middleware closes the gap so lazy disclosure is a real\n * boundary, not just an advertisement filter.\n *\n * Returns an uninstall function the run-end teardown calls so handlers\n * never leak across runs.\n */\nfunction installLazyDisclosureGate(\n hooks: Hookable<AgentHooks>,\n lazyCanonicalNames: ReadonlySet<string>,\n unlocked: ReadonlySet<string>,\n discoveryToolName: string | null,\n): () => void {\n if (lazyCanonicalNames.size === 0)\n return () => {}\n return hooks.hook('tool:gate', (ctx) => {\n if (ctx.block)\n return\n if (!lazyCanonicalNames.has(ctx.name))\n return\n if (unlocked.has(ctx.name))\n return\n ctx.block = true\n ctx.reason = discoveryToolName\n ? `Tool \"${ctx.name}\" is listed in <searchable_tools> but its schema has not been loaded. Call the \\`${discoveryToolName}\\` tool with names: [\"${ctx.name}\"] first, then re-issue the call.`\n : `Tool \"${ctx.name}\" is listed in <searchable_tools> but its schema has not been loaded.`\n })\n}\n\n// ---------------------------------------------------------------------------\n// createAgent\n// ---------------------------------------------------------------------------\n\nexport function createAgent({ provider, name: agentName, system: agentSystem, tools: agentTools, toolAliases, behavior: agentBehavior, execution, mcpServers, session, skills: agentSkills, mcpConnector, eager }: AgentOptions): Agent {\n const hooks = createHooks<AgentHooks>()\n const executionContext = execution ?? createProcessContext()\n const sourceTools = agentTools ?? {}\n\n let abortController: AbortController | undefined\n let running = false\n let idleResolve: (() => void) | undefined\n let idlePromise: Promise<void> | undefined\n let executionHandle: ExecutionHandle | null = null\n let mcpConnection: McpConnection | null = null\n // Shared in-flight warmup promise. Guarantees that concurrent `warmup()` calls\n // and the lazy bootstrap inside `run()` observe the same outcome — we never\n // kick off the connector twice, and a failure in one caller propagates to\n // every awaiter instead of getting masked by a retry.\n let mcpWarmupPromise: Promise<void> | null = null\n const allMcpServers = mcpServers ?? []\n const steeringQueue: string[] = []\n const followUpQueue: string[] = []\n let conversationTurns: SessionTurn[] = session?.turns.slice() ?? []\n let runCounter = session?.runs.length ?? 0\n\n // Skills — resolved once at creation, used across runs.\n const skillsConfig = agentSkills\n const skillsEnabledValue = skillsConfig?.enabled\n const skillsDisabled = skillsEnabledValue === false || (Array.isArray(skillsEnabledValue) && skillsEnabledValue.length === 0)\n let resolvedSkills: SkillConfig[] | null = null\n let skillsCatalog: string | null = null\n // Cleanup fn for the inline-skills temp directory (created by\n // `resolveSkills` when `skills.write` is set). Replaced with the real\n // teardown on first resolution; called from `destroy()` so the OS temp\n // doesn't fill up across many short-lived agents.\n let skillsCleanup: () => void = () => {}\n\n // Per-agent activation state (lives across runs; `run-end` deactivates every\n // skill at each run boundary, `reset` clears everything, `resume` rehydrates).\n const skillActivationState = createSkillActivationState({\n maxActive: skillsConfig?.maxActive,\n })\n\n async function run(options: AgentRunOptions): Promise<AgentStats> {\n if (running) {\n throw new Error('Agent is already running. Use steer() or followUp() to queue messages, or waitForIdle().')\n }\n\n // Validate: prompt is required unless resuming a session with turns\n const hasSessionTurns = session && session.turns.length > 0\n if (!options.prompt && !hasSessionTurns) {\n throw new Error('prompt is required when no session with existing turns is provided')\n }\n if (!options.prompt && hasSessionTurns) {\n const lastTurn = session!.turns.at(-1)\n if (lastTurn && lastTurn.role !== 'user') {\n throw new Error('cannot resume without prompt: last session turn must be a user message')\n }\n }\n\n running = true\n abortController = new AbortController()\n const runId = `run_${++runCounter}`\n\n // Track run in session\n // `startRun` / `session:start` both expect a string prompt — coerce PromptPart[]\n // down to its concatenated text for bookkeeping. Full multimodal content still\n // lives in the turn pushed later.\n const promptLabel = typeof options.prompt === 'string'\n ? options.prompt\n : Array.isArray(options.prompt)\n ? options.prompt\n .filter((p): p is { type: 'text', text: string } => p.type === 'text')\n .map(p => p.text)\n .join('\\n')\n : ''\n // Default depth to 0 for top-level runs so the `runs` list always has a\n // numeric depth — lets consumers group/filter by level without null-checking.\n session?.startRun(runId, promptLabel, {\n ...(options.parentRunId ? { parentRunId: options.parentRunId } : {}),\n depth: typeof options.depth === 'number' ? options.depth : 0,\n })\n if (session) {\n await session.updateStatus('running')\n await hooks.callHook('session:start', { sessionId: session.id, runId, prompt: promptLabel })\n }\n\n // If an external signal is provided, wire it to our internal controller\n if (options.signal) {\n if (options.signal.aborted) {\n abortController.abort()\n }\n else {\n const onExternalAbort = () => abortController?.abort()\n options.signal.addEventListener('abort', onExternalAbort, { once: true })\n }\n }\n\n idlePromise = new Promise<void>((resolve) => {\n idleResolve = resolve\n })\n\n // Collect child agent stats reported via spawn:complete hook\n const childrenStats: ChildRunStats[] = []\n const unregisterSpawnHook = hooks.hook('spawn:complete', (ctx) => {\n childrenStats.push(ctx)\n })\n\n // Per-run hook registrations. Registered before runLoop, unregistered in finally,\n // so handlers never leak across runs even on throw paths.\n //\n // A typed hook registration interface is exposed on `options.hooks` so TS\n // catches signature mismatches at the call-site; here we have to cross the\n // `Object.entries` (string-keyed) barrier, so we validate the event name\n // against the known hook surface at runtime. Unknown keys would otherwise\n // silently never fire.\n const perRunUnregisters: Array<() => void> = []\n if (options.hooks) {\n for (const [event, handler] of Object.entries(options.hooks)) {\n if (!isKnownHookEvent(event)) {\n throw new Error(\n `Unknown hook event \"${event}\" passed to run(). See AgentHooks for valid events.`,\n )\n }\n const handlerList = Array.isArray(handler) ? handler : [handler]\n for (const fn of handlerList) {\n if (typeof fn !== 'function')\n continue\n // Safe cast: event was validated via isKnownHookEvent. Handler arity\n // is host-validated via the AgentRunOptions['hooks'] surface type.\n perRunUnregisters.push(hooks.hook(event, fn as AgentHooks[typeof event]))\n }\n }\n }\n\n // Spawn execution context\n if (!executionHandle) {\n executionHandle = await executionContext.spawn()\n }\n\n // Connect MCP servers lazily on first run. Delegated to `warmup()` so the\n // fast-path (\"already connected\") and the slow-path (\"pending warmup from\n // `eager: true` or a concurrent `agent.warmup()` call\") share one promise\n // and one outcome.\n if (allMcpServers.length > 0 && !mcpConnection) {\n await warmup()\n }\n\n // Resolve skills lazily on first run (skip if explicitly disabled).\n // Shell interpolation was previously applied here once per agent — it now\n // runs per `skills_use` invocation (Phase 3) so command output is fresh on\n // each activation rather than cached at resolution time.\n if (!skillsDisabled && skillsConfig && !resolvedSkills) {\n const bundle = await resolveSkills(skillsConfig)\n resolvedSkills = bundle.skills\n skillsCleanup = bundle.cleanup\n await hooks.callHook('skills:resolve', { skills: resolvedSkills })\n\n // The catalog prose branches on whether the `skills_use` tool will be\n // auto-injected into this agent's tool set. That decision happens later\n // in this function (at tool-merge time), but we can predict it here:\n // skills tool is registered iff the config doesn't opt out AND the\n // catalog is non-empty. A run-level `tools` override would suppress\n // injection, but we don't yet know `options.tools` — so the catalog may\n // occasionally mention `skills_use` even when a specific run uses\n // `tools: {}`. That's an acceptable mismatch (the model reads the\n // system prompt once; consumers doing aggressive per-run tool overrides\n // already accept that context may reflect the agent default).\n const skillsToolRegistered = skillsConfig?.tool !== false && resolvedSkills.length > 0\n const catalogCtx = {\n catalog: buildCatalog(resolvedSkills, { skillsToolRegistered }),\n skills: resolvedSkills,\n }\n await hooks.callHook('skills:catalog', catalogCtx)\n skillsCatalog = catalogCtx.catalog\n }\n\n // Session-resume rehydration: when resuming a session with prior turns, scan\n // for `skills_use` tool_call blocks and re-mark those skills active. Does\n // NOT fire `skills:activate` again — the model already saw the response\n // content in the carried-forward history. Fired with `via: 'resume'` so\n // downstream consumers can distinguish a fresh activation from a rehydrated\n // one.\n if (resolvedSkills && session && session.turns.length > 0 && skillActivationState.active().length === 0) {\n const skillsByName = new Map(resolvedSkills.map(s => [s.name, s]))\n for (const turn of session.turns) {\n if (turn.role !== 'assistant')\n continue\n for (const block of turn.content) {\n if (block.type !== 'tool_call' || block.name !== 'skills_use')\n continue\n const skillName = (block.input as { name?: string } | undefined)?.name\n if (!skillName)\n continue\n const skill = skillsByName.get(skillName)\n if (!skill)\n continue\n if (skillActivationState.activate(skill, 'resume') === 'ok') {\n await hooks.callHook('skills:activate', { skill, via: 'resume' })\n }\n }\n }\n }\n\n const thinking = options.thinking ?? 'off'\n const model = options.model ?? provider.meta.defaultModel\n const resolvedBehavior = resolveBehavior(agentBehavior, options.behavior)\n const { toolExecution, maxTurns, maxTokens, thinkingBudget, schema, cache, toolOutputBudget, compactStrategy, compactThreshold, compactKeepTurns, thinkingDecay, dedupTools, toolBudgets, elideStaleReads, toolDisclosure, toolSearch } = resolvedBehavior\n\n // System prompt: run-time option > agent default > fallback\n let system = options.system || agentSystem || 'You are a helpful assistant.'\n\n // Append skills catalog to system prompt\n if (skillsCatalog) {\n system = `${system}\\n\\n${skillsCatalog}`\n }\n\n // Tool resolution: run-level override > agent tools + MCP tools\n const runBaseTools = options.tools !== undefined\n ? options.tools\n : (mcpConnection\n ? { ...sourceTools, ...mcpConnection.tools }\n : sourceTools)\n\n // Track which tools came from MCP — only these are eligible for lazy\n // disclosure. A run-level `tools` override skips MCP entirely so the set\n // stays empty in that case.\n const mcpToolNames: ReadonlySet<string>\n = options.tools === undefined && mcpConnection\n ? new Set(Object.keys(mcpConnection.tools))\n : new Set<string>()\n\n // Auto-inject `skills_use` / `skills_read` / `skills_run_script` when the\n // resolved skills catalog is non-empty. Opt out via `SkillsConfig.tool: false`.\n //\n // Skill tools are merged at the same tier as agent/MCP — a run-level\n // `tools: {}` override still wins (consistent with \"no tools means no tools\").\n // Agent-defined tools with the same name win over auto-injected ones.\n const shouldInjectSkillTools\n = options.tools === undefined\n && !!resolvedSkills\n && resolvedSkills.length > 0\n && skillsConfig?.tool !== false\n\n const mergedWithSkills = shouldInjectSkillTools\n ? {\n // Auto-injected first so agent + MCP tools can override by name.\n skills_use: createSkillsUseTool({\n catalog: resolvedSkills!,\n state: skillActivationState,\n hooks,\n }),\n skills_read: createSkillsReadTool({\n catalog: resolvedSkills!,\n state: skillActivationState,\n }),\n skills_run_script: createSkillsRunScriptTool({\n catalog: resolvedSkills!,\n state: skillActivationState,\n scriptTimeoutMs: skillsConfig?.scriptTimeoutMs,\n }),\n ...runBaseTools,\n }\n : runBaseTools\n\n // Build a spec-name-indexed map for the loop (models call tools by spec name, not map key)\n const toolsPreSearch: Record<string, typeof mergedWithSkills[string]> = {}\n for (const tool of Object.values(mergedWithSkills)) {\n toolsPreSearch[tool.spec.name] = tool\n }\n\n // Progressive tool disclosure — partition the registry into eager vs lazy\n // buckets and prepare the per-run `unlocked` set the loop reads when\n // rebuilding the wire-level tool list.\n //\n // Native (non-MCP) tools are always eager; `tool_search` itself must be\n // eager too (the discovery path can't gate on its own surfacing). The\n // `unlocked` set seeds with every eager canonical tool name and grows as\n // the model surfaces lazy tools through `tool_search`.\n //\n // We pass `toolAliases` so lazy entries can carry their wire-level\n // (alias-rewritten) display name — what the catalog and `tool_search`\n // results show to the model — while keeping the canonical name on the\n // entry for unlock-set membership and dispatch-map lookup.\n const disclosure = partitionToolDisclosure(toolsPreSearch, mcpToolNames, mcpServers, toolDisclosure, toolAliases)\n const unlocked = new Set<string>(disclosure.eagerCanonicalNames)\n const hostDefinedToolSearch = !!toolsPreSearch.tool_search\n const shouldInjectToolSearch\n = disclosure.lazyEntries.length > 0\n && toolSearch?.tool !== false\n && !hostDefinedToolSearch\n let tools = toolsPreSearch\n if (shouldInjectToolSearch) {\n const toolSearchTool = createToolSearchTool({\n catalog: disclosure.lazyEntries,\n unlocked,\n ...(toolSearch?.limit !== undefined ? { defaultLimit: toolSearch.limit } : {}),\n })\n tools = { ...toolsPreSearch, [toolSearchTool.spec.name]: toolSearchTool }\n unlocked.add(toolSearchTool.spec.name)\n }\n\n // Decide which discovery-tool name (if any) the catalog text should\n // point at. `tool_search` when we auto-injected, the host's tool when\n // they brought their own (we use the wire/alias name in both cases —\n // that's what the model is told to call), and `null` when they fully\n // opted out so the catalog stays accurate without misleading prose.\n const discoveryToolName: string | null = shouldInjectToolSearch\n ? 'tool_search'\n : (hostDefinedToolSearch\n ? (toolAliases?.tool_search ?? 'tool_search')\n : null)\n\n // Append the lazy-tool catalog AFTER the skills catalog so both use the\n // same anchor point — the catalog text is stable across turns and rides\n // the system-prompt cache breakpoint.\n if (disclosure.lazyEntries.length > 0) {\n system = `${system}\\n\\n${buildSearchableCatalog(disclosure.lazyEntries, { discoveryToolName })}`\n }\n\n // Build alias maps once per run. Throws on alias collisions.\n const aliasMaps = buildAliasMaps(toolAliases, Object.keys(tools))\n\n // Hard gate for lazy tools — refuses dispatch on canonical names not yet\n // in `unlocked`. Production providers already enforce this via their\n // tool-list validator, but the middleware closes the gap for custom /\n // mock / lenient providers and for any path where a model quotes a name\n // straight from the catalog. The hook is run-scoped; teardown lives in\n // the `finally` below.\n //\n // Ordering note: this gate registers AFTER `installAllowedToolsGate`\n // (skill allowlist), `installToolBudgetsGate`, and `installDedupToolsGate`.\n // A skill refusal therefore wins over a \"load via tool_search\" message,\n // which is the right priority — and a dedup `result` substitute can only\n // hit on a previously-recorded successful call, which had to pass this\n // gate to land in the cache, so dedup never short-circuits past an\n // un-unlocked tool.\n const uninstallLazyDisclosureGate = installLazyDisclosureGate(\n hooks,\n disclosure.lazyCanonicalNames,\n unlocked,\n discoveryToolName,\n )\n\n // Closure that recomputes the wire-level tool list from the current\n // `unlocked` snapshot. Called once up-front for the seed value and again\n // per-iteration in the loop when lazy disclosure may have grown the set.\n // Safe to call repeatedly — `provider.formatTools` is a pure mapping.\n //\n // Caching note: each successful `tool_search` appends one or more tools\n // to the formatted list, which moves provider-side cache breakpoints\n // (Anthropic marks the last tool, OpenAI-compat is similar). That costs\n // one tool-list cache miss per discovery wave; subsequent turns with the\n // same unlocked set hit cache normally. With many lazy tools and few\n // discovery waves this still beats eager (which always sends every\n // schema), but it is not a free optimisation.\n function buildFormattedTools(): unknown[] {\n const specs: ToolSpec[] = []\n for (const t of Object.values(tools)) {\n if (!unlocked.has(t.spec.name))\n continue\n specs.push({\n name: aliasMaps.aliasByCanonical.get(t.spec.name) ?? t.spec.name,\n description: t.spec.description || '',\n inputSchema: t.spec.inputSchema,\n })\n }\n return specs.length > 0 ? provider.formatTools(specs) : []\n }\n const formattedTools = buildFormattedTools()\n\n // Build initial turns — carry forward existing session history if resuming\n const turns: SessionTurn[] = []\n\n // Resume: prepend prior conversation turns from session.\n //\n // Triggers on re-runs (runs > 0) or promptless runs (session turns already\n // contain the user message). **Excluded for child agents**: when the spawn\n // tool runs with `persist: true`, the child agent shares the parent's\n // session for *storage* but its conversation must start fresh from the\n // task prompt. Otherwise the child would pull in the parent's in-flight\n // assistant turn — including the parent's pending `spawn` tool_use — and\n // every provider (Anthropic loudly, OpenAI implicitly) rejects a message\n // history where a `tool_use` lacks its matching `tool_result`.\n const isResume = session\n && session.turns.length > 0\n && (session.runs.length > 0 || !options.prompt)\n && !options.parentRunId\n if (isResume) {\n // Filter out turns from subagent runs (depth > 0). With `persist: true`\n // every child agent appends its own user/assistant turns to the shared\n // `session.turns` array, sandwiched between the parent's `tool_call`\n // (for `spawn`) and the parent's `tool_result`. Replaying those child\n // turns into the resumed parent's conversation puts an unrelated\n // user/assistant pair right after the `tool_call`, breaking the\n // Anthropic `tool_use → tool_result` adjacency rule and crashing the\n // very first API call after reload.\n //\n // We keep turns with no `runId` (legacy data) and turns whose `runId`\n // belongs to a top-level run; everything that came from a subagent run\n // stays in the persisted session for transcript reconstruction (see\n // `eventsFromTurns`) but is invisible to the resumed conversation.\n const childRunIds = new Set(\n session!.runs.filter(r => (r.depth ?? 0) > 0).map(r => r.id),\n )\n const resumed = childRunIds.size === 0\n ? session!.turns\n : session!.turns.filter(t => !t.runId || !childRunIds.has(t.runId))\n turns.push(...resumed)\n }\n\n // Track where this run's turns start (after any resumed turns)\n const runTurnStart = turns.length\n\n if (options.system) {\n await hooks.callHook('system:before', { system: options.system })\n }\n\n const promptParts = canonicalizePrompt(options.prompt)\n if (promptParts) {\n const promptMsg = buildPromptMessage(provider, promptParts)\n turns.push({\n id: crypto.randomUUID(),\n runId,\n role: promptMsg.role,\n content: promptMsg.content,\n createdAt: Date.now(),\n })\n }\n\n conversationTurns = turns\n\n // Track how many turns existed before this run started (for incremental persistence)\n let lastPersistedTurnCount = isResume ? session!.turns.length : 0\n\n // Persist + emit the seeded user turn before any assistant `turn:before` fires.\n // Without this, the seeded turn was persisted only after the first `turn:after`,\n // so DB rows ordered by `created_at` placed the user turn AFTER its assistant\n // response. Consumers already dedupe `session:turns` payloads, so emitting the\n // seeded turn separately is safe.\n if (session && turns.length > lastPersistedTurnCount) {\n const seededTurns = turns.slice(lastPersistedTurnCount)\n await session.appendTurns(seededTurns)\n lastPersistedTurnCount = turns.length\n await hooks.callHook('session:turns', { sessionId: session.id, turns: seededTurns, count: turns.length })\n }\n\n // Incremental turn persistence after each assistant turn\n const unregisterSessionSync = session\n ? hooks.hook('turn:after', async () => {\n const newTurns = turns.slice(lastPersistedTurnCount)\n if (newTurns.length > 0) {\n await session.appendTurns(newTurns)\n lastPersistedTurnCount = turns.length\n await hooks.callHook('session:turns', { sessionId: session.id, turns: newTurns, count: turns.length })\n }\n })\n : undefined\n\n // Persist any turns not yet synced to the session store\n async function flushTurns() {\n if (!session)\n return\n const remaining = turns.slice(lastPersistedTurnCount)\n if (remaining.length > 0) {\n await session.appendTurns(remaining)\n lastPersistedTurnCount = turns.length\n await hooks.callHook('session:turns', { sessionId: session.id, turns: remaining, count: turns.length })\n }\n }\n\n // Deactivate every active skill with `reason: 'run-end'`. Called at each\n // natural run boundary regardless of status (completed / aborted / error).\n async function deactivateAllSkills() {\n for (const record of skillActivationState.clear())\n await hooks.callHook('skills:deactivate', { skill: record.skill, reason: 'run-end' })\n }\n\n // Finalize session: persist run status and fire session:end\n async function finalizeSession(status: SessionEndStatus) {\n if (!session)\n return\n const run = session.runs.find(r => r.id === runId)\n if (run)\n await session.updateRun(run)\n await session.updateStatus(status === 'aborted' ? 'idle' : status)\n await hooks.callHook('session:end', { sessionId: session.id, runId, status, turnRange: [runTurnStart, turns.length - 1] })\n }\n\n // Install the skill allowed-tools gate for this run; remove it in `finally`\n // so tool:gate listeners never leak across runs.\n const uninstallAllowedToolsGate = installAllowedToolsGate(hooks, skillActivationState)\n\n // Per-tool soft call budgets. Installed BEFORE dedup so a budget block\n // wins over a dedup hit — otherwise a model spamming a dedup-eligible\n // tool would bypass the cap entirely (every dedup hit short-circuits\n // budgets that fire later in the chain). Order: allowed-tools → budgets\n // → dedup → consumer hooks. The middleware owns its own per-tool\n // approval counter so within-batch ordering is correct in parallel mode.\n const uninstallToolBudgets = installToolBudgetsGate(\n hooks,\n () => toolBudgets,\n msg => steeringQueue.push(msg),\n )\n\n // Per-tool argument-dedup middleware. No-op when `behavior.dedupTools` is\n // empty/unset or when the run is sessionless. Behavior is the field-merged\n // resolution of agent + run defaults — same precedence as every other\n // behavior knob.\n const uninstallDedupTools = installDedupToolsGate(\n hooks,\n () => dedupTools,\n () => session ?? undefined,\n )\n\n const runStartMs = Date.now()\n\n const runDepth = typeof options.depth === 'number' ? options.depth : 0\n\n try {\n const stats = await runLoop({\n provider,\n hooks,\n agentName,\n agentSystem,\n agentTools: sourceTools,\n agentToolAliases: toolAliases,\n agentMcpServers: mcpServers,\n agentSkills,\n // Forward the resolved view (agent + run merged) so per-run overrides\n // of `dedupReads` / `requireReadBeforeEdit` / etc. are visible to\n // tools via `ToolContext.behavior`.\n agentBehavior: resolvedBehavior,\n tools,\n formattedTools,\n rebuildFormattedTools: disclosure.lazyEntries.length > 0 ? buildFormattedTools : undefined,\n aliasMaps,\n model,\n system,\n thinking,\n toolExecution,\n signal: abortController.signal,\n execution: executionContext,\n handle: executionHandle!,\n steeringQueue,\n followUpQueue,\n turns,\n runId,\n generateTurnId: () => session?.generateTurnId() ?? crypto.randomUUID(),\n maxTurns,\n maxTokens,\n ...(session ? { session } : {}),\n depth: runDepth,\n thinkingBudget,\n schema,\n cache,\n toolOutputBudget,\n compactStrategy,\n compactThreshold,\n compactKeepTurns,\n ...(elideStaleReads !== undefined ? { elideStaleReads } : {}),\n ...(thinkingDecay !== undefined ? { thinkingDecay } : {}),\n runStartMs,\n runToolCounts: {},\n })\n\n // `stats` is the parent-loop view returned by `runLoop` —\n // `totalIn/Out/turnUsage` cover this run's loop only. Children are\n // collected separately via `spawn:complete` and folded into the\n // returned `AgentStats` below; the loop view is preserved verbatim\n // for `session.completeRun(...)` so per-run session ledgers stay\n // additive (children are persisted as their own runs in the same\n // session — folding cumulative numbers in here would double-count).\n const parentTurnCost = stats.turnUsage\n ?.reduce((sum, t) => sum + (t.cost ?? 0), 0) ?? 0\n\n // Roll children's already-cumulative totals into the parent. Each\n // child's `stats.totalIn/Out/cost/totalCacheRead/totalCacheCreation`\n // was finalized through this same path before bubbling up via\n // `spawn:complete`, so a single-level sum lands grandchildren\n // transitively.\n let childrenIn = 0\n let childrenOut = 0\n let childrenCost = 0\n let childrenCacheRead = 0\n let childrenCacheCreation = 0\n for (const c of childrenStats) {\n childrenIn += c.stats.totalIn\n childrenOut += c.stats.totalOut\n childrenCost += c.stats.cost ?? 0\n childrenCacheRead += c.stats.totalCacheRead\n childrenCacheCreation += c.stats.totalCacheCreation\n }\n\n const cumulativeCost = parentTurnCost + childrenCost\n\n const finalStats: AgentStats = {\n ...stats,\n totalIn: stats.totalIn + childrenIn,\n totalOut: stats.totalOut + childrenOut,\n totalCacheRead: stats.totalCacheRead + childrenCacheRead,\n totalCacheCreation: stats.totalCacheCreation + childrenCacheCreation,\n ...(cumulativeCost > 0 ? { cost: cumulativeCost } : {}),\n children: childrenStats.length > 0 ? childrenStats : undefined,\n }\n\n await flushTurns()\n\n // If aborted during loop (loop broke cleanly without throwing)\n if (abortController.signal.aborted) {\n session?.abortRun(runId)\n await finalizeSession('aborted')\n await hooks.callHook('agent:done', finalStats)\n return finalStats\n }\n\n session?.completeRun(runId, {\n turns: stats.turns,\n tokensIn: stats.totalIn,\n tokensOut: stats.totalOut,\n turnUsage: stats.turnUsage,\n cost: parentTurnCost > 0 ? parentTurnCost : undefined,\n })\n await finalizeSession('completed')\n\n await hooks.callHook('agent:done', finalStats)\n return finalStats\n }\n catch (err) {\n await flushTurns()\n\n // If aborted, provider may throw — return gracefully\n if (abortController.signal.aborted) {\n session?.abortRun(runId)\n await finalizeSession('aborted')\n const stats: AgentStats = {\n totalIn: 0,\n totalOut: 0,\n totalCacheRead: 0,\n totalCacheCreation: 0,\n turns: 0,\n elapsed: 0,\n }\n await hooks.callHook('agent:done', stats)\n return stats\n }\n\n const message = err instanceof Error ? err.message : String(err)\n session?.errorRun(runId, message)\n await finalizeSession('error')\n throw err\n }\n finally {\n // Deactivate every skill active at run end. Runs on every exit path —\n // completed, aborted, or thrown — so activation state never leaks across\n // run boundaries. Explicit activation via `agent.activateSkill()` is\n // subject to the same rule: it lives until the next run boundary.\n await deactivateAllSkills()\n\n // Teardown run-scoped skill handlers (allowed-tools gate, etc.).\n uninstallAllowedToolsGate()\n uninstallDedupTools()\n uninstallToolBudgets()\n uninstallLazyDisclosureGate()\n\n unregisterSpawnHook()\n unregisterSessionSync?.()\n for (const unregister of perRunUnregisters)\n unregister()\n running = false\n abortController = undefined\n steeringQueue.length = 0\n followUpQueue.length = 0\n idleResolve?.()\n idlePromise = undefined\n idleResolve = undefined\n }\n }\n\n function abort() {\n abortController?.abort()\n }\n\n function steer(message: string) {\n steeringQueue.push(message)\n }\n\n function followUpFn(message: string) {\n followUpQueue.push(message)\n }\n\n function waitForIdle(): Promise<void> {\n return idlePromise ?? Promise.resolve()\n }\n\n async function reset() {\n // Reject mid-run resets explicitly. The loop holds its own reference to\n // the in-flight `turns` array (built per-`run()`), so clearing\n // `conversationTurns` here would have left the loop's view untouched\n // and the next `turn:after` would re-link it back to the unflushed\n // buffer — silently making the call a no-op. Throwing forces callers\n // to `await agent.waitForIdle()` first so reset's invariant\n // (\"everything cleared\") actually holds.\n if (running) {\n throw new Error(\n 'Cannot reset() while the agent is running. Call `agent.abort()` and `await agent.waitForIdle()` first.',\n )\n }\n conversationTurns = []\n steeringQueue.length = 0\n followUpQueue.length = 0\n // Activation state is agent-scoped — a reset should clear it too.\n // We fire `skills:deactivate` with reason='reset' for each previously active\n // skill so consumer telemetry stays consistent. Previously fire-and-forget;\n // awaiting ensures a listener's rejection surfaces rather than silently\n // breaking the invariant \"reset clears activation\".\n const cleared = skillActivationState.clear()\n for (const record of cleared)\n await hooks.callHook('skills:deactivate', { skill: record.skill, reason: 'reset' })\n }\n\n async function activateSkill(name: string): Promise<void> {\n if (!resolvedSkills) {\n throw new Error(\n `Cannot activate skill \"${name}\" — skills have not been resolved yet. `\n + 'Call activateSkill after the first `run()`, or pass a skills config that resolves at agent-creation time.',\n )\n }\n const skill = resolvedSkills.find(s => s.name === name)\n if (!skill) {\n const available = resolvedSkills.map(s => s.name).join(', ') || '<none>'\n throw new Error(`Unknown skill \"${name}\". Available skills: ${available}.`)\n }\n const outcome = skillActivationState.activate(skill, 'explicit')\n if (outcome === 'cap-reached') {\n throw new Error(\n `Cannot activate skill \"${name}\" — the maxActive cap of ${skillsConfig?.maxActive} has been reached.`,\n )\n }\n if (outcome === 'ok')\n await hooks.callHook('skills:activate', { skill, via: 'explicit' })\n }\n\n async function deactivateSkill(name: string): Promise<void> {\n const removed = skillActivationState.deactivate(name)\n if (removed)\n await hooks.callHook('skills:deactivate', { skill: removed.skill, reason: 'explicit' })\n }\n\n // Wrap session methods to fire hooks\n if (session) {\n const originalSave = session.save.bind(session)\n const originalSetMeta = session.setMeta.bind(session)\n\n session.save = async () => {\n await originalSave()\n await hooks.callHook('session:save', { sessionId: session.id })\n }\n\n // `setMeta` has a synchronous surface (hosts `await setMeta` wouldn't gain\n // anything), but we must still surface listener errors — a promise\n // without a handler becomes an unhandled rejection. Route rejections\n // through a no-op `.catch` that records on the session via updateStatus\n // is overkill; logging here is sufficient because the primary side effect\n // (the metadata write) has already succeeded.\n session.setMeta = (key: string, value: unknown) => {\n originalSetMeta(key, value)\n // `callHook` returns `void | Promise<...>` depending on whether any\n // listener is async. Normalize to a promise so we can attach a rejection\n // handler without leaking an unhandled rejection. Intentionally do not\n // re-throw — the sync contract must not leak a listener failure back to\n // the caller of setMeta.\n void Promise.resolve(hooks.callHook('session:meta', { sessionId: session.id, key, value })).catch((err: unknown) => {\n console.error('[zidane] session:meta listener rejected:', err)\n })\n }\n }\n\n let destroyed = false\n\n /**\n * Pre-connect MCP servers. Returns the shared in-flight promise when a\n * bootstrap is already running, so concurrent callers converge on one\n * connection. Clears the cached promise on failure so the next caller can\n * retry — leaving a rejected promise cached would permanently poison future\n * runs on the same agent.\n */\n async function warmup(): Promise<void> {\n // Post-destroy no-op. Without this guard, a `warmup()` (or a `run()` that\n // calls warmup) after `destroy()` would open a fresh MCP connection that\n // nobody ever closes — the `mcpConnection.close()` branch of `destroy` has\n // already run and won't run again.\n if (destroyed)\n return\n if (mcpConnection || allMcpServers.length === 0)\n return\n if (mcpWarmupPromise)\n return mcpWarmupPromise\n\n mcpWarmupPromise = (async () => {\n const connection = mcpConnector\n ? await mcpConnector(allMcpServers)\n : await connectMcpServers(allMcpServers, undefined, hooks)\n // If destroy() fired while we were bootstrapping, close the fresh\n // connection immediately rather than leak it into a destroyed agent.\n // destroy() awaits this promise before returning, so its subsequent\n // `if (mcpConnection) close()` branch would handle this too — but only\n // when assignment wins the race. Closing here unconditionally is safer.\n if (destroyed) {\n await connection.close().catch(() => {})\n return\n }\n mcpConnection = connection\n })()\n\n try {\n await mcpWarmupPromise\n }\n catch (err) {\n // Drop the cached promise so the next `run()` / `warmup()` call gets a\n // fresh attempt. MCP failures at bootstrap are typically transient\n // (network blip, slow stdio spawn) and the partial-failure path in\n // `connectMcpServers` already tolerates any server that does come up.\n mcpWarmupPromise = null\n throw err\n }\n }\n\n async function destroy() {\n // Idempotent: a host may call destroy() in a `finally` block AND a\n // process-level signal handler; racing double-frees crash the MCP SDK.\n if (destroyed)\n return\n destroyed = true\n // If destroy races with a still-pending warmup, wait for it to finish\n // before closing. Otherwise `mcpConnection` could be populated after\n // destroy() returns and leak clients past the agent's lifetime.\n if (mcpWarmupPromise) {\n try {\n await mcpWarmupPromise\n }\n catch {\n // Bootstrap failure is already surfaced to the warmup caller; destroy\n // path just wants to clean up whatever partial state exists.\n }\n }\n if (mcpConnection) {\n await mcpConnection.close()\n mcpConnection = null\n }\n if (executionHandle) {\n await executionContext.destroy(executionHandle)\n executionHandle = null\n }\n // Remove the inline-skills temp directory if one was materialized.\n // No-op when `skills.write` was unused.\n skillsCleanup()\n skillsCleanup = () => {}\n }\n\n // Eager bootstrap: kick off MCP connection in the background so the first\n // `run()` doesn't pay the full bootstrap cost. Rejection is captured on the\n // shared warmup promise; the next `warmup()` / `run()` caller observes it.\n // A detached `.catch` swallows the rejection here only to prevent Node's\n // unhandled-rejection warning — the error is still attached to the promise\n // for the next awaiter.\n if (eager && allMcpServers.length > 0) {\n void warmup().catch(() => {})\n }\n\n return {\n hooks,\n run,\n abort,\n steer,\n followUp: followUpFn,\n waitForIdle,\n reset,\n destroy,\n warmup,\n activateSkill,\n deactivateSkill,\n get isRunning() { return running },\n get turns() { return conversationTurns },\n get execution() { return executionContext },\n get handle() { return executionHandle },\n get session() { return session ?? null },\n get activeSkills() { return skillActivationState.active() },\n // Expose a frozen view of provider.meta. Hosts previously could mutate\n // the underlying provider meta (e.g. via `agent.meta.defaultModel = …`),\n // which quietly affected every other agent sharing the same provider\n // instance. Freezing forces callers to construct a new provider when\n // they want to override model/capabilities.\n meta: Object.freeze({ ...provider.meta }),\n }\n}\n","/**\n * Internal helpers shared between the `edit` and `multi_edit` tools.\n *\n * Not part of the public API — intentionally not re-exported from `tools/index.ts`\n * or the package barrel.\n */\n\n/**\n * Count exact (non-overlapping) occurrences of `needle` in `haystack`.\n * Returns 0 for an empty needle — both edit tools reject empty `old_string`\n * up front, so this branch is defensive rather than semantic.\n */\nexport function countExactMatches(haystack: string, needle: string): number {\n if (needle.length === 0)\n return 0\n let count = 0\n let idx = 0\n while (true) {\n const next = haystack.indexOf(needle, idx)\n if (next === -1)\n break\n count++\n idx = next + needle.length\n }\n return count\n}\n\n// ---------------------------------------------------------------------------\n// Curly-quote normalization + SDK-sanitization fallbacks\n// ---------------------------------------------------------------------------\n//\n// Models can't reliably emit Unicode curly quotes, and the Anthropic API\n// silently sanitizes a handful of XML-like tags before they hit the model\n// (`<name>` → `<n>`, etc.). When `old_string` doesn't match exactly, we retry\n// against the same content with both transforms applied so an \"old_string not\n// found\" failure that's only typographical resolves on the second pass.\n//\n// Mirrors the Claude Code Edit tool's recovery strategy. Verbatim port of the\n// quote constants and the desanitization table; the resolve loop below is\n// reorganized to share state between exact / quote-normalized / desanitized.\n\nexport const LEFT_SINGLE_CURLY_QUOTE = '\\u2018'\nexport const RIGHT_SINGLE_CURLY_QUOTE = '\\u2019'\nexport const LEFT_DOUBLE_CURLY_QUOTE = '\\u201C'\nexport const RIGHT_DOUBLE_CURLY_QUOTE = '\\u201D'\n\n/** Map curly quotes (any of the four) to their straight ASCII equivalents. */\nexport function normalizeQuotes(str: string): string {\n return str\n .replaceAll(LEFT_SINGLE_CURLY_QUOTE, '\\'')\n .replaceAll(RIGHT_SINGLE_CURLY_QUOTE, '\\'')\n .replaceAll(LEFT_DOUBLE_CURLY_QUOTE, '\"')\n .replaceAll(RIGHT_DOUBLE_CURLY_QUOTE, '\"')\n}\n\n/**\n * Substitutions Anthropic's API applies to assistant output before the model\n * sees it. The model emits the sanitized form; the file on disk contains the\n * unsanitized form. We undo the substitutions on `old_string` so the search\n * lands on the actual file contents.\n *\n * Verbatim from `claude-code/tools/FileEditTool/utils.ts`.\n */\nconst DESANITIZATIONS: ReadonlyArray<readonly [string, string]> = [\n ['<fnr>', '<function_results>'],\n ['<n>', '<name>'],\n ['</n>', '</name>'],\n ['<o>', '<output>'],\n ['</o>', '</output>'],\n ['<e>', '<error>'],\n ['</e>', '</error>'],\n ['<s>', '<system>'],\n ['</s>', '</system>'],\n ['<r>', '<result>'],\n ['</r>', '</result>'],\n ['< META_START >', '<META_START>'],\n ['< META_END >', '<META_END>'],\n ['< EOT >', '<EOT>'],\n ['< META >', '<META>'],\n ['< SOS >', '<SOS>'],\n ['\\n\\nH:', '\\n\\nHuman:'],\n ['\\n\\nA:', '\\n\\nAssistant:'],\n]\n\n/**\n * Apply the SDK desanitization table to a string. Exported so the edit tools\n * can apply it to `new_string` whenever `old_string` matched via a\n * desanitize-class fallback — keeps the file's unsanitized form on disk\n * instead of writing the model's abbreviated form back.\n */\nexport function desanitize(s: string): string {\n let out = s\n for (const [from, to] of DESANITIZATIONS)\n out = out.replaceAll(from, to)\n return out\n}\n\n/**\n * Strip line-number prefixes from each line of a needle, used as a recovery\n * fallback when the model pastes a `read_file` chunk verbatim into\n * `old_string` — the on-disk file doesn't carry the metadata prefix.\n *\n * Accepts three separator characters so a model that learned on a different\n * agent stack still works here: `\\t` (Claude Code compact, our default),\n * `|`, and `→`. Pattern: optional leading whitespace, 1-9 digits, then one\n * of `\\t | →`. The 9-digit ceiling covers files up to ~1B lines without\n * overshooting into legitimate `\\d{N}<sep>` content like Markdown table\n * cells with long numeric IDs.\n */\nconst LINE_NUMBER_PREFIX_RE = /^[ \\t]*\\d{1,9}[\\t|\\u2192]/gm\nexport function stripLineNumberPrefixes(s: string): string {\n return s.replace(LINE_NUMBER_PREFIX_RE, '')\n}\n\n/**\n * Locate the actual substring in `haystack` that corresponds to `needle`,\n * recovering from typographical mismatch on six escalating fallbacks:\n *\n * 1. Exact substring match (the happy path — no transformation).\n * 2. Curly-quote normalization on both sides — when the model emits straight\n * quotes but the file has curly ones (or vice versa), the slice of the\n * file at the matched position carries the file's actual typography.\n * 3. Anthropic-sanitization undo on the needle — the model's `<n>` becomes\n * the file's `<name>`, etc.\n * 4. Combined: desanitize + quote normalization on the needle.\n * 5. Line-number-prefix strip — when the model pasted a numbered `read_file`\n * chunk verbatim into `old_string` and the file carries no such prefix.\n * 6. Combined: line-number strip + quote normalization — paste-back of a\n * numbered chunk against a file whose typography differs from the model's.\n *\n * Returns `{ actual, occurrences }` — `actual` is the string that exists in\n * the file (use this to do the actual replace; preserves the file's\n * typography). `occurrences` is the count of those matches in the file.\n *\n * Returns `null` when no recovery worked.\n */\nexport interface ResolvedMatch {\n actual: string\n occurrences: number\n /** Recovery path — `'exact'` when no transformation was applied. */\n via: 'exact' | 'quotes' | 'desanitize' | 'quotes+desanitize' | 'line-numbers' | 'quotes+line-numbers'\n}\n\n/**\n * Search `target` in `normFile` and slice the matching span out of the\n * original `haystack`, counting all non-overlapping occurrences. `normFile`\n * is the haystack with whatever transform (quotes / desanitize / combined)\n * was applied to make the indices align — slicing the original haystack\n * preserves the file's actual typography so `replace_all` writes back the\n * file's form, not the model's.\n *\n * Pre-condition: `normFile.length === haystack.length` (every transform\n * we use is one-to-one). Returns null on miss.\n */\nfunction locateAndCount(\n haystack: string,\n normFile: string,\n target: string,\n via: ResolvedMatch['via'],\n): ResolvedMatch | null {\n const idx = normFile.indexOf(target)\n if (idx === -1)\n return null\n const actual = haystack.slice(idx, idx + target.length)\n let occ = 0\n let cursor = 0\n while (true) {\n const next = normFile.indexOf(target, cursor)\n if (next === -1)\n break\n occ++\n cursor = next + target.length\n }\n return { actual, occurrences: occ, via }\n}\n\nexport function resolveOldString(haystack: string, needle: string): ResolvedMatch | null {\n // 1. Exact match — happy path.\n const exact = countExactMatches(haystack, needle)\n if (exact > 0)\n return { actual: needle, occurrences: exact, via: 'exact' }\n\n // 2. Curly-quote normalization. Either side can carry curly quotes:\n // model emitted straight + file has curly, OR model emitted curly +\n // file has straight. Normalize both and look there. Slice the original\n // haystack to recover the actual file-side typography.\n const normNeedle = normalizeQuotes(needle)\n const normFile = normalizeQuotes(haystack)\n if (normNeedle !== needle || normFile !== haystack) {\n const m = locateAndCount(haystack, normFile, normNeedle, 'quotes')\n if (m)\n return m\n }\n\n // 3. Desanitize the needle — model-side substitution undo (`<n>` → `<name>`,\n // etc.) The file always has the unsanitized form; only the model emits\n // the abbreviated version.\n const desan = desanitize(needle)\n if (desan !== needle) {\n const desanCount = countExactMatches(haystack, desan)\n if (desanCount > 0)\n return { actual: desan, occurrences: desanCount, via: 'desanitize' }\n }\n\n // 4. Combined: desanitize + quote normalization. Hit when the model\n // emitted both sanitized tokens and straight quotes, but the file has\n // the unsanitized form with curly quotes.\n const combo = desanitize(normNeedle)\n if (combo !== needle) {\n const m = locateAndCount(haystack, normFile, combo, 'quotes+desanitize')\n if (m)\n return m\n }\n\n // 5. Line-number-prefix strip. When `read_file` returns line-numbered\n // output and the model pasted the chunk verbatim into `old_string`,\n // the on-disk file doesn't carry those prefixes. Strip them and\n // retry; the file-side `actual` is the prefix-free needle so the\n // replacement lands on real bytes.\n //\n // Guard against a needle that strips down to whitespace-only (e.g.\n // `1\\t\\n2\\t\\n3\\t` → `\\n\\n`). Searching for `\\n\\n` would match arbitrary\n // blank-line patterns anywhere in the file — a high false-positive risk.\n // Require the stripped needle to carry at least one non-whitespace\n // character before we trust the result.\n const stripped = stripLineNumberPrefixes(needle)\n if (stripped !== needle && stripped.trim().length > 0) {\n const count = countExactMatches(haystack, stripped)\n if (count > 0)\n return { actual: stripped, occurrences: count, via: 'line-numbers' }\n\n // 6. Combined: line-number strip + curly-quote normalization. The\n // typography mismatch may live in the file, the needle, or both.\n const strippedNorm = normalizeQuotes(stripped)\n if (strippedNorm !== stripped || normFile !== haystack) {\n const m = locateAndCount(haystack, normFile, strippedNorm, 'quotes+line-numbers')\n if (m)\n return m\n }\n }\n\n return null\n}\n\n/**\n * Apply the same recovery transforms used to find `old_string` to\n * `new_string`, so the file gets back its native form: desanitize when\n * the model emitted `<n>` for `<name>`, strip line-number prefixes when\n * the match required them, then re-curlify when the match required\n * quote normalization. Shared between `edit` and `multi_edit`.\n */\nexport function styleReplacementForVia(\n replacement: string,\n via: ResolvedMatch['via'],\n actual: string,\n): string {\n let out = replacement\n if (via === 'desanitize' || via === 'quotes+desanitize')\n out = desanitize(out)\n if (via === 'line-numbers' || via === 'quotes+line-numbers')\n out = stripLineNumberPrefixes(out)\n if (via === 'quotes' || via === 'quotes+desanitize' || via === 'quotes+line-numbers')\n out = preserveQuoteStyle(actual, out)\n return out\n}\n\n/**\n * When `old_string` matched via curly-quote normalization, re-style\n * `new_string` so the file's typography is preserved across the edit.\n * Detects whether the matched file region had curly singles, doubles, or\n * both, and applies the matching curlification to the replacement.\n *\n * Apostrophes in contractions (`don't`, `it's`) get the right-single curly\n * quote regardless of opening context — that's the canonical typographer's\n * convention for English. Other quotes use a simple\n * preceded-by-whitespace-or-opening-punctuation heuristic.\n */\nexport function preserveQuoteStyle(actual: string, replacement: string): string {\n const hasDouble = actual.includes(LEFT_DOUBLE_CURLY_QUOTE) || actual.includes(RIGHT_DOUBLE_CURLY_QUOTE)\n const hasSingle = actual.includes(LEFT_SINGLE_CURLY_QUOTE) || actual.includes(RIGHT_SINGLE_CURLY_QUOTE)\n if (!hasDouble && !hasSingle)\n return replacement\n\n let out = replacement\n if (hasDouble)\n out = applyCurly(out, '\"', LEFT_DOUBLE_CURLY_QUOTE, RIGHT_DOUBLE_CURLY_QUOTE, false)\n if (hasSingle)\n out = applyCurly(out, '\\'', LEFT_SINGLE_CURLY_QUOTE, RIGHT_SINGLE_CURLY_QUOTE, true)\n return out\n}\n\nfunction applyCurly(\n s: string,\n straight: string,\n left: string,\n right: string,\n contractionAware: boolean,\n): string {\n const chars = [...s]\n const result: string[] = []\n for (let i = 0; i < chars.length; i++) {\n if (chars[i] !== straight) {\n result.push(chars[i])\n continue\n }\n if (contractionAware) {\n const prev = i > 0 ? chars[i - 1] : ''\n const next = i < chars.length - 1 ? chars[i + 1] : ''\n // Letter-quote-letter is a contraction, not a quote — always right.\n if (/\\p{L}/u.test(prev) && /\\p{L}/u.test(next)) {\n result.push(right)\n continue\n }\n }\n result.push(isOpeningContext(chars, i) ? left : right)\n }\n return result.join('')\n}\n\nfunction isOpeningContext(chars: string[], i: number): boolean {\n if (i === 0)\n return true\n const prev = chars[i - 1]\n return prev === ' ' || prev === '\\t' || prev === '\\n' || prev === '\\r'\n || prev === '(' || prev === '[' || prev === '{'\n || prev === '\\u2014' || prev === '\\u2013' // em / en dash\n}\n","/**\n * Path-suggestion helper for file-not-found errors.\n *\n * When `read_file` / `edit` / `multi_edit` get a missing-file error, walk the\n * parent directory in the agent's execution context for files sharing the\n * same basename (sans extension) — common cause: model picked the wrong\n * extension (`.js` vs `.ts`, `.md` vs `.mdx`). Returns the closest sibling\n * filename so the tool can append `Did you mean X?` to the error.\n *\n * Mirrors `claude-code/utils/file.ts` `findSimilarFile`. Goes through the\n * `ExecutionContext.listFiles` seam so it works in process / docker / sandbox.\n */\n\nimport type { ExecutionContext, ExecutionHandle } from '../contexts'\n\n/**\n * Find a sibling file in the same directory sharing `path`'s basename\n * (sans extension), excluding the missing path itself. Returns just the\n * filename (not the full path) when found, otherwise `null`.\n *\n * Silent on errors — a missing parent directory or a `listFiles` failure\n * means we have no suggestion, not that anything is wrong.\n */\nexport async function findSimilarFile(\n execution: ExecutionContext,\n handle: ExecutionHandle,\n path: string,\n): Promise<string | null> {\n const slash = path.lastIndexOf('/')\n const dir = slash === -1 ? '.' : (path.slice(0, slash) || '/')\n const target = slash === -1 ? path : path.slice(slash + 1)\n const dot = target.lastIndexOf('.')\n const targetBase = dot === -1 ? target : target.slice(0, dot)\n\n if (targetBase.length === 0)\n return null\n\n let entries: string[]\n try {\n entries = await execution.listFiles(handle, dir)\n }\n catch {\n return null\n }\n\n for (const entry of entries) {\n if (entry === target)\n continue\n const entryDot = entry.lastIndexOf('.')\n const entryBase = entryDot === -1 ? entry : entry.slice(0, entryDot)\n if (entryBase === targetBase)\n return entry\n }\n return null\n}\n\n/**\n * Format a `Did you mean X?` suffix for missing-file errors. Returns an empty\n * string when no suggestion is available so callers can string-concat\n * unconditionally.\n */\nexport async function suggestionFor(\n execution: ExecutionContext,\n handle: ExecutionHandle,\n path: string,\n): Promise<string> {\n const sibling = await findSimilarFile(execution, handle, path)\n return sibling ? ` Did you mean ${sibling}?` : ''\n}\n","import type { ToolContext, ToolDef } from './types'\nimport { resolveOldString, stripLineNumberPrefixes, styleReplacementForVia } from './edit-utils'\nimport { suggestionFor } from './path-suggest'\nimport { getReadState, hashContent } from './read-state'\n\n/**\n * Surgical edit — replace `old_string` with `new_string` in a single file.\n *\n * Mirrors Claude Code's `Edit` semantics so models post-trained on Anthropic's\n * tool surface need no relearning. Fails clearly when `old_string` isn't unique\n * (unless `replace_all: true`) and when not found, with a nearest-match preview\n * so the model can recover without a separate `read_file` round-trip.\n */\n\nexport const edit: ToolDef = {\n spec: {\n name: 'edit',\n description: 'Replace exact `old_string` with `new_string` in a file. Fails if `old_string` is not unique unless `replace_all: true`. Prefer over `write_file` for surgical changes — preserves the rest of the file. Tolerates `read_file` line-number prefixes (`<N>\\\\t…`, `<N>|…`, or `<N>→…`) in `old_string` / `new_string` — they are stripped before matching/writing, so you can paste a numbered chunk verbatim.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Relative file path.' },\n old_string: { type: 'string', description: 'Exact substring to find.' },\n new_string: { type: 'string', description: 'Replacement substring.' },\n replace_all: { type: 'boolean', description: 'Replace every occurrence. Default: false.' },\n },\n required: ['path', 'old_string', 'new_string'],\n },\n },\n async execute({ path, old_string, new_string, replace_all }, ctx: ToolContext) {\n const target = path as string\n const find = old_string as string\n const replacement = new_string as string\n const replaceAll = replace_all === true\n\n if (find === replacement)\n return `Edit error: old_string and new_string are identical — nothing to change in ${target}.`\n\n if (find.length === 0)\n return `Edit error: old_string is empty. Use write_file to create or fully overwrite a file.`\n\n let original: string\n try {\n original = await ctx.execution.readFile(ctx.handle, target)\n }\n catch {\n const hint = await suggestionFor(ctx.execution, ctx.handle, target)\n return `Edit error: file not found: ${target}.${hint}`\n }\n\n // Read-before-edit guard. When `behavior.requireReadBeforeEdit` is on and\n // the agent has a session, refuse edits against files the model hasn't\n // read this session, and against files whose on-disk content has drifted\n // from what the model last saw — both produce silent corruption when an\n // edit applies a substring against bytes the model \"remembers\" but no\n // longer reflect reality.\n if (ctx.behavior?.requireReadBeforeEdit && ctx.session) {\n const readState = getReadState(ctx.session)\n const absKey = `${ctx.handle.cwd}::${target}`\n const prior = readState?.get(absKey)\n if (!prior)\n return `Edit error: ${target} has not been read in this session. Call read_file first so the edit applies against the current contents.`\n if (prior.contentHash !== hashContent(original))\n return `Edit error: ${target} has changed on disk since the last read. Re-read the file before editing.`\n }\n\n // Resolve `old_string` against the file content with the recovery\n // cascade in `resolveOldString` (exact → quotes → desanitize → combined\n // → line-number-strip → strip+quotes). On a non-exact hit, `match.actual`\n // is the file-side substring (preserves the file's typography) and the\n // replacement is re-styled below to match.\n const match = resolveOldString(original, find)\n\n if (!match) {\n const preview = nearestMatchPreview(original, find)\n return preview\n ? `Edit error: old_string not found in ${target}. Closest match in the file: ${preview}`\n : `Edit error: old_string not found in ${target}.`\n }\n\n const { actual, occurrences, via } = match\n\n if (occurrences > 1 && !replaceAll)\n return `Edit error: old_string appears ${occurrences} times in ${target}. Pass replace_all=true or expand old_string for uniqueness.`\n\n const styledReplacement = styleReplacementForVia(replacement, via, actual)\n\n const updated = replaceAll\n ? original.split(actual).join(styledReplacement)\n : original.replace(actual, styledReplacement)\n\n if (updated === original)\n return `Edit error: replacement produced no change in ${target}.`\n\n await ctx.execution.writeFile(ctx.handle, target, updated)\n\n // Keep read-state coherent — after a successful edit, the model knows the\n // post-edit content (it produced new_string), so we record the new hash\n // against the same slice. This lets a chain of edits proceed without\n // re-reading between each one even with `requireReadBeforeEdit` on.\n if (ctx.session) {\n const readState = getReadState(ctx.session)\n const absKey = `${ctx.handle.cwd}::${target}`\n const prior = readState?.get(absKey)\n if (readState && prior) {\n readState.set(absKey, { ...prior, contentHash: hashContent(updated), mtimeMs: Date.now() })\n }\n }\n\n return `Edited ${target}: replaced ${occurrences} occurrence${occurrences === 1 ? '' : 's'}.`\n },\n}\n\n/**\n * Find the line that shares the longest common prefix with the needle's first\n * line. Cheap heuristic — better than nothing for the common \"model has a typo\"\n * case (off-by-one indent, trailing whitespace, escape mismatch).\n *\n * Returns a \"line N: <preview>\" snippet or null when no line shares a useful\n * prefix. Strips line-number prefixes from the needle first so a model that\n * pasted a numbered `read_file` chunk verbatim still gets a useful diagnostic.\n */\nfunction nearestMatchPreview(haystack: string, needle: string): string | null {\n // If the model included `<N>\\t` (or `<N>|` / `<N>→`) prefixes from a\n // numbered read, strip them before scoring — otherwise the prefix\n // dominates and we never match real file lines.\n const normalizedNeedle = stripLineNumberPrefixes(needle)\n const needleFirstLine = normalizedNeedle.split('\\n')[0]\n if (needleFirstLine.length < 3)\n return null\n\n const lines = haystack.split('\\n')\n let bestScore = 0\n let bestIdx = -1\n for (let i = 0; i < lines.length; i++) {\n const score = sharedPrefixLength(lines[i], needleFirstLine)\n if (score > bestScore) {\n bestScore = score\n bestIdx = i\n }\n }\n if (bestIdx < 0 || bestScore < Math.min(8, Math.floor(needleFirstLine.length / 2)))\n return null\n\n const snippet = lines[bestIdx].slice(0, 80)\n return `line ${bestIdx + 1}: ${JSON.stringify(snippet)}`\n}\n\nfunction sharedPrefixLength(a: string, b: string): number {\n const max = Math.min(a.length, b.length)\n let i = 0\n while (i < max && a.charCodeAt(i) === b.charCodeAt(i))\n i++\n return i\n}\n","import type { ToolContext, ToolDef } from './types'\nimport { stat } from 'node:fs/promises'\nimport { resolve } from 'node:path'\n\n/**\n * Glob-pattern file matching.\n *\n * Uses Bun's native `Bun.Glob` engine when running in the in-process execution\n * context. For non-process contexts (docker, sandbox), falls back to running\n * the pattern through a shell `find` invocation so the match is executed\n * wherever the context lives.\n *\n * Results are capped at 1000 entries to keep model input bounded.\n *\n * By default each row carries `<path>\\t<size>\\t<mtime>` metadata so the\n * model can rank \"what changed recently\" without a follow-up `read_file`.\n * Pass `metadata: false` to fall back to plain newline-separated paths.\n * Metadata is best-effort: in-process contexts use `node:fs/promises stat`\n * (parallelized); non-process contexts fall through to the path-only shape\n * since shelling out per file would dominate the call latency.\n */\nconst DEFAULT_LIMIT = 1000\n\n// Only allow characters that are meaningful in glob patterns plus path/name chars.\n// Anything else (quotes, backticks, $, ;, |, <, >, spaces-in-weird-places, etc.) is\n// rejected so the shell fallback can't be hijacked via a crafted `pattern`.\nconst SAFE_GLOB_PATTERN_RE = /^[\\w./*?[\\]{}!,^@+-]+$/\n\nasync function globInProcess(pattern: string, cwd: string, limit: number): Promise<string[]> {\n // Bun.Glob is available in Bun runtime; the agent targets Bun so this is safe.\n const glob = new Bun.Glob(pattern)\n const results: string[] = []\n for await (const file of glob.scan({ cwd })) {\n results.push(file)\n if (results.length >= limit)\n break\n }\n return results.sort()\n}\n\nasync function globViaShell(pattern: string, ctx: ToolContext, limit: number): Promise<string[]> {\n // Reject any characters that could break out of the single-quoted arg. With the\n // allowlist above, pattern is guaranteed shell-safe when single-quoted.\n if (!SAFE_GLOB_PATTERN_RE.test(pattern))\n throw new Error('Glob pattern contains unsupported characters (shell fallback only allows path/glob metacharacters)')\n\n // `find -path`'s `*` matches any character — including `/` — so `**` and `*` are\n // effectively equivalent. Using the user pattern verbatim keeps semantics close to\n // Bun.Glob for recursive matches. `find -name` (no slash in pattern) matches basenames.\n const useBasename = !pattern.includes('/')\n const finder = useBasename\n ? `find . -type f -name '${pattern}'`\n : `find . -type f -path './${pattern}'`\n const searchCmd = `${finder} 2>/dev/null | sed 's|^./||' | sort | head -n ${limit}`\n const result = await ctx.execution.exec(ctx.handle, searchCmd)\n if (result.exitCode !== 0 && !result.stdout)\n return []\n return result.stdout.split('\\n').filter(line => line.length > 0)\n}\n\nexport const glob: ToolDef = {\n spec: {\n name: 'glob',\n description: 'Match files by glob pattern (supports **, *, ?). Relative to the execution context cwd. By default each row is `<path>\\\\t<size-bytes>\\\\t<mtime-iso>`; set `metadata: false` for a plain newline-separated list of paths. Always sorted.',\n inputSchema: {\n type: 'object',\n properties: {\n pattern: {\n type: 'string',\n description: 'Glob pattern (e.g. \"src/**/*.ts\", \"*.md\", \"test/**/fixtures/*\").',\n },\n limit: {\n type: 'number',\n description: `Maximum number of matches to return. Default: ${DEFAULT_LIMIT}.`,\n },\n metadata: {\n type: 'boolean',\n description: 'Append size (bytes) and mtime (ISO) per row, tab-separated. Default: true. In-process only — non-process execution contexts always return paths.',\n },\n },\n required: ['pattern'],\n },\n },\n async execute({ pattern, limit, metadata }, ctx: ToolContext) {\n const pat = pattern as string\n const max = typeof limit === 'number' && limit > 0 ? limit : DEFAULT_LIMIT\n const wantMetadata = metadata !== false\n\n try {\n const entries = ctx.execution.type === 'process'\n ? await globInProcess(pat, ctx.handle.cwd, max)\n : await globViaShell(pat, ctx, max)\n if (entries.length === 0)\n return '(no matches)'\n\n // Metadata only makes sense in-process — shelling out per file would\n // dominate latency for large match sets, and `find -printf` is\n // GNU-only. Non-process contexts return paths only.\n if (!wantMetadata || ctx.execution.type !== 'process')\n return entries.join('\\n')\n\n const rows = await Promise.all(entries.map(async (rel) => {\n try {\n const s = await stat(resolve(ctx.handle.cwd, rel))\n return `${rel}\\t${s.size}\\t${new Date(s.mtimeMs).toISOString()}`\n }\n catch {\n // Stat failure (race with deletion, perms) — emit path with\n // empty columns so the row count still matches.\n return `${rel}\\t\\t`\n }\n }))\n return rows.join('\\n')\n }\n catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n return `Glob error: ${message}`\n }\n },\n}\n","import type { ToolContext, ToolDef } from './types'\nimport { shellQuote } from './shell-quote'\n\n/**\n * Search file contents by regex.\n *\n * Wraps ripgrep (`rg`) when available, falls back to an in-process Bun.Glob +\n * regex implementation when running in the in-process execution context. For\n * non-process contexts without `rg`, returns a clear hint rather than silently\n * doing nothing.\n *\n * The tool surface mirrors Claude Code's `Grep` so models authored against the\n * Anthropic tool surface need no relearning. Output modes:\n * - `files_with_matches` (default) — newline-separated paths.\n * - `content` — `path:line:match` (line numbers on by default).\n * - `count` — `path:N` per matching file.\n *\n * Results are capped via `head_limit` (default 250) to keep model input\n * bounded; `offset` lets the caller page through.\n */\n\nconst DEFAULT_HEAD_LIMIT = 250\nconst DEFAULT_OUTPUT_MODE: OutputMode = 'files_with_matches'\n\ntype OutputMode = 'content' | 'files_with_matches' | 'count'\n\ninterface GrepInput {\n 'pattern': string\n 'path'?: string\n 'glob'?: string\n 'type'?: string\n 'output_mode'?: OutputMode\n '-i'?: boolean\n '-n'?: boolean\n '-A'?: number\n '-B'?: number\n '-C'?: number\n 'multiline'?: boolean\n 'head_limit'?: number\n 'offset'?: number\n}\n\nexport const grep: ToolDef = {\n spec: {\n name: 'grep',\n description: 'Search file contents by regex. Returns matching paths (default), match content, or per-file counts. Backed by ripgrep when available with a Bun.Glob fallback for in-process runs.',\n inputSchema: {\n type: 'object',\n properties: {\n 'pattern': { type: 'string', description: 'Regex (PCRE-flavored via ripgrep, JS regex via fallback).' },\n 'path': { type: 'string', description: 'File or directory to search. Default: \".\".' },\n 'glob': { type: 'string', description: 'Restrict to files matching this glob, e.g. \"**/*.ts\".' },\n 'type': { type: 'string', description: 'rg file type filter, e.g. \"ts\", \"py\", \"rust\". Ignored by the fallback.' },\n 'output_mode': { type: 'string', enum: ['content', 'files_with_matches', 'count'], description: 'Default: \"files_with_matches\".' },\n '-i': { type: 'boolean', description: 'Case-insensitive match.' },\n '-n': { type: 'boolean', description: 'Show line numbers (content mode). Default: true.' },\n '-A': { type: 'integer', description: 'Lines of trailing context (content mode).' },\n '-B': { type: 'integer', description: 'Lines of leading context (content mode).' },\n '-C': { type: 'integer', description: 'Lines of surrounding context (content mode). Overridden by -A/-B if set.' },\n 'multiline': { type: 'boolean', description: 'Allow patterns to match across line boundaries.' },\n 'head_limit': { type: 'integer', description: 'Cap output entries. Default: 250. Set 0 for unlimited.' },\n 'offset': { type: 'integer', description: 'Skip first N entries. Default: 0.' },\n },\n required: ['pattern'],\n },\n },\n async execute(rawInput, ctx: ToolContext) {\n const input = rawInput as unknown as GrepInput\n\n const useRg = await isRipgrepAvailable(ctx)\n if (useRg)\n return runViaRipgrep(input, ctx)\n\n if (ctx.execution.type === 'process')\n return runInProcess(input, ctx)\n\n return 'grep error: ripgrep is not available in the execution context. Install `rg` or use the `shell` tool with grep/awk.'\n },\n}\n\n// ---------------------------------------------------------------------------\n// ripgrep path\n// ---------------------------------------------------------------------------\n\n/**\n * Probe ripgrep availability **per call**. The probe is intentionally not\n * cached: caching at module scope would leak across execution contexts (an\n * orchestrator running an in-process agent and a docker agent in the same\n * Node process must be able to differ on whether `rg` exists), and caching\n * per handle adds bookkeeping for negligible savings — `rg --version` is\n * ~5 ms, and grep is invoked at most a few times per turn.\n */\nasync function isRipgrepAvailable(ctx: ToolContext): Promise<boolean> {\n const result = await ctx.execution.exec(ctx.handle, 'rg --version')\n return result.exitCode === 0\n}\n\nasync function runViaRipgrep(input: GrepInput, ctx: ToolContext): Promise<string> {\n const args = ['rg']\n const mode = (input.output_mode ?? DEFAULT_OUTPUT_MODE) as OutputMode\n\n if (mode === 'files_with_matches')\n args.push('--files-with-matches')\n else if (mode === 'count')\n args.push('--count')\n else\n args.push((input['-n'] ?? true) ? '--line-number' : '--no-line-number')\n\n if (input['-i'])\n args.push('-i')\n\n if (mode === 'content') {\n if (typeof input['-A'] === 'number')\n args.push('-A', String(input['-A']))\n if (typeof input['-B'] === 'number')\n args.push('-B', String(input['-B']))\n if (typeof input['-C'] === 'number' && typeof input['-A'] !== 'number' && typeof input['-B'] !== 'number')\n args.push('-C', String(input['-C']))\n }\n\n if (input.multiline)\n args.push('--multiline', '--multiline-dotall')\n\n if (input.glob)\n args.push('--glob', input.glob)\n\n if (input.type)\n args.push('--type', input.type)\n\n args.push('--', input.pattern)\n\n // Always pass a path — rg reads from stdin when invoked from a non-TTY child\n // process without a path argument, which hangs forever waiting for input.\n args.push(input.path ?? '.')\n\n const command = args.map(shellQuote).join(' ')\n const result = await ctx.execution.exec(ctx.handle, command)\n\n // ripgrep exits 1 when there are no matches — that's not an error here.\n if (result.exitCode !== 0 && result.exitCode !== 1) {\n return `grep error: ${result.stderr.trim() || `rg exited with code ${result.exitCode}`}`\n }\n\n return formatPaginated(result.stdout, input)\n}\n\n// ---------------------------------------------------------------------------\n// In-process fallback (Bun.Glob + readFile + regex)\n// ---------------------------------------------------------------------------\n\nasync function runInProcess(input: GrepInput, ctx: ToolContext): Promise<string> {\n const mode = (input.output_mode ?? DEFAULT_OUTPUT_MODE) as OutputMode\n const flags = `${input['-i'] ? 'i' : ''}${input.multiline ? 's' : ''}${mode !== 'content' ? '' : 'g'}`\n\n let regex: RegExp\n try {\n regex = new RegExp(input.pattern, flags || undefined)\n }\n catch (err) {\n return `grep error: invalid regex: ${(err as Error).message}`\n }\n\n const files = await enumerateFiles(input, ctx)\n const showLineNumbers = input['-n'] ?? true\n const before = (input['-B'] ?? input['-C'] ?? 0)\n const after = (input['-A'] ?? input['-C'] ?? 0)\n\n const lines: string[] = []\n for (const path of files) {\n let content: string\n try {\n content = await ctx.execution.readFile(ctx.handle, path)\n }\n catch {\n continue\n }\n if (input.multiline) {\n // Multiline mode: scan the whole buffer with /g semantics.\n const allMatches = [...content.matchAll(new RegExp(regex.source, `${flags.replace(/g/, '')}g`))]\n if (allMatches.length === 0)\n continue\n if (mode === 'files_with_matches') {\n lines.push(path)\n continue\n }\n if (mode === 'count') {\n lines.push(`${path}:${allMatches.length}`)\n continue\n }\n // content mode — emit each match's surrounding line context.\n for (const m of allMatches) {\n const lineStart = content.lastIndexOf('\\n', m.index! - 1) + 1\n const lineEnd = content.indexOf('\\n', m.index!)\n const snippet = content.slice(lineStart, lineEnd === -1 ? undefined : lineEnd)\n const lineNo = content.slice(0, m.index!).split('\\n').length\n lines.push(formatContentLine(path, lineNo, snippet, showLineNumbers))\n }\n continue\n }\n\n const fileLines = content.split('\\n')\n const matched: number[] = []\n for (let i = 0; i < fileLines.length; i++) {\n regex.lastIndex = 0\n if (regex.test(fileLines[i]))\n matched.push(i)\n }\n if (matched.length === 0)\n continue\n\n if (mode === 'files_with_matches') {\n lines.push(path)\n continue\n }\n if (mode === 'count') {\n lines.push(`${path}:${matched.length}`)\n continue\n }\n\n const includeLineNos = new Set<number>()\n for (const m of matched) {\n for (let i = Math.max(0, m - before); i <= Math.min(fileLines.length - 1, m + after); i++)\n includeLineNos.add(i)\n }\n const sorted = [...includeLineNos].sort((a, b) => a - b)\n let prev = -2\n for (const lineNo of sorted) {\n if (lineNo > prev + 1 && lines.length > 0)\n lines.push('--')\n const snippet = fileLines[lineNo]\n lines.push(formatContentLine(path, lineNo + 1, snippet, showLineNumbers))\n prev = lineNo\n }\n }\n\n return formatPaginated(lines.join('\\n'), input)\n}\n\nfunction formatContentLine(path: string, lineNo: number, snippet: string, showLineNumbers: boolean): string {\n return showLineNumbers ? `${path}:${lineNo}:${snippet}` : `${path}:${snippet}`\n}\n\nasync function enumerateFiles(input: GrepInput, ctx: ToolContext): Promise<string[]> {\n const cwd = ctx.handle.cwd\n const root = input.path ?? '.'\n\n // If `path` is a single file, just return it.\n // Cheap heuristic: contains a dot in the basename and no glob wildcards.\n if (input.path && !input.path.includes('*') && !input.path.includes('?')) {\n try {\n const stat = await ctx.execution.exec(ctx.handle, `test -f ${shellQuote(input.path)} && echo file || echo dir`)\n if (stat.stdout.trim() === 'file')\n return [input.path]\n }\n catch { /* fall through to glob enumeration */ }\n }\n\n const pattern = input.glob ?? '**/*'\n const glob = new Bun.Glob(pattern)\n const out: string[] = []\n const scanRoot = root === '.' ? cwd : `${cwd.replace(/\\/$/, '')}/${root.replace(/^\\.\\//, '')}`\n for await (const file of glob.scan({ cwd: scanRoot, onlyFiles: true })) {\n out.push(root === '.' ? file : `${root.replace(/\\/$/, '')}/${file}`)\n }\n return out.sort()\n}\n\nfunction formatPaginated(text: string, input: GrepInput): string {\n const headLimit = typeof input.head_limit === 'number' && input.head_limit >= 0\n ? input.head_limit\n : DEFAULT_HEAD_LIMIT\n const offset = typeof input.offset === 'number' && input.offset > 0\n ? Math.floor(input.offset)\n : 0\n\n if (!text.trim())\n return '(no matches)'\n\n const lines = text.split('\\n').filter(l => l.length > 0)\n const total = lines.length\n\n const sliced = headLimit === 0\n ? lines.slice(offset)\n : lines.slice(offset, offset + headLimit)\n\n if (sliced.length === 0)\n return '(no matches in this slice)'\n\n const truncatedHead = offset > 0\n const truncatedTail = headLimit > 0 && offset + headLimit < total\n\n let out = sliced.join('\\n')\n if (truncatedHead)\n out = `…(${offset} earlier matches skipped)…\\n${out}`\n if (truncatedTail)\n out = `${out}\\n…(${total - offset - headLimit} more matches; re-run with offset=${offset + headLimit} or larger head_limit)`\n return out\n}\n","/**\n * Interaction tool — lets the agent request structured input from the outside world.\n *\n * Not included in any preset by default. Add it explicitly:\n *\n * import { createInteractionTool } from 'zidane'\n *\n * const askUser = createInteractionTool({\n * schema: { type: 'object', properties: { question: { type: 'string' } }, required: ['question'] },\n * onRequest: async (payload) => {\n * const answer = await promptUser(payload.question)\n * return { answer }\n * },\n * })\n *\n * const preset = definePreset({ name: 'interactive', tools: { ...basicTools, ask_user: askUser } })\n */\n\nimport type { ToolContext, ToolDef } from './types'\n\nexport interface InteractionToolOptions {\n /** JSON Schema for the request payload the model sends */\n schema: Record<string, unknown>\n /** Tool name (default: 'interaction') */\n name?: string\n /** Tool description shown to the model */\n description?: string\n /** Called when the model invokes this tool. Receives the validated payload and tool context, returns data for the model. */\n onRequest: (payload: Record<string, unknown>, ctx: ToolContext) => Promise<Record<string, unknown> | string>\n}\n\n/**\n * Create an interaction tool that lets the agent request structured input.\n *\n * The model calls this tool with a payload matching the schema.\n * `onRequest` is called with the payload and should return the response\n * (string or object) that gets sent back to the model as the tool result.\n */\nexport function createInteractionTool(options: InteractionToolOptions): ToolDef {\n const name = options.name ?? 'interaction'\n const description = options.description ?? 'Request structured input from the user or external system.'\n\n return {\n spec: {\n name,\n description,\n inputSchema: options.schema,\n },\n async execute(input, ctx) {\n const result = await options.onRequest(input, ctx)\n\n return typeof result === 'string' ? result : JSON.stringify(result)\n },\n }\n}\n","import type { ToolContext, ToolDef } from './types'\n\nexport const listFiles: ToolDef = {\n spec: {\n name: 'list_files',\n description: 'List files and directories at the given path (relative to project root).',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Relative directory path (default: \".\")' },\n },\n required: [],\n },\n },\n async execute({ path }, ctx: ToolContext) {\n try {\n const entries = await ctx.execution.listFiles(ctx.handle, (path as string) || '.')\n return entries.join('\\n') || '(empty directory)'\n }\n catch {\n return `Directory not found: ${path}`\n }\n },\n}\n","import type { ToolContext, ToolDef } from './types'\nimport { resolveOldString, styleReplacementForVia } from './edit-utils'\nimport { suggestionFor } from './path-suggest'\nimport { getReadState, hashContent } from './read-state'\n\n/**\n * Atomic multi-edit on a single file.\n *\n * Apply a list of edits in order. Each edit replaces `old_string` with\n * `new_string` against the file contents *as left by the previous edit* (not\n * the original on-disk content). All-or-nothing — if any edit fails (empty\n * `old_string`, not found, ambiguous match without `replace_all`), the whole\n * call rejects and the file is not written.\n *\n * Mirrors Claude Code's `MultiEdit` semantics so models authored against the\n * Anthropic tool surface work without retraining.\n */\n\ninterface EditStep {\n old_string: string\n new_string: string\n replace_all?: boolean\n}\n\nexport const multiEdit: ToolDef = {\n spec: {\n name: 'multi_edit',\n description: 'Apply a sequential list of edits to a file atomically. Each edit operates on the result of the previous edit. All edits must succeed for any to be written. Prefer this over multiple `edit` calls when several non-overlapping changes are needed in the same file. Each step tolerates `read_file` line-number prefixes (`<N>\\\\t…`, `<N>|…`, or `<N>→…`) in `old_string` / `new_string`.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Relative file path.' },\n edits: {\n type: 'array',\n description: 'List of edits applied in order; each operates on the previous edit\\'s output.',\n items: {\n type: 'object',\n properties: {\n old_string: { type: 'string' },\n new_string: { type: 'string' },\n replace_all: { type: 'boolean' },\n },\n required: ['old_string', 'new_string'],\n },\n },\n },\n required: ['path', 'edits'],\n },\n },\n async execute({ path, edits }, ctx: ToolContext) {\n const target = path as string\n const steps = edits as EditStep[]\n\n if (!Array.isArray(steps) || steps.length === 0)\n return `multi_edit error: edits must be a non-empty array.`\n\n let current: string\n try {\n current = await ctx.execution.readFile(ctx.handle, target)\n }\n catch {\n const hint = await suggestionFor(ctx.execution, ctx.handle, target)\n return `multi_edit error: file not found: ${target}.${hint}`\n }\n\n // Read-before-edit guard — see edit.ts for rationale. Same logic applies\n // here: refuse when the file hasn't been read or has drifted.\n if (ctx.behavior?.requireReadBeforeEdit && ctx.session) {\n const readState = getReadState(ctx.session)\n const absKey = `${ctx.handle.cwd}::${target}`\n const prior = readState?.get(absKey)\n if (!prior)\n return `multi_edit error: ${target} has not been read in this session. Call read_file first so the edits apply against the current contents.`\n if (prior.contentHash !== hashContent(current))\n return `multi_edit error: ${target} has changed on disk since the last read. Re-read the file before editing.`\n }\n\n let applied = 0\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i]\n const find = step.old_string\n const replacement = step.new_string\n const replaceAll = step.replace_all === true\n\n if (typeof find !== 'string' || typeof replacement !== 'string')\n return `multi_edit error: edit #${i + 1} is missing old_string or new_string.`\n\n if (find.length === 0)\n return `multi_edit error: edit #${i + 1} has empty old_string. Use write_file to fully replace a file.`\n\n if (find === replacement)\n return `multi_edit error: edit #${i + 1} old_string and new_string are identical.`\n\n const match = resolveOldString(current, find)\n if (!match)\n return `multi_edit error: edit #${i + 1} old_string not found in ${target}.`\n\n const { actual, occurrences, via } = match\n if (occurrences > 1 && !replaceAll)\n return `multi_edit error: edit #${i + 1} old_string appears ${occurrences} times. Pass replace_all=true on this edit or expand old_string for uniqueness.`\n\n const styledReplacement = styleReplacementForVia(replacement, via, actual)\n\n current = replaceAll\n ? current.split(actual).join(styledReplacement)\n : current.replace(actual, styledReplacement)\n applied += occurrences\n }\n\n await ctx.execution.writeFile(ctx.handle, target, current)\n\n // Keep read-state coherent after a successful multi-edit — see edit.ts.\n if (ctx.session) {\n const readState = getReadState(ctx.session)\n const absKey = `${ctx.handle.cwd}::${target}`\n const prior = readState?.get(absKey)\n if (readState && prior) {\n readState.set(absKey, { ...prior, contentHash: hashContent(current), mtimeMs: Date.now() })\n }\n }\n\n return `Edited ${target}: applied ${steps.length} edit${steps.length === 1 ? '' : 's'} (${applied} replacement${applied === 1 ? '' : 's'}).`\n },\n}\n","/**\n * Binary-aware file read for the `read_file` tool.\n *\n * Dispatches to `ExecutionContext.readFileBinary` when implemented; otherwise\n * shells out via `base64 < path` so docker / sandbox contexts don't have to\n * implement a custom primitive. The shell fallback is portable (busybox /\n * coreutils / macOS all ship `base64`) and only fires when the native path\n * is unavailable.\n *\n * Returns a base64 string ready to drop into a `ToolResultContent` image\n * block. Raises on read failure — caller is responsible for catching and\n * formatting the error message.\n */\n\nimport type { ExecutionContext, ExecutionHandle } from '../contexts'\nimport { Buffer } from 'node:buffer'\nimport { alwaysQuote } from './shell-quote'\n\n/**\n * Best-effort guess at IANA media type from a file extension. Covers the\n * extensions Zidane's `read_file` actually dispatches to image blocks\n * (png/jpg/jpeg/gif/webp). Other extensions return `undefined` and the\n * caller short-circuits the binary route.\n */\nexport function imageMediaTypeFor(path: string): string | undefined {\n const dot = path.lastIndexOf('.')\n if (dot === -1)\n return undefined\n const ext = path.slice(dot + 1).toLowerCase()\n switch (ext) {\n case 'png':\n return 'image/png'\n case 'jpg':\n case 'jpeg':\n return 'image/jpeg'\n case 'gif':\n return 'image/gif'\n case 'webp':\n return 'image/webp'\n default:\n return undefined\n }\n}\n\n/**\n * Read a file as base64. Prefers `ExecutionContext.readFileBinary` (zero\n * subprocess overhead in-process) and falls back to `base64 < path` via\n * the shell seam — works on docker / sandbox without an interface change.\n *\n * Returns `{ base64, byteLength }`. `byteLength` is the *decoded* byte count\n * so callers can size-budget against the original file, not the inflated\n * base64 representation (which is ~4/3× larger).\n */\nexport async function readFileAsBase64(\n execution: ExecutionContext,\n handle: ExecutionHandle,\n path: string,\n): Promise<{ base64: string, byteLength: number }> {\n if (execution.readFileBinary) {\n const bytes = await execution.readFileBinary(handle, path)\n const b64 = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString('base64')\n return { base64: b64, byteLength: bytes.byteLength }\n }\n\n // Shell fallback. Use `base64 -i` on macOS-style implementations; the\n // GNU/coreutils form just takes the path positionally. Try both.\n // `2>/dev/null` swallows the macOS warning when the GNU form is used on\n // a system without `-i`.\n const cmd = `base64 < ${alwaysQuote(path)}`\n const result = await execution.exec(handle, cmd)\n if (result.exitCode !== 0)\n throw new Error(`base64 read failed: ${result.stderr || `exit ${result.exitCode}`}`)\n // `base64` may emit line-wrapped output (76-col default); strip whitespace.\n const b64 = result.stdout.replace(/\\s+/g, '')\n return { base64: b64, byteLength: decodedBase64ByteLength(b64) }\n}\n\n/**\n * Decoded byte length of a (whitespace-stripped) base64 string. Accounts for\n * `=` padding so the value matches the original file size to the byte —\n * `Math.floor(len * 3 / 4)` over-reports by 1–2 bytes on padded payloads.\n */\nfunction decodedBase64ByteLength(b64: string): number {\n if (b64.length === 0)\n return 0\n let pad = 0\n if (b64.endsWith('=='))\n pad = 2\n else if (b64.endsWith('='))\n pad = 1\n return Math.max(0, (b64.length * 3) / 4 - pad)\n}\n","import type { ToolResultContent } from '../types'\nimport type { ToolContext, ToolDef } from './types'\nimport { Buffer } from 'node:buffer'\nimport { looksBinary } from './binary-detect'\nimport { imageMediaTypeFor, readFileAsBase64 } from './binary-read'\nimport { suggestionFor } from './path-suggest'\nimport { getReadState, hashContent } from './read-state'\n\n/**\n * Read a file with line-based offset/limit and a hard byte cap.\n *\n * Defaults are tuned for source code: 2000 lines / 256 KiB. A typical source\n * file, lockfile, or large config fits in one read; logs and very large\n * fixtures get truncated with a footer that documents how to fetch the\n * remainder.\n *\n * Binary files are detected on the leading bytes — if the buffer contains a\n * NUL or has an unreasonable proportion of non-printable bytes, we skip text\n * decoding and return a marker so the model doesn't drown in mojibake.\n */\n\nconst DEFAULT_LINE_LIMIT = 2000\nconst DEFAULT_BYTE_CAP = 262_144\n\n/**\n * Hard upper bound on raw image bytes we'll inline as a base64 image block.\n * Above this, we return a marker instead — the model won't get useful\n * information from a 10 MB+ screenshot rendered as one tool result, and\n * the wire bill gets ugly. Override via the `maxBytes` parameter on the\n * tool call.\n */\nconst DEFAULT_IMAGE_BYTE_CAP = 5 * 1024 * 1024\n\nexport const readFile: ToolDef = {\n spec: {\n name: 'read_file',\n description: 'Read a file by path. Returns lines [offset..offset+limit). Default offset=1, limit=2000. Each line is prefixed with its 1-indexed line number followed by a tab (e.g. `42\\\\tconst foo = bar`); the prefix is metadata, not part of the file. Mirrors Claude Code\\'s `cat -n`-style compact output for token efficiency. A trailing footer explains how to read the rest when truncated. Binary files return a short marker rather than mojibake.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Relative file path.' },\n offset: { type: 'integer', description: '1-indexed line number to start from. Default: 1.' },\n limit: { type: 'integer', description: 'Max lines to return. Default: 2000. Set 0 for unlimited.' },\n maxBytes: { type: 'integer', description: 'Hard byte cap on file content read, regardless of line count. Default: 262144. Set 0 for unlimited. The rendered output may be slightly larger than this cap when `lineNumbers` is on (each line carries a `<N>\\\\t` prefix).' },\n lineNumbers: { type: 'boolean', description: 'Prefix each line with its 1-indexed line number. Default: true. Override the agent-wide `behavior.readLineNumbers` for this call.' },\n },\n required: ['path'],\n },\n },\n async execute({ path, offset, limit, maxBytes, lineNumbers }, ctx: ToolContext) {\n // Image dispatch — vision-aware models can answer questions directly\n // against the image bytes; non-vision models get the marker substitution\n // applied later in the loop (`stripImagesForNonVision`). Skips the line-\n // based read entirely. Gated on extension only — content-sniffing would\n // double the IO for a marginal accuracy win.\n const imgMedia = imageMediaTypeFor(path as string)\n if (imgMedia) {\n const sizeCap = maxBytes !== undefined ? normalizeInteger(maxBytes, DEFAULT_IMAGE_BYTE_CAP) : DEFAULT_IMAGE_BYTE_CAP\n try {\n const { base64, byteLength } = await readFileAsBase64(ctx.execution, ctx.handle, path as string)\n if (sizeCap > 0 && byteLength > sizeCap) {\n return `[image too large to inline: ${path}, ${byteLength} bytes (cap ${sizeCap}). Raise maxBytes, or use shell to inspect.]`\n }\n const content: ToolResultContent[] = [\n { type: 'text', text: `Image: ${path} (${byteLength} bytes, ${imgMedia})` },\n { type: 'image', mediaType: imgMedia, data: base64 },\n ]\n return content\n }\n catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n const hint = await suggestionFor(ctx.execution, ctx.handle, path as string)\n return `Image read failed: ${path} — ${msg}.${hint}`\n }\n }\n\n let raw: string\n try {\n raw = await ctx.execution.readFile(ctx.handle, path as string)\n }\n catch {\n const hint = await suggestionFor(ctx.execution, ctx.handle, path as string)\n return `File not found: ${path}.${hint}`\n }\n\n const totalBytes = Buffer.byteLength(raw)\n\n // Per-session dedup: when the model re-reads the same file with the same\n // slice and the contents are unchanged, return a short stub instead of\n // re-emitting the bytes. Costs nothing when no session is bound (the\n // common case for direct/standalone tool invocations).\n //\n // The hash is taken on the *raw* file before any truncation so a future\n // read with a wider slice still invalidates the prior stub-eligible\n // entry — re-emitting the freshly-included bytes.\n const dedupEnabled = ctx.behavior?.dedupReads !== false\n const readState = dedupEnabled ? getReadState(ctx.session) : undefined\n const absKey = `${ctx.handle.cwd}::${path}`\n const offsetForKey = normalizeInteger(offset, 1)\n const limitForKey = normalizeInteger(limit, DEFAULT_LINE_LIMIT)\n const maxBytesForKey = normalizeInteger(maxBytes, DEFAULT_BYTE_CAP)\n const showLineNumbers = typeof lineNumbers === 'boolean'\n ? lineNumbers\n : (ctx.behavior?.readLineNumbers ?? true)\n const currentHash = readState ? hashContent(raw) : ''\n if (readState) {\n const prior = readState.get(absKey)\n if (\n prior\n && prior.contentHash === currentHash\n && prior.offset === offsetForKey\n && prior.limit === limitForKey\n && prior.maxBytes === maxBytesForKey\n // Toggling `lineNumbers` between reads must miss dedup: the stub\n // claims \"the prior result is still current\", but the prior\n // output was a different shape — the model would draw bogus\n // conclusions if we replayed it.\n && prior.lineNumbers === showLineNumbers\n ) {\n return `File ${path} unchanged since the previous read in this session — the prior result is still current.`\n }\n }\n\n // Cheap binary detection on a leading sample. ExecutionContext.readFile\n // returns UTF-8-decoded text already — but if the underlying file was\n // binary, the decode replaces invalid sequences with U+FFFD. Use a NUL\n // byte and replacement-char ratio in the sample as a heuristic.\n if (looksBinary(raw)) {\n return `[binary file: ${path}, ${totalBytes} bytes; use shell with hexdump | xxd | od to inspect]`\n }\n\n const offsetN = offsetForKey\n const limitN = limitForKey\n const maxBytesN = maxBytesForKey\n\n const lines = raw.split('\\n')\n const totalLines = lines.length\n\n // 1-indexed offset → 0-indexed slice start.\n const startIdx = Math.max(0, offsetN - 1)\n const endIdx = limitN > 0 ? Math.min(totalLines, startIdx + limitN) : totalLines\n let slice = lines.slice(startIdx, endIdx)\n\n // Apply byte cap at the line boundary. Walk lines, accumulating bytes; cut\n // just below the cap. The \"truncatedSlice.length > 0\" guard ensures we\n // always emit at least one line — files with a single oversized line would\n // otherwise return empty. The single-line overflow gets handled by the\n // hard-cap pass below.\n let bytesCut = false\n if (maxBytesN > 0) {\n const truncatedSlice: string[] = []\n let bytesUsed = 0\n for (const line of slice) {\n const lineBytes = Buffer.byteLength(line) + 1 // +1 for the '\\n' rejoin\n if (bytesUsed + lineBytes > maxBytesN && truncatedSlice.length > 0) {\n bytesCut = true\n break\n }\n truncatedSlice.push(line)\n bytesUsed += lineBytes\n if (bytesUsed >= maxBytesN) {\n // Budget consumed — keep this line, stop here.\n break\n }\n }\n if (truncatedSlice.length < slice.length)\n bytesCut = true\n slice = truncatedSlice\n }\n\n // Hard-cap pass: when the line-boundary loop had to admit an oversized line\n // (single huge line, or first line ≥ maxBytes), the body still exceeds the\n // budget. Truncate the last line at a UTF-8-safe boundary and flag it as a\n // mid-line cut so the footer can warn the reader that offset+1 won't pick\n // up where this read left off.\n let midLineCut = false\n if (maxBytesN > 0 && slice.length > 0) {\n const bodyBytes = Buffer.byteLength(slice.join('\\n'))\n if (bodyBytes > maxBytesN) {\n const lastIdx = slice.length - 1\n const lastLine = slice[lastIdx]\n const otherBytes = lastIdx > 0\n ? Buffer.byteLength(slice.slice(0, lastIdx).join('\\n')) + 1 // +1 for the joining '\\n'\n : 0\n const budgetForLast = Math.max(0, maxBytesN - otherBytes)\n // Estimate cut at char count = byte budget (correct for ASCII), then\n // walk back if the resulting prefix still overflows because of multi-\n // byte codepoints. Worst case ~3 iterations (max UTF-8 width is 4).\n let cut = Math.min(lastLine.length, budgetForLast)\n while (cut > 0 && Buffer.byteLength(lastLine.slice(0, cut)) > budgetForLast)\n cut--\n slice[lastIdx] = lastLine.slice(0, cut)\n midLineCut = true\n bytesCut = true\n }\n }\n\n const linesReturned = slice.length\n const lastLineRead = startIdx + linesReturned\n\n // Line numbers default on. Format: `<line-no>\\t<content>` — bare digit,\n // tab separator, no padding. Matches Claude Code's compact `cat -n`\n // output for token efficiency (~5 chars saved per line vs. padded\n // forms). Models treat the prefix as metadata; `edit` strips it from\n // `old_string` when the model pastes a numbered chunk back, and also\n // accepts `<N>|<content>` / `<N>→<content>` for cross-stack tolerance.\n const body = showLineNumbers\n ? slice.map((line, i) => `${startIdx + i + 1}\\t${line}`).join('\\n')\n : slice.join('\\n')\n\n if (readState) {\n readState.set(absKey, {\n contentHash: currentHash,\n offset: offsetN,\n limit: limitN,\n maxBytes: maxBytesN,\n lineNumbers: showLineNumbers,\n mtimeMs: Date.now(),\n })\n }\n\n const linesTruncated = endIdx < totalLines || bytesCut\n if (!linesTruncated && offsetN === 1)\n return body\n\n if (!linesTruncated) {\n // Reading from a non-1 offset; tell the model where the read started.\n return `${body}\\n\\n…read lines ${offsetN}-${lastLineRead} of ${totalLines}.`\n }\n\n if (midLineCut) {\n // Line N was only partially read, so offset=N+1 would skip the unread\n // portion — we don't suggest it. Raising maxBytes is the only lossless\n // way forward. Avoid suggesting shell+sed/awk slicing here: that primes\n // a debugging anti-pattern where the model loops on narrow shell probes\n // instead of using paginated read_file calls.\n return `${body}\\n\\n…truncated mid-line at line ${lastLineRead} (byte cap ${maxBytesN} reached). File has ${totalLines} lines, ${totalBytes} bytes total. Raise maxBytes to read the full line.`\n }\n\n const reason = bytesCut ? `byte cap (${maxBytesN}) reached` : `line limit (${limitN}) reached`\n return `${body}\\n\\n…truncated at line ${lastLineRead} (${reason}). File has ${totalLines} lines, ${totalBytes} bytes total — re-read with offset=${lastLineRead + 1} to continue.`\n },\n}\n\nfunction normalizeInteger(value: unknown, fallback: number): number {\n if (typeof value !== 'number' || !Number.isFinite(value))\n return fallback\n // Validation auto-coerces strings to numbers, so by the time we get here\n // a non-finite value means the caller passed something garbled.\n if (value < 0)\n return fallback\n return Math.floor(value)\n}\n","/**\n * Per-command exit-code interpretation for the `shell` tool.\n *\n * Many command-line tools use non-zero exit codes to signal information that\n * is *not* an error — `grep` returns 1 for \"no matches found\", `diff` returns\n * 1 for \"files differ\", `find` returns 1 when some directories were\n * inaccessible, and `test`/`[` return 1 for \"condition false\". Treating\n * those uniformly as failures wastes turns: models retry or pivot when there\n * is nothing wrong.\n *\n * Mirrors `claude-code/tools/BashTool/commandSemantics.ts`.\n */\n\nexport interface CommandSemanticResult {\n /** Whether to surface this as an error to the model (`Exit code N` prefix). */\n isError: boolean\n /** Optional human-readable footer appended after the body, e.g. \"No matches found\". */\n message?: string\n}\n\ntype CommandSemantic = (exitCode: number) => CommandSemanticResult\n\nconst DEFAULT_SEMANTIC: CommandSemantic = exitCode => ({\n isError: exitCode !== 0,\n message: exitCode !== 0 ? `Command failed with exit code ${exitCode}` : undefined,\n})\n\nconst COMMAND_SEMANTICS: ReadonlyMap<string, CommandSemantic> = new Map<string, CommandSemantic>([\n // grep / ripgrep: 0 = matches, 1 = no matches, ≥2 = error.\n ['grep', exit => ({ isError: exit >= 2, message: exit === 1 ? 'No matches found' : undefined })],\n ['rg', exit => ({ isError: exit >= 2, message: exit === 1 ? 'No matches found' : undefined })],\n // diff: 0 = identical, 1 = differ, ≥2 = error.\n ['diff', exit => ({ isError: exit >= 2, message: exit === 1 ? 'Files differ' : undefined })],\n // find: 0 = ok, 1 = some dirs inaccessible (warning), ≥2 = error.\n ['find', exit => ({ isError: exit >= 2, message: exit === 1 ? 'Some directories were inaccessible' : undefined })],\n // test / [: 0 = condition true, 1 = condition false, ≥2 = error.\n ['test', exit => ({ isError: exit >= 2, message: exit === 1 ? 'Condition is false' : undefined })],\n ['[', exit => ({ isError: exit >= 2, message: exit === 1 ? 'Condition is false' : undefined })],\n])\n\n/**\n * Pick the semantic for a command line. Best-effort: walks the command from\n * right to left, taking the last segment after `|` / `&&` / `||` / `;` —\n * that's the segment whose exit code propagates. Don't depend on this for\n * security; it's a heuristic, not a parser.\n */\nexport function interpretShellResult(\n command: string,\n exitCode: number,\n): CommandSemanticResult {\n const base = extractTrailingCommand(command)\n const semantic = COMMAND_SEMANTICS.get(base) ?? DEFAULT_SEMANTIC\n return semantic(exitCode)\n}\n\nfunction extractTrailingCommand(command: string): string {\n // Split on the common chain operators. The exit code we see is the trailing\n // segment's. Quoted operators escape the split, but we don't try to be\n // perfect — false positives just fall back to default semantics.\n const segments = command.split(/\\|\\||&&|[;|\\n]/)\n const last = segments[segments.length - 1]?.trim() ?? command\n // First whitespace-delimited token of the trailing segment, sans leading\n // env assignments (`FOO=bar baz` → `baz`).\n const tokens = last.split(/\\s+/).filter(t => !/^[A-Z_]\\w*=/i.test(t))\n return tokens[0] ?? ''\n}\n","import type { ToolContext, ToolDef } from './types'\nimport { Buffer } from 'node:buffer'\nimport { interpretShellResult } from './shell-semantics'\n\n/**\n * Execute a shell command in the agent's execution context.\n *\n * Truncation is **tail-priority**: when stdout+stderr combined exceeds\n * `maxOutputBytes`, the head is dropped and a marker `…(N bytes truncated\n * from head)…` is inserted before the tail. Errors and exit summaries\n * usually live at the end of output, so keeping the tail preserves the\n * model's most useful signal.\n *\n * Defaults are tuned for typical commands (build output, test runs): the\n * combined cap is 32 KiB and the per-call timeout follows the execution\n * context's own default (30 s for in-process).\n */\n\nconst DEFAULT_MAX_OUTPUT_BYTES = 32_768\n\nexport const shell: ToolDef = {\n spec: {\n name: 'shell',\n description: 'Execute a shell command in the project root and return its combined stdout/stderr. Output is tail-priority truncated at 32 KiB by default; errors and exit-code summaries live in the tail. By default each call appends a `(exit N, Nms)` footer and surfaces non-empty stderr in a separate section even on success — set `metadata: false` to return only stdout. Set maxOutputBytes=0 to disable truncation.',\n inputSchema: {\n type: 'object',\n properties: {\n command: { type: 'string', description: 'Shell command to run.' },\n timeout: { type: 'integer', description: 'Per-call timeout in milliseconds.' },\n maxOutputBytes: { type: 'integer', description: 'Truncate combined stdout+stderr beyond this many bytes. Default: 32768. Set 0 for unlimited.' },\n metadata: { type: 'boolean', description: 'Append `(exit N, Nms)` footer and surface non-empty stderr on success. Default: true.' },\n },\n required: ['command'],\n },\n },\n async execute({ command, timeout, maxOutputBytes, metadata }, ctx: ToolContext) {\n // `ExecutionContext.exec` accepts a timeout in seconds; the tool surface\n // takes it in milliseconds so the value lines up with the rest of zidane's\n // ms-based timing. Round up so a 500ms request doesn't collapse to 0.\n const execOpts: { timeout?: number } = {}\n if (typeof timeout === 'number' && Number.isFinite(timeout) && timeout > 0)\n execOpts.timeout = Math.max(1, Math.ceil(timeout / 1000))\n\n const cmd = command as string\n const wantMetadata = metadata !== false\n const startedAt = Date.now()\n const result = await ctx.execution.exec(ctx.handle, cmd, execOpts)\n const durationMs = Date.now() - startedAt\n\n const cap = normalizeCap(maxOutputBytes)\n const semantic = interpretShellResult(cmd, result.exitCode)\n\n // True success (exit 0): stdout body, tail-truncated. With metadata,\n // surface non-empty stderr in a separate section (warnings, deprecation\n // notices) and append an `(exit 0, Nms)` footer.\n if (result.exitCode === 0) {\n const stdoutTail = truncateTail(result.stdout || '(no output)', cap)\n if (!wantMetadata)\n return stdoutTail\n const stderrTrimmed = result.stderr.trim()\n const stderrSection = stderrTrimmed\n ? `\\n[stderr]\\n${truncateTail(stderrTrimmed, Math.min(cap, 2048))}`\n : ''\n return `${stdoutTail}${stderrSection}\\n(exit 0, ${durationMs}ms)`\n }\n\n // Per-command semantic override: non-zero exit codes that are NOT errors\n // (grep no-match, diff differ, find partial, test false). Don't surface\n // `Exit code N` — that misleads the model into retrying. Append a short\n // footer with the semantic interpretation so the model sees the why.\n if (!semantic.isError) {\n const body = (result.stdout || result.stderr || '').trim()\n const tail = truncateTail(body, cap)\n const semanticFooter = semantic.message ? `\\n(${semantic.message})` : ''\n const timingFooter = wantMetadata ? `\\n(exit ${result.exitCode}, ${durationMs}ms)` : ''\n const head = tail.length > 0 ? tail : (semantic.message ?? '(no output)')\n return `${head}${semanticFooter}${timingFooter}`\n }\n\n // Real failure → keep the `Exit code N` line outside the truncation budget.\n // Truncating the joined body otherwise drops the exit-code prefix (it sits at\n // the head) the moment stdout overflows, leaving the model unable to tell\n // success from failure on large-output commands.\n const combined = `${result.stdout}\\n${result.stderr}`.trim()\n const header = wantMetadata\n ? `Exit code ${result.exitCode} (${durationMs}ms)`\n : `Exit code ${result.exitCode}`\n return `${header}\\n${truncateTail(combined, cap)}`\n },\n}\n\nfunction normalizeCap(value: unknown): number {\n if (typeof value !== 'number' || !Number.isFinite(value))\n return DEFAULT_MAX_OUTPUT_BYTES\n if (value < 0)\n return DEFAULT_MAX_OUTPUT_BYTES\n return Math.floor(value)\n}\n\n/**\n * Tail-priority byte truncation. When `text` exceeds `cap` bytes, the head is\n * dropped and replaced with a marker. Always cuts on character boundaries (no\n * mid-codepoint splits) by walking from the end with `Buffer.byteLength`.\n *\n * `cap === 0` disables truncation. `cap` is interpreted as a UTF-8 byte budget\n * for the tail itself — the marker is added on top and may push the visible\n * length slightly past `cap`. That tradeoff is intentional: a marker that\n * always fits inside the budget would shrink the actual content displayed.\n */\nfunction truncateTail(text: string, cap: number): string {\n if (cap === 0)\n return text\n\n const totalBytes = Buffer.byteLength(text)\n if (totalBytes <= cap)\n return text\n\n // Walk back from the end, accumulating UTF-8 bytes per character, until\n // we've gathered up to `cap` bytes. Slicing on char index ensures we never\n // split a multi-byte codepoint mid-stream.\n let bytes = 0\n let charIdx = text.length\n while (charIdx > 0) {\n const ch = text[charIdx - 1]\n const chBytes = Buffer.byteLength(ch)\n if (bytes + chBytes > cap)\n break\n bytes += chBytes\n charIdx--\n }\n\n const tail = text.slice(charIdx)\n const droppedBytes = totalBytes - Buffer.byteLength(tail)\n return `…(${droppedBytes} bytes truncated from head)…\\n${tail}`\n}\n","/**\n * Spawn tool — create sub-agents from a parent agent.\n *\n * A configurable factory that reads the parent's preset-y fields from ToolContext.\n *\n * Usage:\n * ```ts\n * import { createSpawnTool } from 'zidane'\n * import { definePreset, basicTools } from 'zidane/presets'\n *\n * const preset = definePreset({\n * name: 'orchestrator',\n * tools: { ...basicTools, spawn: createSpawnTool({ maxConcurrent: 5 }) },\n * })\n * ```\n *\n * Each `createSpawnTool()` call returns a fresh instance with its own\n * concurrency counter, depth cap, and child-stats accumulator — never\n * share an instance across unrelated parent agents.\n *\n * Key guarantees:\n * - **Depth-capped** to `maxDepth` (default 3) to prevent infinite recursion.\n * - **Concurrency slot is reserved synchronously** before any `await`, so a\n * parent running tools in parallel cannot exceed `maxConcurrent`.\n * - **Pre-aborted signals short-circuit** without paying agent-spawn cost.\n * - **Abort / timeout / error are surfaced distinctly** in the returned text\n * and via `ChildRunStats.status` on `spawn:complete`.\n * - **`agent.destroy()` errors never mask the original run error** (captured\n * and emitted via `spawn:error` but the primary error wins).\n * - **Child hooks bubble** to the parent as `child:*` events when\n * `forwardHooks` is set (default `true`).\n * - **Persistence** via `persist: true` — child runs get appended to the\n * parent's session with `parentRunId` wired, so the run tree is\n * reconstructible from a stored `SessionData`.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from '../agent'\nimport type { Preset } from '../presets'\nimport type { Session } from '../session'\nimport type { AgentStats, ChildRunStats } from '../types'\nimport type { ToolContext, ToolDef } from './types'\nimport { createAgent } from '../agent'\nimport { flattenTurns, formatTokenUsage } from '../stats'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface ChildAgent {\n id: string\n task: string\n startedAt: number\n /** Subagent depth — 1 for a direct child of a top-level agent. */\n depth: number\n}\n\nexport interface SpawnToolState {\n /** Currently running children. */\n readonly children: ReadonlyMap<string, ChildAgent>\n /**\n * Cumulative stats across every completed direct child of this spawn-tool\n * instance (returns a copy). Each child's contribution is the cumulative\n * `AgentStats` returned by its `agent.run()` — so\n * `totalIn`/`totalOut`/`totalCacheRead`/`totalCacheCreation` cover the\n * entire subtree (children + grandchildren + …), while `turns` and\n * `elapsed` stay parent-loop-only per child and are summed across direct\n * children. `elapsed` over-counts when children ran in parallel.\n *\n * Lives across multiple parent runs that share this instance.\n */\n readonly totalChildStats: Readonly<AgentStats>\n}\n\n// ---------------------------------------------------------------------------\n// Events to bubble from child → parent. Keep these lists small: the goal is\n// to give the parent a usable live-tail (and a place to gate child calls)\n// without drowning it in telemetry.\n//\n// Two kinds:\n// - {@link BUBBLED_EVENTS} — observational. Forwarded as a spread copy so\n// the parent's listeners can't accidentally mutate the child's ctx.\n// - {@link BUBBLED_GATE_EVENTS} — gates. Forwarded with the SAME ctx\n// reference so parent listeners can set `block` / `reason` / `result`\n// and have those mutations land on the gate the child's loop is\n// awaiting on.\n// ---------------------------------------------------------------------------\n\nconst BUBBLED_EVENTS = [\n 'stream:text',\n 'stream:thinking',\n 'stream:end',\n 'tool:before',\n 'tool:after',\n 'tool:error',\n 'turn:after',\n] as const\n\nconst BUBBLED_GATE_EVENTS = [\n 'tool:gate',\n 'mcp:tool:gate',\n] as const\n\ntype BubbledEvent = typeof BUBBLED_EVENTS[number]\ntype BubbledGateEvent = typeof BUBBLED_GATE_EVENTS[number]\n\n// Mapping from a bubbled event to its corresponding `child:*` event. Kept as\n// an explicit table (rather than a computed `child:${evt}` template literal)\n// so AgentHooks can type each entry independently.\nconst CHILD_EVENT_NAME: Record<BubbledEvent, keyof AgentHooks> = {\n 'stream:text': 'child:stream:text',\n 'stream:thinking': 'child:stream:thinking',\n 'stream:end': 'child:stream:end',\n 'tool:before': 'child:tool:before',\n 'tool:after': 'child:tool:after',\n 'tool:error': 'child:tool:error',\n 'turn:after': 'child:turn:after',\n}\n\nconst CHILD_GATE_EVENT_NAME: Record<BubbledGateEvent, keyof AgentHooks> = {\n 'tool:gate': 'child:tool:gate',\n 'mcp:tool:gate': 'child:mcp:tool:gate',\n}\n\n// ---------------------------------------------------------------------------\n// Session-scoped child label counter\n//\n// The `child-N` label that surfaces in transcripts (and in the spawn tool's\n// return string) is allocated per-session — *seeded* from the persisted\n// run tree — rather than from a closure-local counter on the spawn-tool\n// instance. The reason: closure counters don't survive process restarts,\n// so a fresh CLI launch that reopens a session with two prior children\n// (`child-1`, `child-2`) would start its next spawn at `child-1` and\n// collide with the persisted labels. Anchoring on `session.runs.filter(\n// depth > 0).length` makes the live counter pick up exactly where the\n// reloaded transcript's labels left off — matching `eventsFromTurns`'s\n// chronological numbering on the read side.\n//\n// The WeakMap caches the counter for the lifetime of the `Session` object\n// after the first call so the read of `session.runs.length` only happens\n// once per session, even though spawns mutate `session.runs` mid-run.\n//\n// Sessionless agents (no `ctx.session`) fall back to `localCounter` — the\n// closure is the best we can do without a shared anchor.\n// ---------------------------------------------------------------------------\n\nconst sessionChildCounters = new WeakMap<Session, number>()\n\nfunction reserveChildLabel(session: Session): string {\n let counter = sessionChildCounters.get(session)\n if (counter === undefined)\n counter = session.runs.filter(r => (r.depth ?? 0) > 0).length\n counter += 1\n sessionChildCounters.set(session, counter)\n return `child-${counter}`\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction extractText(message: unknown): string {\n if (!message || typeof message !== 'object')\n return ''\n\n const msg = message as Record<string, unknown>\n\n if (typeof msg.content === 'string')\n return msg.content\n\n if (Array.isArray(msg.content)) {\n return msg.content\n .filter((block): block is Record<string, unknown> => !!block && typeof block === 'object' && (block as Record<string, unknown>).type === 'text')\n .map(block => block.text)\n .join('\\n')\n }\n\n return ''\n}\n\n/**\n * Race `task` (an already-running child `agent.run()` promise) against a\n * timer. Does NOT race against the parent abort signal — the child agent\n * already observes the same signal internally and handles its own aborted\n * bookkeeping, so racing here would detach the spawn from the child's\n * session-persisting finally block.\n *\n * On timeout: rejects with `SpawnTimeoutError`; caller is expected to call\n * `agent.abort()` and subsequently `await` the original `task` so the\n * child's session state (runs, turns, status) gets flushed before the\n * parent moves on.\n */\nasync function raceWithTimeout<T>(\n task: Promise<T>,\n timeoutMs: number | undefined,\n): Promise<T> {\n if (!timeoutMs || timeoutMs <= 0)\n return task\n\n let timer: ReturnType<typeof setTimeout> | undefined\n try {\n return await new Promise<T>((resolve, reject) => {\n timer = setTimeout(() => reject(new SpawnTimeoutError(timeoutMs)), timeoutMs)\n task.then(resolve, reject)\n })\n }\n finally {\n if (timer)\n clearTimeout(timer)\n }\n}\n\nclass SpawnTimeoutError extends Error {\n readonly timeoutMs: number\n constructor(timeoutMs: number) {\n super(`Child agent timed out after ${timeoutMs}ms`)\n this.name = 'SpawnTimeoutError'\n this.timeoutMs = timeoutMs\n }\n}\n\n/**\n * Wire child's hooks to bubble into `parentHooks` as `child:*` events.\n *\n * Three kinds of forwarding:\n *\n * 1. **Originating observational events** (`stream:text`, `tool:before`, …)\n * → rewrite to the matching `child:*` event, inject `{ childId, depth }`,\n * fire on the parent's hook bus as a **spread copy** (so parent listeners\n * can't accidentally mutate the child's ctx).\n * 2. **Originating gate events** (`tool:gate`, `mcp:tool:gate`) → forward\n * the **same ctx reference**, augmented with `childId` / `depth`, so a\n * parent listener writing `ctx.block = true` lands on the gate the\n * child's loop is awaiting on. The bubble itself `await`s the parent's\n * callHook so any async approval (e.g. a TUI picker) completes before\n * the child's loop sees the decision.\n * 3. **Re-bubbled `child:*` events** from a grandchild already carry the\n * originating `childId` + `depth`. Forward verbatim so a top-level\n * listener sees true ancestry, not the immediate parent's.\n *\n * Returns a function that unregisters every listener registered here.\n * Called before `agent.run()` starts, torn down in a finally block — so\n * nothing leaks even if the child throws mid-run.\n */\nfunction bubbleHooks(\n childHooks: Hookable<AgentHooks>,\n parentHooks: Hookable<AgentHooks>,\n childId: string,\n depth: number,\n): () => void {\n const unregisters: Array<() => void> = []\n\n // Cast the callHook surface once — it accepts any (name, ctx) at runtime\n // but the typed overload is too narrow to satisfy across the map.\n const fire = parentHooks.callHook as unknown as (\n name: keyof AgentHooks,\n ctx: Record<string, unknown>,\n ) => Promise<unknown>\n\n // Observational events — `void fire(...)` so a slow parent listener never\n // backpressures child emission (the child has already moved on by then).\n for (const evt of BUBBLED_EVENTS) {\n const parentEvt = CHILD_EVENT_NAME[evt]\n const unregister = childHooks.hook(evt, (ctx: object) => {\n void fire(parentEvt, { ...(ctx as Record<string, unknown>), childId, depth })\n })\n unregisters.push(unregister)\n }\n\n // Gate events — `await` so the parent's decision is in place before the\n // child's loop reads `ctx.block` / `ctx.result`. Same ctx reference is\n // passed through; the bubble only adds `childId` + `depth` for routing.\n const tagOnCtx = (ctx: Record<string, unknown>) => {\n ctx.childId = childId\n ctx.depth = depth\n }\n for (const evt of BUBBLED_GATE_EVENTS) {\n const parentEvt = CHILD_GATE_EVENT_NAME[evt]\n const unregister = childHooks.hook(evt, async (ctx: object) => {\n tagOnCtx(ctx as Record<string, unknown>)\n await fire(parentEvt, ctx as Record<string, unknown>)\n })\n unregisters.push(unregister)\n }\n\n // Chain bubbling: forward already-tagged `child:*` events from a grandchild\n // through to the parent, preserving the originating spawn's `childId` +\n // `depth`. Without this, only direct children would surface.\n const chainHook = childHooks.hook as unknown as (\n name: keyof AgentHooks,\n handler: (ctx: object) => void | Promise<void>,\n ) => () => void\n for (const evt of BUBBLED_EVENTS) {\n const parentEvt = CHILD_EVENT_NAME[evt]\n unregisters.push(chainHook(parentEvt, (ctx) => {\n void fire(parentEvt, ctx as Record<string, unknown>)\n }))\n }\n for (const evt of BUBBLED_GATE_EVENTS) {\n const parentEvt = CHILD_GATE_EVENT_NAME[evt]\n unregisters.push(chainHook(parentEvt, async (ctx) => {\n // Gates need the await chain to remain serial up to the top-level\n // listener — otherwise the deepest child's loop resumes before the\n // root's decision lands.\n await fire(parentEvt, ctx as Record<string, unknown>)\n }))\n }\n\n return () => {\n for (const u of unregisters) u()\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport interface SpawnToolOptions {\n /** Maximum concurrent sub-agents (default: 3). */\n maxConcurrent?: number\n /**\n * Maximum subagent depth. 0 disables spawning entirely; 1 allows top-level\n * spawns but forbids grandchildren; 3 (default) allows three levels of\n * recursion — enough for most orchestration patterns, a sharp ceiling\n * against runaway loops.\n */\n maxDepth?: number\n /** Child model override. */\n model?: string\n /** Child system prompt override. Per-spawn `input.system` takes precedence. */\n system?: string\n /** Child thinking level. */\n thinking?: 'off' | 'minimal' | 'low' | 'medium' | 'high'\n /** Preset override for children. Shallow-merged over the parent's preset (parent fields still win for anything left unset). */\n preset?: Preset\n /**\n * Per-child timeout, in milliseconds. When the child exceeds it the spawn\n * tool returns a timeout marker, fires `spawn:error`, and destroys the\n * child agent. Default: none.\n */\n timeoutMs?: number\n /**\n * When `true` and the parent has a session, the child reuses the parent's\n * session — child turns are appended with the child's own `runId`, and the\n * resulting `SessionRun` carries `parentRunId` so the tree is\n * reconstructible. Default: `false` (child is in-memory only).\n */\n persist?: boolean\n /**\n * Forward a curated subset of child hook events (`stream:*`, `tool:*`,\n * `turn:after`) onto the parent's hook bus as `child:*` events. Default:\n * `true`. Grandchildren bubble through their child transparently.\n */\n forwardHooks?: boolean\n /** Called when a child agent starts. */\n onSpawn?: (child: ChildAgent) => void\n /** Called when a child agent completes (success, abort, timeout, or error). */\n onComplete?: (child: ChildAgent, stats: AgentStats, status: NonNullable<ChildRunStats['status']>) => void\n}\n\n/**\n * Create a configured spawn tool.\n *\n * State (`children`, `totalChildStats`, counters, active count) is scoped to\n * the returned instance. Multiple parent agents using the same instance will\n * share counters + stats + concurrency slots — call `createSpawnTool()` per\n * agent (or use the stateless default `spawn`) to keep them isolated.\n */\nexport function createSpawnTool(options: SpawnToolOptions = {}): ToolDef & SpawnToolState {\n const localChildren = new Map<string, ChildAgent>()\n let localCounter = 0\n let localActiveCount = 0\n const maxConcurrent = options.maxConcurrent ?? 3\n const maxDepth = options.maxDepth ?? 3\n const forwardHooks = options.forwardHooks ?? true\n\n const localStats: AgentStats = {\n totalIn: 0,\n totalOut: 0,\n totalCacheRead: 0,\n totalCacheCreation: 0,\n turns: 0,\n elapsed: 0,\n }\n\n return {\n get children() { return localChildren },\n get totalChildStats() { return { ...localStats } },\n\n spec: {\n name: 'spawn',\n description: 'Spawn a sub-agent for a self-contained task that benefits from isolation (separate context window, separate retries) — for example, a deep research dive or a long codegen pass on a specific file. The sub-agent runs independently with its own tool access and returns its final response. Do NOT spawn for sequential steps you could do yourself.',\n inputSchema: {\n type: 'object',\n properties: {\n task: {\n type: 'string',\n description: 'The task prompt for the sub-agent. Be specific about what you want it to accomplish.',\n },\n system: {\n type: 'string',\n description: 'Optional system prompt override for this specific sub-agent.',\n },\n },\n required: ['task'],\n },\n },\n\n async execute(input: Record<string, unknown>, ctx: ToolContext): Promise<string> {\n const task = input.task as string\n const systemOverride = input.system as string | undefined\n const parentDepth = ctx.depth ?? 0\n const childDepth = parentDepth + 1\n\n // Reject before any await so the parent-level LLM sees the failure\n // immediately, and the concurrency slot below is reserved atomically\n // with the cap check.\n if (childDepth > maxDepth) {\n return `Cannot spawn: maxDepth=${maxDepth} reached (parent depth=${parentDepth}). Deepen the cap with createSpawnTool({ maxDepth }).`\n }\n\n if (localActiveCount >= maxConcurrent) {\n return `Cannot spawn: ${localActiveCount}/${maxConcurrent} sub-agents already running. Wait for one to complete.`\n }\n\n // Signal short-circuit: a pre-aborted parent means the child would\n // immediately no-op on its first `signal.aborted` check. Skip the\n // agent/handle/session setup cost entirely.\n if (ctx.signal.aborted) {\n return `[sub-agent pre-aborted] Parent signal was already aborted — skipped \"${task.slice(0, 80)}\"`\n }\n\n // Reserve the slot + id SYNCHRONOUSLY — this block must not contain\n // any `await`, so (a) two parallel spawns can't both pass the cap\n // check, and (b) the session-scoped child counter (see\n // `reserveChildLabel`) sees a consistent `session.runs` snapshot\n // between concurrent spawns sharing this session.\n const id = ctx.session\n ? reserveChildLabel(ctx.session)\n : `child-${++localCounter}`\n localActiveCount++\n const child: ChildAgent = { id, task, startedAt: Date.now(), depth: childDepth }\n localChildren.set(id, child)\n\n let destroyError: Error | undefined\n let childRunStatus: NonNullable<ChildRunStats['status']> = 'completed'\n let finalStats: AgentStats | undefined\n let result = ''\n\n // Bubble child hook events to parent if requested. Wired BEFORE\n // `agent.run()` so even the very first `turn:before` is observable.\n let unbubble: (() => void) | undefined\n\n try {\n const parentPreset: Preset = {\n ...(ctx.name !== undefined ? { name: ctx.name } : {}),\n ...(ctx.system !== undefined ? { system: ctx.system } : {}),\n tools: ctx.tools,\n ...(ctx.toolAliases !== undefined ? { toolAliases: ctx.toolAliases } : {}),\n ...(ctx.mcpServers !== undefined ? { mcpServers: ctx.mcpServers } : {}),\n ...(ctx.skills !== undefined ? { skills: ctx.skills } : {}),\n ...(ctx.behavior !== undefined ? { behavior: ctx.behavior } : {}),\n }\n const agent = createAgent({\n ...parentPreset,\n ...options.preset,\n provider: ctx.provider,\n execution: ctx.execution,\n // Share the parent's session on opt-in. Child turns get appended to\n // the same session.turns stream with the child's runId; the child\n // run itself is tagged with parentRunId below, via AgentRunOptions.\n ...(options.persist && ctx.session ? { session: ctx.session } : {}),\n })\n\n if (forwardHooks)\n unbubble = bubbleHooks(agent.hooks, ctx.hooks, id, childDepth)\n\n options.onSpawn?.(child)\n await ctx.hooks.callHook('spawn:before', { id, task, depth: childDepth })\n\n // `agent.run()` is started here and we hold onto its promise so we\n // can always `await` it before destroying. Even on a timeout we\n // re-await the run — that lets the child's internal `finally`\n // (session.abortRun, finalizeSession, hooks) flush its state to the\n // store before the parent hands the outcome back to the LLM.\n const runPromise = agent.run({\n prompt: task,\n model: options.model,\n system: systemOverride ?? options.system,\n thinking: options.thinking,\n signal: ctx.signal,\n depth: childDepth,\n ...(options.persist && ctx.runId ? { parentRunId: ctx.runId } : {}),\n })\n\n try {\n finalStats = await raceWithTimeout(runPromise, options.timeoutMs)\n\n // Tree-wide turn count keeps the model-facing line internally\n // consistent with the cumulative token numbers — otherwise a\n // 2-turn child that spawned a 50-turn grandchild would print\n // \"2 turns ... 5000 tokens\" and look broken. Equals\n // `finalStats.turns` when the child has no descendants of its own.\n const treeTurns = flattenTurns(finalStats).length\n // `formatTokenUsage` reports the effective input (including\n // cached reads / cache creations) with the cached portion broken\n // out — see the helper's docstring.\n const usage = formatTokenUsage(finalStats)\n if (ctx.signal.aborted) {\n childRunStatus = 'aborted'\n result = [\n `[sub-agent ${id}] Aborted after ${treeTurns} turns (${finalStats.elapsed}ms)`,\n `Tokens: ${usage}`,\n ].join('\\n')\n }\n else {\n const response = extractText(agent.turns.at(-1))\n result = [\n `[sub-agent ${id}] Completed in ${treeTurns} turns (${finalStats.elapsed}ms)`,\n `Tokens: ${usage}`,\n '',\n response || '(no text response)',\n ].join('\\n')\n }\n }\n catch (err) {\n if (err instanceof SpawnTimeoutError) {\n childRunStatus = 'timeout'\n agent.abort() // triggers child's internal abort path\n // Await the run so its finally block persists aborted state\n // before we move on. Swallow any error from the awaited promise\n // — we've already classified the outcome as 'timeout'.\n try {\n finalStats = await runPromise\n }\n catch {\n finalStats = {\n totalIn: 0,\n totalOut: 0,\n totalCacheRead: 0,\n totalCacheCreation: 0,\n turns: 0,\n elapsed: err.timeoutMs,\n }\n }\n result = `[sub-agent ${id}] Timed out after ${err.timeoutMs}ms`\n }\n else {\n const error = err instanceof Error ? err : new Error(String(err))\n childRunStatus = 'error'\n finalStats = {\n totalIn: 0,\n totalOut: 0,\n totalCacheRead: 0,\n totalCacheCreation: 0,\n turns: 0,\n elapsed: 0,\n }\n result = `[sub-agent ${id}] Error: ${error.message}`\n await ctx.hooks.callHook('spawn:error', { id, task, depth: childDepth, error })\n }\n }\n finally {\n // Always attempt to destroy. Capture any destroy error so it can be\n // surfaced via spawn:error without masking the primary outcome.\n try {\n await agent.destroy()\n }\n catch (err) {\n destroyError = err instanceof Error ? err : new Error(String(err))\n }\n }\n\n // Aggregate after run finalization so in-flight totalIn/Out/turns\n // counters are stable.\n if (finalStats) {\n localStats.totalIn += finalStats.totalIn\n localStats.totalOut += finalStats.totalOut\n localStats.totalCacheRead += finalStats.totalCacheRead\n localStats.totalCacheCreation += finalStats.totalCacheCreation\n localStats.turns += finalStats.turns\n // `elapsed` is a cumulative sum across children — documented as such.\n // Over-counts when children run in parallel; reflects \"total CPU-ish\n // time burned on children\" rather than wall-clock parallelism.\n localStats.elapsed += finalStats.elapsed\n }\n\n // Build ChildRunStats + emit completion hook. Emitted for every\n // terminal state (success/abort/timeout/error) so consumers can\n // reconcile local state without also listening on spawn:error.\n const childRunStats: ChildRunStats = {\n id,\n task,\n stats: finalStats!,\n depth: childDepth,\n status: childRunStatus,\n ...(finalStats!.output ? { output: finalStats!.output } : {}),\n }\n options.onComplete?.(child, finalStats!, childRunStatus)\n await ctx.hooks.callHook('spawn:complete', childRunStats)\n\n if (destroyError) {\n // Non-fatal but worth surfacing: a destroy failure leaves an\n // execution-handle / MCP connection in a weird state.\n await ctx.hooks.callHook('spawn:error', {\n id,\n task,\n depth: childDepth,\n error: destroyError,\n })\n }\n\n return result\n }\n finally {\n unbubble?.()\n localActiveCount--\n localChildren.delete(id)\n }\n },\n }\n}\n","import type { ToolContext, ToolDef } from './types'\nimport { Buffer } from 'node:buffer'\n\n/**\n * Write a file, with an idempotency signal when the content is unchanged.\n *\n * Three return shapes — chosen so the model can recognize a no-op without a\n * separate read:\n * - `Created path (N bytes)` — file did not exist\n * - `Updated path (N bytes)` — content differed from on-disk\n * - `No change needed: path already at target state (N bytes)` — equal\n *\n * Race window: in non-process execution contexts (docker, sandbox) shared by\n * multiple agents, another writer can mutate the file between our read and\n * our write. Local process context is single-writer per agent so the race is\n * a non-issue there. Documented rather than locked because the cost of\n * cross-context locking outweighs the cost of a stale \"No change\" message.\n */\n\nexport const writeFile: ToolDef = {\n spec: {\n name: 'write_file',\n description: 'Write content to a file (creates parent directories). Returns Created / Updated / \"No change needed\" so the model can detect no-ops without a separate read.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Relative file path.' },\n content: { type: 'string', description: 'File content.' },\n },\n required: ['path', 'content'],\n },\n },\n async execute({ path, content }, ctx: ToolContext) {\n const targetPath = path as string\n const targetContent = content as string\n\n let existing: string | undefined\n try {\n existing = await ctx.execution.readFile(ctx.handle, targetPath)\n }\n catch {\n // File does not exist (or read failed for unrelated reasons — we'll let\n // writeFile surface that error). Either way: treat as a fresh write.\n }\n\n const bytes = Buffer.byteLength(targetContent)\n\n if (existing === targetContent)\n return `No change needed: ${targetPath} already at target state (${bytes} bytes).`\n\n await ctx.execution.writeFile(ctx.handle, targetPath, targetContent)\n\n return existing === undefined\n ? `Created ${targetPath} (${bytes} bytes).`\n : `Updated ${targetPath} (${bytes} bytes).`\n },\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAgB,eACd,SACA,gBACW;CACX,MAAM,mCAAmB,IAAI,KAAqB;CAClD,MAAM,mCAAmB,IAAI,KAAqB;CAElD,IAAI,CAAC,SACH,OAAO;EAAE;EAAkB;EAAkB;CAG/C,MAAM,eAAe,IAAI,IAAI,eAAe;CAK5C,SAAS,eAAe,WAA4B;EAClD,MAAM,SAAS,QAAS;EACxB,OAAO,OAAO,WAAW,YAAY,OAAO,SAAS,KAAK,WAAW;;CAGvE,KAAK,MAAM,CAAC,WAAW,UAAU,OAAO,QAAQ,QAAQ,EAAE;EACxD,IAAI,OAAO,UAAU,YAAY,MAAM,WAAW,GAChD,MAAM,IAAI,MAAM,mBAAmB,UAAU,8BAA8B;EAE7E,IAAI,UAAU,WACZ;EAEF,IAAI,CAAC,aAAa,IAAI,UAAU,EAC9B;EAKF,IAAI,aAAa,IAAI,MAAM,IAAI,CAAC,eAAe,MAAM,EACnD,MAAM,IAAI,MAAM,eAAe,UAAU,QAAQ,MAAM,iDAAiD;EAG1G,MAAM,oBAAoB,iBAAiB,IAAI,MAAM;EACrD,IAAI,qBAAqB,sBAAsB,WAC7C,MAAM,IAAI,MACR,+BAA+B,kBAAkB,SAAS,UAAU,kBAAkB,MAAM,GAC7F;EAGH,iBAAiB,IAAI,WAAW,MAAM;EACtC,iBAAiB,IAAI,OAAO,UAAU;;CAGxC,OAAO;EAAE;EAAkB;EAAkB;;;AAI/C,SAAgB,WAAW,WAAmB,MAAyB;CACrE,OAAO,KAAK,iBAAiB,IAAI,UAAU,IAAI;;;AAIjD,SAAgB,gBAAgB,MAAc,MAAyB;CACrE,OAAO,KAAK,iBAAiB,IAAI,KAAK,IAAI;;;;;;AAO5C,SAAgB,qBACd,SACA,MACuB;CACvB,IAAI,KAAK,iBAAiB,SAAS,GACjC,OAAO;CACT,OAAO,QAAQ,KAAK,UAAU;EAC5B,IAAI,MAAM,SAAS,aACjB,OAAO;EACT,MAAM,OAAO,KAAK,iBAAiB,IAAI,MAAM,KAAK;EAClD,IAAI,CAAC,QAAQ,SAAS,MAAM,MAC1B,OAAO;EACT,OAAO;GAAE,GAAG;GAAO,MAAM;GAAM;GAC/B;;;;;;AAOJ,SAAgB,0BACd,SACA,MACuB;CACvB,IAAI,KAAK,iBAAiB,SAAS,GACjC,OAAO;CACT,OAAO,QAAQ,KAAK,UAAU;EAC5B,IAAI,MAAM,SAAS,aACjB,OAAO;EACT,MAAM,YAAY,KAAK,iBAAiB,IAAI,MAAM,KAAK;EACvD,IAAI,CAAC,aAAa,cAAc,MAAM,MACpC,OAAO;EACT,OAAO;GAAE,GAAG;GAAO,MAAM;GAAW;GACpC;;;;;;;AAQJ,SAAgB,sBACd,UACA,MACkB;CAClB,IAAI,KAAK,iBAAiB,SAAS,GACjC,OAAO;CACT,OAAO,SAAS,KAAI,SAAQ;EAAE,GAAG;EAAK,SAAS,qBAAqB,IAAI,SAAS,KAAK;EAAE,EAAE;;;;ACvG5F,MAAM,wBAAQ,IAAI,SAAgC;;;;;;AAOlD,SAAgB,aAAa,SAAwD;CACnF,IAAI,CAAC,SACH,OAAO,KAAA;CACT,IAAI,MAAM,MAAM,IAAI,QAAQ;CAC5B,IAAI,CAAC,KAAK;EACR,sBAAM,IAAI,KAAK;EACf,MAAM,IAAI,SAAS,IAAI;;CAEzB,OAAO;;AAgBT,MAAM,mCAAmB,IAAI,SAAgC;;;;;AAM7D,SAAgB,kBAAkB,SAAwD;CACxF,IAAI,CAAC,SACH,OAAO,KAAA;CACT,IAAI,MAAM,iBAAiB,IAAI,QAAQ;CACvC,IAAI,CAAC,KAAK;EACR,sBAAM,IAAI,KAAK;EACf,iBAAiB,IAAI,SAAS,IAAI;;CAEpC,OAAO;;;;;;;;AAST,SAAgB,YAAY,MAAsB;CAChD,IAAI,IAAI;CACR,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,KAAK,KAAK,WAAW,EAAE;EACvB,IAAK,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,SAAU;;CAExE,OAAO,EAAE,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI;;;;;;;;;;;;;;AC7DxC,SAAgB,sBACd,OACA,eACA,YACY;CAUZ,MAAM,0BAAU,IAAI,KAAqB;CAEzC,SAAS,WAAW,QAAgB,MAAsB;EACxD,OAAO,GAAG,OAAO,IAAI;;CAGvB,SAAS,YAAY,KAKlB;EAGD,IAAI,IAAI,SAAS,IAAI,WAAW,KAAA,GAC9B;EAGF,MAAM,SADa,eACM,GAAG,IAAI;EAChC,IAAI,CAAC,QACH;EAGF,MAAM,QAAQ,kBADE,YACuB,CAAC;EACxC,IAAI,CAAC,OACH;EAEF,IAAI;EACJ,IAAI;GACF,OAAO,OAAO,IAAI,MAAM;UAEpB;GAIJ;;EAEF,IAAI,OAAO,SAAS,YAAY,KAAK,WAAW,GAC9C;EAEF,MAAM,QAAQ,MAAM,IAAI,IAAI,KAAK;EACjC,IAAI,SAAS,MAAM,SAAS,MAAM;GAIhC,IAAI,SAAS,MAAM;GACnB;;EAIF,QAAQ,IAAI,WAAW,IAAI,QAAQ,IAAI,KAAK,EAAE,KAAK;;CAGrD,SAAS,aAAa,KAGnB;EACD,MAAM,MAAM,WAAW,IAAI,QAAQ,IAAI,KAAK;EAC5C,MAAM,OAAO,QAAQ,IAAI,IAAI;EAC7B,IAAI,SAAS,KAAA,GACX;EACF,QAAQ,OAAO,IAAI;EAGnB,MAAM,QAAQ,kBADE,YACuB,CAAC;EACxC,IAAI,CAAC,OACH;EAEF,MAAM,IAAI,IAAI,MAAM;GAAE;GAAM,QAAQ,IAAI;GAAQ,CAAC;;CAGnD,MAAM,iBAAiB,MAAM,KAAK,aAAa,YAAY;CAC3D,MAAM,kBAAkB,MAAM,KAAK,cAAc,aAAa;CAE9D,OAAO,SAAS,YAAY;EAC1B,gBAAgB;EAChB,iBAAiB;EACjB,QAAQ,OAAO;;;;;AC5FnB,MAAM,eAAe,IAAI,IAAI;CAAC;CAAQ;CAAQ;CAAQ;CAAK;CAAO;CAAO;CAAM,CAAC;AAChF,MAAM,gBAAgB,IAAI,IAAI;CAAC;CAAS;CAAS;CAAS;CAAK;CAAM;CAAM;CAAK,CAAC;AAEjF,SAAgB,iBACd,OACA,QACkB;CAClB,MAAM,WAAY,OAAO,YAAY,EAAE;CACvC,MAAM,aAAc,OAAO,cAAc,EAAE;CAG3C,KAAK,MAAM,SAAS,UAClB,IAAI,EAAE,SAAS,UAAU,MAAM,WAAW,KAAA,KAAa,MAAM,WAAW,MACtE,OAAO;EAAE,OAAO;EAAO,OAAO,2BAA2B;EAAS;CAMtE,IAAI;CACJ,MAAM,YAAsB,EAAE;CAE9B,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,EAAE;EAChD,MAAM,aAAa,WAAW;EAC9B,IAAI,CAAC,YAAY,MACf;EACF,IAAI,UAAU,KAAA,KAAa,UAAU,MACnC;EAEF,MAAM,UAAU,YAAY,OAAO,WAAW;EAC9C,IAAI,QAAQ,OACV,OAAO;GAAE,OAAO;GAAO,OAAO,UAAU,IAAI,KAAK,QAAQ;GAAS;EAEpE,IAAI,QAAQ,SAAS;GACnB,IAAI,CAAC,SACH,UAAU,EAAE,GAAG,OAAO;GACxB,QAAQ,OAAO,QAAQ;GACvB,UAAU,KAAK,IAAI;;;CAIvB,OAAO;EACL,OAAO;EACP,cAAc,WAAW;EACzB;EACD;;AAUH,SAAS,YAAY,OAAgB,QAAuC;CAC1E,MAAM,gBAAgB,MAAM,QAAQ,OAAO,KAAK,GAC5C,OAAO,OACP,CAAC,OAAO,KAAe;CAG3B,KAAK,MAAM,KAAK,eACd,IAAI,YAAY,OAAO,EAAE,EAAE;EACzB,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,SAAS,MAAM,EAC7C,OAAO;GACL;GACA,SAAS;GACT,OAAO,kBAAkB,KAAK,UAAU,OAAO,KAAK,CAAC,QAAQ,YAAY,MAAM;GAChF;EAEH,OAAO;GAAE;GAAO,SAAS;GAAO;;CAKpC,KAAK,MAAM,KAAK,eAAe;EAC7B,MAAM,UAAU,UAAU,OAAO,EAAE;EACnC,IAAI,QAAQ,IAAI;GACd,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,SAAS,QAAQ,MAAM,EACrD,OAAO;IACL;IACA,SAAS;IACT,OAAO,kBAAkB,KAAK,UAAU,OAAO,KAAK,CAAC,QAAQ,YAAY,QAAQ,MAAM;IACxF;GAEH,OAAO;IAAE,OAAO,QAAQ;IAAO,SAAS;IAAM;;;CAKlD,OAAO;EACL;EACA,SAAS;EACT,OAAO,YAJQ,cAAc,KAAK,MAIP,CAAC,QAAQ,SAAS,MAAM,CAAC,GAAG,YAAY,MAAM;EAC1E;;AAGH,SAAS,YAAY,OAAgB,MAAuB;CAC1D,QAAQ,MAAR;EACE,KAAK,UAAU,OAAO,OAAO,UAAU;EACvC,KAAK,UAAU,OAAO,OAAO,UAAU,YAAY,OAAO,SAAS,MAAM;EACzE,KAAK,WAAW,OAAO,OAAO,UAAU,YAAY,OAAO,UAAU,MAAM;EAC3E,KAAK,WAAW,OAAO,OAAO,UAAU;EACxC,KAAK,SAAS,OAAO,MAAM,QAAQ,MAAM;EACzC,KAAK,UAAU,OAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM;EAC1F,KAAK,QAAQ,OAAO,UAAU;EAC9B,SAAS,OAAO;;;AAIpB,SAAS,UAAU,OAAgB,MAA4D;CAE7F,IAAI,OAAO,UAAU,UAAU;EAC7B,IAAI,SAAS,WAAW;GACtB,MAAM,UAAU,MAAM,MAAM;GAC5B,IAAI,aAAa,IAAI,QAAQ,EAC3B,OAAO;IAAE,IAAI;IAAM,OAAO;IAAM;GAClC,IAAI,cAAc,IAAI,QAAQ,EAC5B,OAAO;IAAE,IAAI;IAAM,OAAO;IAAO;GACnC,OAAO,EAAE,IAAI,OAAO;;EAEtB,IAAI,SAAS,UAAU;GACrB,MAAM,IAAI,OAAO,MAAM,MAAM,CAAC;GAC9B,OAAO,OAAO,SAAS,EAAE,GAAG;IAAE,IAAI;IAAM,OAAO;IAAG,GAAG,EAAE,IAAI,OAAO;;EAEpE,IAAI,SAAS,WAAW;GACtB,MAAM,IAAI,OAAO,MAAM,MAAM,CAAC;GAC9B,OAAO,OAAO,UAAU,EAAE,GAAG;IAAE,IAAI;IAAM,OAAO;IAAG,GAAG,EAAE,IAAI,OAAO;;EAErE,IAAI,SAAS,WAAW,SAAS,UAC/B,IAAI;GACF,MAAM,SAAS,KAAK,MAAM,MAAM;GAChC,IAAI,SAAS,WAAW,MAAM,QAAQ,OAAO,EAC3C,OAAO;IAAE,IAAI;IAAM,OAAO;IAAQ;GACpC,IAAI,SAAS,YAAY,WAAW,QAAQ,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,OAAO,EAC9F,OAAO;IAAE,IAAI;IAAM,OAAO;IAAQ;GACpC,OAAO,EAAE,IAAI,OAAO;UAEhB;GACJ,OAAO,EAAE,IAAI,OAAO;;EAGxB,IAAI,SAAS,QACX,OAAO,UAAU,MAAM,UAAU,SAAS;GAAE,IAAI;GAAM,OAAO;GAAM,GAAG,EAAE,IAAI,OAAO;;CAKvF,IAAI,OAAO,UAAU,YAAY,OAAO,SAAS,MAAM,EAAE;EACvD,IAAI,SAAS,UACX,OAAO;GAAE,IAAI;GAAM,OAAO,OAAO,MAAM;GAAE;EAC3C,IAAI,SAAS,aAAa,OAAO,UAAU,MAAM,EAC/C,OAAO;GAAE,IAAI;GAAM;GAAO;;CAI9B,IAAI,OAAO,UAAU,aAAa,SAAS,UACzC,OAAO;EAAE,IAAI;EAAM,OAAO,OAAO,MAAM;EAAE;CAE3C,OAAO,EAAE,IAAI,OAAO;;AAGtB,SAAS,SAAS,OAAwB;CACxC,IAAI,UAAU,MACZ,OAAO;CACT,IAAI,MAAM,QAAQ,MAAM,EACtB,OAAO;CACT,OAAO,OAAO;;AAGhB,SAAS,YAAY,OAAwB;CAC3C,IAAI;CACJ,IAAI;EACF,IAAI,KAAK,UAAU,MAAM;SAErB;EACJ,IAAI,OAAO,MAAM;;CAEnB,IAAI,MAAM,KAAA,GACR,IAAI,OAAO,MAAM;CACnB,OAAO,EAAE,SAAS,KAAK,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,OAAO;;;;AC/GlD,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;AAmB7B,SAAgB,mBACd,YACA,OACA,MACoB;CACpB,IAAI,OAAO,eAAe,YAAY,cAAc,GAClD,OAAO;CACT,IAAI,CAAC,OACH,OAAO;CAET,IAAI;CACJ,IAAI,OAAO,UAAU,YACnB,MAAM,MAAM,MAAM,WAAW;MAE1B;EACH,IAAI,QAAQ,MAAM,WAChB,OAAO;EACT,MAAM,IAAI,OAAO,MAAM;EACvB,MAAM,KAAK,IAAI,MAAM,OAAO,aAAa,MAAM,UAAU,EAAE;;CAO7D,IAAI,OAAO,MAAM,IAAI,IAAI,OAAO,GAC9B,OAAO;CACT,OAAO,KAAK,MAAM,KAAK,IAAI,YAAY,IAAI,CAAC;;;AAI9C,SAAS,gBAAgB,OAAwC;CAC/D,OAAO,MACJ,QAAQ,MAAyD,EAAE,SAAS,SAAS,CACrF,KAAI,OAAM;EAAE,MAAM,EAAE;EAAM,SAAS,EAAE;EAAS,EAAE;;;;;;;;;;;;;;;;;;AAmBrD,MAAM,kBAAkB;;;;;;;;;;;;;;;;;AAkBxB,SAAgB,oBACd,UACA,WACA,WACkB;CAClB,IAAI,SAAS,WAAW,GACtB,OAAO;CAET,IAAI,aAAa;CACjB,KAAK,MAAM,OAAO,UAChB,KAAK,MAAM,SAAS,IAAI,SACtB,IAAI,MAAM,SAAS,eACjB,cAAc,qBAAqB,MAAM,OAAO;CAGtD,IAAI,cAAc,WAChB,OAAO;CAKT,MAAM,OAAO,KAAK,IAAI,GAAG,UAAU;CACnC,MAAM,SAAS,SAAS,SAAS;CACjC,IAAI,UAAU,GACZ,OAAO;CAET,IAAI,UAAU;CACd,MAAM,MAAM,SAAS,OAAO;CAC5B,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAAK;EAC/B,MAAM,MAAM,IAAI;EAChB,IAAI,aAAa;EACjB,MAAM,aAAa,IAAI,QAAQ,KAAK,UAAU;GAC5C,IAAI,MAAM,SAAS,eACjB,OAAO;GAGT,IADsB,qBAAqB,MAAM,OAChC,IAAI,IACnB,OAAO;GACT,aAAa;GACb,UAAU;GACV,OAAO;IAAE,GAAG;IAAO,QAAQ;IAAiB;IAC5C;EACF,IAAI,YACF,IAAI,KAAK;GAAE,GAAG;GAAK,SAAS;GAAY;;CAE5C,OAAO,UAAU,MAAM;;;;;;;;;;;;;;;;;;;AAoBzB,MAAa,kBAAkB;AAE/B,SAAgB,sBAAsB,UAA8C;CAClF,IAAI,SAAS,WAAW,GACtB,OAAO;CAGT,MAAM,iCAAiB,IAAI,KAAqB;CAChD,KAAK,MAAM,OAAO,UAChB,KAAK,MAAM,SAAS,IAAI,SACtB,IAAI,MAAM,SAAS,iBAAiB,OAAO,MAAM,WAAW,UAC1D,eAAe,IAAI,MAAM,QAAQ,MAAM,OAAO;CAOpD,MAAM,uCAAuB,IAAI,KAAqB;CAEtD,MAAM,+BAAe,IAAI,KAA+C;CAExE,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KACnC,KAAK,MAAM,SAAS,SAAS,GAAG,SAAS;EACvC,IAAI,MAAM,SAAS,aACjB;EACF,MAAM,OAAQ,MAAM,MAA6B;EACjD,IAAI,OAAO,SAAS,UAClB;EAEF,IAAI,MAAM,SAAS,aAAa;GAC9B,aAAa,IAAI,MAAM,IAAI;IAAE;IAAM,QAAQ;IAAG,CAAC;GAC/C;;EAGF,MAAM,SAAS,MAAM,SAAS,UAAU,MAAM,SAAS;EACvD,MAAM,UAAU,MAAM,SAAS;EAC/B,IAAI,CAAC,UAAU,CAAC,SACd;EAEF,MAAM,SAAS,eAAe,IAAI,MAAM,GAAG;EAC3C,IAAI,OAAO,WAAW,UACpB;EAQF,IAAI,EAHc,SACd,OAAO,WAAW,UAAU,GAC3B,OAAO,WAAW,WAAW,IAAI,OAAO,WAAW,WAAW,GAEjE;EAEF,MAAM,QAAQ,qBAAqB,IAAI,KAAK;EAC5C,IAAI,UAAU,KAAA,KAAa,IAAI,OAC7B,qBAAqB,IAAI,MAAM,EAAE;;CAIvC,IAAI,qBAAqB,SAAS,GAChC,OAAO;CAGT,MAAM,+BAAe,IAAI,KAAa;CACtC,KAAK,MAAM,CAAC,QAAQ,SAAS,cAAc;EACzC,MAAM,kBAAkB,qBAAqB,IAAI,KAAK,KAAK;EAC3D,IAAI,OAAO,oBAAoB,YAAY,KAAK,SAAS,iBACvD,aAAa,IAAI,OAAO;;CAG5B,IAAI,aAAa,SAAS,GACxB,OAAO;CAET,IAAI,UAAU;CACd,MAAM,MAAM,SAAS,OAAO;CAC5B,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;EACnC,MAAM,MAAM,IAAI;EAChB,IAAI,aAAa;EACjB,MAAM,aAAa,IAAI,QAAQ,KAAK,UAAU;GAC5C,IAAI,MAAM,SAAS,iBAAiB,CAAC,aAAa,IAAI,MAAM,OAAO,EACjE,OAAO;GAIT,IAAI,MAAM,WAAA,sEACR,OAAO;GACT,aAAa;GACb,UAAU;GACV,OAAO;IAAE,GAAG;IAAO,QAAQ;IAAiB;IAC5C;EACF,IAAI,YACF,IAAI,KAAK;GAAE,GAAG;GAAK,SAAS;GAAY;;CAE5C,OAAO,UAAU,MAAM;;AAGzB,SAAS,0BACP,UACA,UACkB;CAClB,IAAI,SAAS,KAAK,cAAc,WAAW,OACzC,OAAO;CAET,OAAO,SAAS,KAAK,QAAQ;EAC3B,IAAI,UAAU;EACd,MAAM,aAAa,IAAI,QAAQ,KAAK,UAAU;GAC5C,IAAI,MAAM,SAAS,iBAAiB,OAAO,MAAM,WAAW,UAC1D,OAAO;GACT,UAAU;GACV,MAAM,YAAY,MAAM,OACrB,KAAI,MAAK,EAAE,SAAS,UAAU,uBAAuB,EAAE,KAAK,CAC5D,KAAK,KAAK;GACb,OAAO;IAAE,GAAG;IAAO,QAAQ;IAAW;IACtC;EACF,OAAO,UAAU;GAAE,GAAG;GAAK,SAAS;GAAY,GAAG;GACnD;;AAGJ,eAAsB,QAAQ,KAAuC;CACnE,IAAI,UAAU;CACd,IAAI,WAAW;CACf,IAAI,iBAAiB;CACrB,IAAI,qBAAqB;CACzB,MAAM,aAA0B,EAAE;CAClC,MAAM,YAAY,KAAK,KAAK;CAG5B,MAAM,WAAW,IAAI,YAAY,OAAO;CACxC,IAAI,iBAAiB;CAIrB,MAAM,OAAO,EAAE,MAAM,KAAA,GAAiC;CACtD,MAAM,iBAAiB;EACrB,IAAI,KAAK,SAAS,KAAA,GAChB,KAAK,OAAO,KAAK,KAAK,GAAG,IAAI;;CAEjC,MAAM,qBAAqB,IAAI,MAAM,KAAK,eAAe,SAAS;CAClE,MAAM,yBAAyB,IAAI,MAAM,KAAK,mBAAmB,SAAS;CAC1E,MAAM,qBAAqB,IAAI,MAAM,KAAK,eAAe,SAAS;CAElE,IAAI;EACF,KAAK,IAAI,OAAO,GAAG,OAAO,UAAU,QAAQ;GAC1C,IAAI,IAAI,OAAO,SAAS;IACtB,MAAM,IAAI,MAAM,SAAS,eAAe,EAAE,CAAC;IAC3C;;GAGF,MAAM,SAAS,MAAM,YAAY,KAAK,KAAK;GAC3C,iBAAiB,OAAO;GAExB,WAAW,OAAO,MAAM;GACxB,YAAY,OAAO,MAAM;GACzB,kBAAkB,OAAO,MAAM,aAAa;GAC5C,sBAAsB,OAAO,MAAM,iBAAiB;GACpD,WAAW,KAAK,OAAO,MAAM;GAE7B,MAAM,IAAI,MAAM,SAAS,SAAS;IAAE;IAAM,QAAQ,OAAO;IAAQ,OAAO,OAAO;IAAO;IAAS;IAAU,CAAC;GAG1G,IAAI,IAAI,OAAO,SAAS;IACtB,MAAM,IAAI,MAAM,SAAS,eAAe,EAAE,CAAC;IAC3C;;GAIF,IAAI,IAAI,cAAc,SAAS,GAAG;IAChC,MAAM,WAAW,IAAI,cAAc,OAAO;IAC1C,MAAM,IAAI,MAAM,SAAS,gBAAgB,EAAE,SAAS,UAAU,CAAC;IAC/D,MAAM,eAAe,IAAI,SAAS,YAAY,SAAS;IACvD,IAAI,MAAM,KAAK;KACb,IAAI,MAAM,IAAI,gBAAgB;KAC9B,OAAO,IAAI;KACX,MAAM,aAAa;KACnB,SAAS,aAAa;KACtB,WAAW,KAAK,KAAK;KACtB,CAAC;IACF;;GAGF,IAAI,OAAO,OAAO;IAEhB,IAAI,IAAI,cAAc,SAAS,GAAG;KAChC,MAAM,WAAW,IAAI,cAAc,OAAO;KAC1C,MAAM,IAAI,MAAM,SAAS,gBAAgB,EAAE,SAAS,UAAU,CAAC;KAC/D,MAAM,cAAc,IAAI,SAAS,YAAY,SAAS;KACtD,IAAI,MAAM,KAAK;MACb,IAAI,MAAM,IAAI,gBAAgB;MAC9B,OAAO,IAAI;MACX,MAAM,YAAY;MAClB,SAAS,YAAY;MACrB,WAAW,KAAK,KAAK;MACtB,CAAC;KACF;;IAGF,OAAO;KACL;KACA;KACA;KACA;KACA,OAAO,OAAO;KACd,SAAS,KAAK,KAAK,GAAG;KACtB,WAAW;KACX,QAAQ,OAAO;KACf,GAAI,KAAK,SAAS,KAAA,IAAY,EAAE,sBAAsB,KAAK,MAAM,GAAG,EAAE;KACvE;;;EAIL,OAAO;GACL;GACA;GACA;GACA;GACA,OAAO;GACP,SAAS,KAAK,KAAK,GAAG;GACtB,WAAW;GACX,GAAI,KAAK,SAAS,KAAA,IAAY,EAAE,sBAAsB,KAAK,MAAM,GAAG,EAAE;GACvE;WAEK;EACN,oBAAoB;EACpB,wBAAwB;EACxB,oBAAoB;;;;;;;;;;AAsBxB,SAAS,kBAAkB,KAAc,KAAyB;CAChE,IAAI,IAAI,OAAO,WAAY,eAAe,SAAS,IAAI,SAAS,cAC9D,OAAO,IAAI,kBAAkB,qBAAqB,EAAE,OAAO,KAAK,CAAC;CAEnE,MAAM,iBAAiB,IAAI,SAAS,gBAAgB,IAAI;CACxD,IAAI,gBACF,OAAO,aAAa,gBAAgB,IAAI,SAAS,MAAM,IAAI;CAG7D,OAAO,IAAI,mBADK,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,EACzB;EAAE,UAAU,IAAI,SAAS;EAAM,OAAO;EAAK,CAAC;;AAGrF,eAAe,YAAY,KAAkB,MAAmC;CAE9E,MAAM,SAAS,MAAM,IAAI,gBAAgB;CAIzC,IAAI,oBAAoB,gBAAgB,IAAI,MAAM;CAOlD,IAAI,IAAI,oBAAoB,MAC1B,oBAAoB,sBAAsB,kBAAkB;CAE9D,MAAM,eAAe,sBAAsB,mBAAmB,IAAI,UAAU;CAI5E,IAAI,oBAAoB,0BAA0B,IAAI,UAAU,aAAa;CAM7E,IAAI,IAAI,oBAAoB,QAAQ;EAClC,MAAM,YAAY,OAAO,IAAI,qBAAqB,YAAY,IAAI,mBAAmB,IACjF,IAAI,mBACJ;EACJ,MAAM,OAAO,OAAO,IAAI,qBAAqB,YAAY,IAAI,oBAAoB,IAC7E,IAAI,mBACJ;EACJ,oBAAoB,oBAAoB,mBAAmB,WAAW,KAAK;;CAG7E,MAAM,0BAA0B,mBAAmB,IAAI,gBAAgB,IAAI,eAAe,KAAK;CAO/F,MAAM,iBAAiB,IAAI,wBACvB,IAAI,uBAAuB,GAC3B,IAAI;CAER,MAAM,gBAA+B;EACnC,OAAO,IAAI;EACX,QAAQ,IAAI;EACZ,OAAO;EACP,UAAU;EACV,WAAW,IAAI,aAAa;EAC5B,UAAU,IAAI;EACd,gBAAgB;EAChB,OAAO,IAAI,SAAS;EACpB,QAAQ,IAAI;EACb;CAKD,MAAM,eAAe,EAAE,UAAU,cAAc,UAAU;CACzD,MAAM,IAAI,MAAM,SAAS,qBAAqB,aAAa;CAC3D,cAAc,WAAW,aAAa;CAMtC,MAAM,YAMF;EACF,QAAQ,cAAc;EACtB,UAAU,cAAc;EACxB;EACA;EACA,GAAI,IAAI,UAAU,EAAE,SAAS,IAAI,SAAS,GAAG,EAAE;EAChD;CACD,MAAM,IAAI,MAAM,SAAS,oBAAoB,UAAU;CACvD,cAAc,SAAS,UAAU;CAEjC,MAAM,IAAI,MAAM,SAAS,eAAe;EAAE;EAAM;EAAQ,SAAS;EAAe,CAAC;CAEjF,IAAI,cAAc;CAClB,IAAI,kBAAkB;CAEtB,IAAI;CACJ,IAAI;EACF,SAAS,MAAM,IAAI,SAAS,OAC1B,eACA;GACE,OAAO,OAAO;IACZ,eAAe;IACf,IAAI,MAAM,SAAS,eAAe;KAAE;KAAO,MAAM;KAAa;KAAQ,CAAC;;GAEzE,WAAW,OAAO;IAChB,mBAAmB;IACnB,IAAI,MAAM,SAAS,mBAAmB;KAAE;KAAO,UAAU;KAAiB;KAAQ,CAAC;;GAErF,eAAe,YAAY;IACzB,OAAO,IAAI,MAAM,SAAS,iBAAiB,WAAW;;GAEzD,CACF;UAEI,KAAK;EAQV,MAAM,aAAwB;GAAE,OAAO;GAAG,QAAQ;GAAG;EACrD,MAAM,eAAe,cACjB,CAAC;GAAE,MAAM;GAAiB,MAAM;GAAa,CAAC,GAC9C,CAAC;GAAE,MAAM;GAAiB,MAAM;GAAsC,CAAC;EAC3E,MAAM,YAAyB;GAC7B,IAAI;GACJ,OAAO,IAAI;GACX,MAAM;GACN,SAAS;GACT,OAAO;GACP,WAAW,KAAK,KAAK;GACtB;EACD,IAAI,MAAM,KAAK,UAAU;EACzB,MAAM,IAAI,MAAM,SAAS,cAAc;GACrC;GACA;GACA,OAAO;GACP,SAAS;GACT,YAAY;IAAE,MAAM,OAAO,OAAO,EAAE,CAAC;IAAE,KAAK,OAAO,OAAO,EAAE,GAAG,IAAI,eAAe,CAAC;IAAE;GACtF,CAAC;EACF,MAAM,kBAAkB,KAAK,IAAI;;CAGnC,IAAI,aACF,MAAM,IAAI,MAAM,SAAS,cAAc;EAAE,MAAM;EAAa;EAAQ,CAAC;CAKvE,MAAM,qBAAqB,OAAO,UAAU,KAAI,QAAO;EACrD,GAAG;EACH,MAAM,gBAAgB,GAAG,MAAM,IAAI,UAAU;EAC9C,EAAE;CACH,MAAM,mBAAmB,0BACvB,OAAO,kBAAkB,WAAW,EAAE,EACtC,IAAI,UACL;CAGD,MAAM,gBAA6B;EACjC,IAAI;EACJ,OAAO,IAAI;EACX,MAAM;EACN,SAAS,OAAO,OACX,iBAAiB,SAAS,IAAI,mBAAmB,CAAC;GAAE,MAAM;GAAQ,MAAM;GAAa,CAAC,GACvF;EACJ,OAAO,OAAO;EACd,WAAW,KAAK,KAAK;EACtB;CACD,IAAI,MAAM,KAAK,cAAc;CAM7B,MAAM,aAAqC,EAAE;CAC7C,KAAK,MAAM,MAAM,oBACf,WAAW,GAAG,SAAS,WAAW,GAAG,SAAS,KAAK;CAErD,MAAM,IAAI,MAAM,SAAS,cAAc;EACrC;EACA;EACA,OAAO,OAAO;EACd,SAAS;EACT,YAAY;GAAE,MAAM,OAAO,OAAO,WAAW;GAAE,KAAK,OAAO,OAAO,EAAE,GAAG,IAAI,eAAe,CAAC;GAAE;EAC9F,CAAC;CAEF,IAAI,OAAO,MAAM;EAEf,IAAI,IAAI,UAAU,CAAC,IAAI,OAAO,SAAS;GACrC,MAAM,aAAuB;IAC3B,MAAM;IACN,aAAa;IACb,aAAa,IAAI;IAClB;GACD,MAAM,iBAAiB,sBAAsB,gBAAgB,IAAI,MAAM,EAAE,IAAI,UAAU;GACvF,IAAI;GACJ,IAAI;IACF,eAAe,MAAM,IAAI,SAAS,OAChC;KACE,OAAO,IAAI;KACX,QAAQ,IAAI;KACZ,OAAO,IAAI,SAAS,YAAY,CAAC,WAAW,CAAC;KAC7C,UAAU;KACV,WAAW,IAAI,aAAa;KAC5B,QAAQ,IAAI;KACZ,YAAY;MAAE,MAAM;MAAQ,MAAM;MAAc;KACjD,EACD;KACE,cAAc;KACd,eAAe,YAAY;MACzB,OAAO,IAAI,MAAM,SAAS,iBAAiB,WAAW;;KAEzD,CACF;YAEI,KAAK;IACV,MAAM,kBAAkB,KAAK,IAAI;;GAGnC,MAAM,SAAS,aAAa,UAAU,MAAK,OAAM,GAAG,SAAS,aAAa,EAAE;GAE5E,IAAI,QACF,MAAM,IAAI,MAAM,SAAS,UAAU;IAAE;IAAQ,QAAQ,IAAI;IAAQ,CAAC;GAGpE,MAAM,aAA0B;IAC9B,IAAI,MAAM,IAAI,gBAAgB;IAC9B,OAAO,IAAI;IACX,MAAM;IACN,SAAS,aAAa,iBAAiB;IACvC,OAAO,aAAa;IACpB,WAAW,KAAK,KAAK;IACtB;GACD,IAAI,MAAM,KAAK,WAAW;GAE1B,OAAO;IACL,OAAO;IACP;IACA,OAAO;KACL,OAAO,OAAO,MAAM,QAAQ,aAAa,MAAM;KAC/C,QAAQ,OAAO,MAAM,SAAS,aAAa,MAAM;KAClD;IACD;IACD;;EAGH,OAAO;GAAE,OAAO;GAAM;GAAQ,OAAO,OAAO;GAAO;;CASrD,IAAI,mBAAmB,WAAW,KAAK,OAAO,MAAM,iBAAiB,SAAS;EAC5E,MAAM,cAAc,IAAI,SAAS,YAAY,mBAAmB;EAChE,IAAI,MAAM,KAAK;GACb,IAAI,MAAM,IAAI,gBAAgB;GAC9B,OAAO,IAAI;GACX,MAAM,YAAY;GAClB,SAAS,YAAY;GACrB,WAAW,KAAK,KAAK;GACtB,CAAC;EACF,OAAO;GAAE,OAAO;GAAO;GAAQ,OAAO,OAAO;GAAO;;CAItD,MAAM,cAAc,IAAI,kBAAkB,aACtC,MAAM,qBAAqB,KAAK,oBAAoB,OAAO,GAC3D,MAAM,uBAAuB,KAAK,oBAAoB,OAAO;CAGjE,MAAM,gBAAgB,IAAI,SAAS,mBAAmB,YAAY;CAClE,IAAI,MAAM,KAAK;EACb,IAAI,MAAM,IAAI,gBAAgB;EAC9B,OAAO,IAAI;EACX,MAAM,cAAc;EACpB,SAAS,cAAc;EACvB,WAAW,KAAK,KAAK;EACtB,CAAC;CAKF,IAAI,OAAO,IAAI,qBAAqB,YAAY,IAAI,mBAAmB,GAAG;EACxE,MAAM,aAAa,YAAY,QAC5B,KAAK,MAAM,MAAM,qBAAqB,EAAE,QAAQ,EACjD,EACD;EACD,IAAI,aAAa,IAAI,kBAAkB;GACrC,MAAM,UAAU,iCAAiC,WAAW,qCAAqC,IAAI,iBAAiB;GACtH,MAAM,UAAU,IAAI,SAAS,YAAY,QAAQ;GACjD,IAAI,MAAM,KAAK;IACb,IAAI,MAAM,IAAI,gBAAgB;IAC9B,OAAO,IAAI;IACX,MAAM,QAAQ;IACd,SAAS,QAAQ;IACjB,WAAW,KAAK,KAAK;IACtB,CAAC;GACF,MAAM,IAAI,MAAM,SAAS,mBAAmB;IAC1C;IACA;IACA,OAAO;IACP,QAAQ,IAAI;IACb,CAAC;;;CAIN,OAAO;EAAE,OAAO;EAAO;EAAQ,OAAO,OAAO;EAAO;;;;;;;;;;;;;;;;;AAsBtD,SAAS,wBACP,UACA,QAC8B;CAC9B,IAAI,OAAO,WAAW,UACpB,OAAO;CACT,IAAI,SAAS,KAAK,cAAc,WAAW,OACzC,OAAO;CAET,OAAO,OACJ,KAAI,MAAK,EAAE,SAAS,UAAU,uBAAuB,EAAE,KAAK,CAC5D,KAAK,KAAK;;AAGf,eAAe,kBACb,KACA,MACA,QACiC;CACjC,MAAM,UAAU,IAAI,MAAM,KAAK;CAC/B,MAAM,SAAS,KAAK;CACpB,MAAM,cAAc,WAAW,KAAK,MAAM,IAAI,UAAU;CAMxD,MAAM,gBAAkD,OAAO,OAAO,EAAE,GAAG,IAAI,eAAe,CAAC;CAK/F,MAAM,UAUF;EACF;EACA;EACA,MAAM,KAAK;EACX;EACA,OAAO,KAAK;EACZ,OAAO;EACP,QAAQ;EACR;EACD;CACD,MAAM,IAAI,MAAM,SAAS,aAAa,QAAQ;CAY9C,IAAI,QAAQ,OAIV,OAAO,EAAE,QAAQ;EAAE,IAAI;EAAQ,SAAS,YAAY,QAAQ;EAAU,EAAE;CAK1E,IAAI,cAAc,KAAK,SAAS,IAAI,cAAc,KAAK,SAAS,KAAK;CAMrE,IAAI,QAAQ,WAAW,KAAA,GAWrB,OAAO,EAAE,QAAQ;EAAE,IAAI;EAAQ,SAAS,MAVf,eAAe,KAAK;GAC3C;GACA;GACA,MAAM,KAAK;GACX;GACA,OAAO,QAAQ;GACf,QAAQ,QAAQ;GAChB,SAAS;GACT;GACD,CAAC;EACkD,EAAE;CAIxD,IAAI,iBAAiB,QAAQ;CAE7B,IAAI,CAAC,SAAS;EAKZ,MAAM,aAQF;GACF;GACA;GACA,MAAM,KAAK;GACX;GACA,OAAO;GACP,eAAe;GAChB;EACD,MAAM,IAAI,MAAM,SAAS,gBAAgB,WAAW;EAEpD,MAAM,UAAU,WAAW,UAAU,6BAA6B,KAAK;EAEvE,IAAI,CAAC,WAAW,eAAe;GAC7B,MAAM,sBAAM,IAAI,MAAM,iBAAiB,KAAK,OAAO;GACnD,MAAM,IAAI,MAAM,SAAS,cAAc;IACrC;IACA;IACA,MAAM,KAAK;IACX;IACA,OAAO;IACP,OAAO;IACR,CAAC;;EAEJ,OAAO,EAAE,QAAQ;GAAE,IAAI;GAAQ;GAAS,EAAE;;CAK5C,MAAM,aAAa,iBAAiB,gBAAgB,QAAQ,KAAK,YAAY;CAC7E,IAAI,CAAC,WAAW,OAAO;EACrB,MAAM,IAAI,MAAM,SAAS,qBAAqB;GAC5C;GACA;GACA,MAAM,KAAK;GACX;GACA,OAAO;GACP,QAAQ,WAAW,SAAS;GAC5B,QAAQ,QAAQ,KAAK;GACtB,CAAC;EACF,OAAO,EAAE,QAAQ;GAAE,IAAI;GAAQ,SAAS,qBAAqB,WAAW;GAAS,EAAE;;CAGrF,iBAAiB,WAAW,gBAAgB;CAK5C,MAAM,YAAY,WAAW,aAAa,WAAW,UAAU,SAAS,IACpE,WAAW,YACX,KAAA;CACJ,IAAI,WACF,MAAM,IAAI,MAAM,SAAS,qBAAqB;EAC5C;EACA;EACA,MAAM,KAAK;EACX;EACA,OAAO;EACP;EACA,QAAQ,QAAQ,KAAK;EACtB,CAAC;CAGJ,MAAM,IAAI,MAAM,SAAS,eAAe;EACtC;EACA;EACA,MAAM,KAAK;EACX;EACA,OAAO;EACP;EACA,GAAI,YAAY,EAAE,WAAW,GAAG,EAAE;EACnC,CAAC;CAEF,IAAI;CACJ,IAAI,UAAU;CAEd,IAAI;EACF,MAAM,UAAuB;GAC3B,UAAU,IAAI;GACd,QAAQ,IAAI;GACZ,WAAW,IAAI;GACf,QAAQ,IAAI;GACZ,OAAO,IAAI;GACX,OAAO,IAAI;GACX,GAAI,IAAI,cAAc,KAAA,IAAY,EAAE,MAAM,IAAI,WAAW,GAAG,EAAE;GAC9D,GAAI,IAAI,gBAAgB,KAAA,IAAY,EAAE,QAAQ,IAAI,aAAa,GAAG,EAAE;GACpE,GAAI,IAAI,qBAAqB,KAAA,IAAY,EAAE,aAAa,IAAI,kBAAkB,GAAG,EAAE;GACnF,GAAI,IAAI,oBAAoB,KAAA,IAAY,EAAE,YAAY,IAAI,iBAAiB,GAAG,EAAE;GAChF,GAAI,IAAI,gBAAgB,KAAA,IAAY,EAAE,QAAQ,IAAI,aAAa,GAAG,EAAE;GACpE,GAAI,IAAI,kBAAkB,KAAA,IAAY,EAAE,UAAU,IAAI,eAAe,GAAG,EAAE;GAC1E;GACA;GACA,OAAO,IAAI;GACX,GAAI,IAAI,UAAU,EAAE,SAAS,IAAI,SAAS,GAAG,EAAE;GAC/C,GAAI,OAAO,IAAI,UAAU,WAAW,EAAE,OAAO,IAAI,OAAO,GAAG,EAAE;GAC9D;EACD,SAAS,MAAM,QAAQ,QAAQ,gBAAgB,QAAQ;UAElD,KAAK;EACV,MAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC;EAIjE,MAAM,WAQF;GACF;GACA;GACA,MAAM,KAAK;GACX;GACA,OAAO;GACP;GACD;EACD,MAAM,IAAI,MAAM,SAAS,cAAc,SAAS;EAChD,SAAS,SAAS,UAAU,eAAe,MAAM;EACjD,UAAU;;CAeZ,OAAO,EAAE,QAAQ;EAAE,IAAI;EAAQ,SAAS,MAZd,eAAe,KAAK;GAC5C;GACA;GACA,MAAM,KAAK;GACX;GACA,OAAO;GACP;GACA;GACA;GACA,GAAI,YAAY,EAAE,WAAW,GAAG,EAAE;GACnC,CAAC;EAEmD,EAAE;;;;;;;;AASzD,eAAe,eACb,KACA,QAWuC;CACvC,MAAM,EAAE,QAAQ,QAAQ,MAAM,aAAa,OAAO,eAAe,cAAc;CAC/E,IAAI,SAAS,OAAO;CACpB,IAAI,UAAU,OAAO;CAKrB,MAAM,eAAe;EACnB;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR;EACA,aAAa,qBAAqB,OAAO;EACzC,GAAI,YAAY,EAAE,WAAW,GAAG,EAAE;EACnC;CACD,MAAM,IAAI,MAAM,SAAS,kBAAkB,aAAa;CACxD,SAAS,aAAa;CACtB,UAAU,aAAa;CAKvB,SAAS,wBAAwB,IAAI,UAAU,OAAO;CAKtD,MAAM,IAAI,MAAM,SAAS,cAAc;EACrC;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR,aAAa,qBAAqB,OAAO;EACzC;EACA,GAAI,YAAY,EAAE,WAAW,GAAG,EAAE;EACnC,CAAC;CAEF,OAAO;;AAGT,eAAe,uBACb,KACA,WACA,QACuB;CACvB,MAAM,UAAwB,EAAE;CAEhC,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;EACzC,MAAM,OAAO,UAAU;EAQvB,IAAI,IAAI,OAAO,SAAS;GACtB,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KACpC,QAAQ,KAAK;IAAE,IAAI,UAAU,GAAG;IAAI,SAAS;IAA8B,CAAC;GAC9E,OAAO;;EAYT,IAAI,IAAI,cAAc,SAAS,GAAG;GAChC,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KACpC,QAAQ,KAAK;IAAE,IAAI,UAAU,GAAG;IAAI,SAAS;IAAsC,CAAC;GACtF,OAAO;;EAGT,MAAM,EAAE,WAAW,MAAM,kBAAkB,KAAK,MAAM,OAAO;EAC7D,QAAQ,KAAK,OAAO;;CAGtB,OAAO;;AAGT,eAAe,qBACb,KACA,WACA,QACuB;CACvB,MAAM,aAAa,UAAU,KAAI,SAAQ,kBAAkB,KAAK,MAAM,OAAO,CAAC;CAE9E,QAAO,MADe,QAAQ,WAAW,WAAW,EACrC,KAAK,GAAG,MAAM;EAC3B,IAAI,EAAE,WAAW,aACf,OAAO,EAAE,MAAM;EACjB,OAAO;GACL,IAAI,UAAU,GAAG;GACjB,SAAS,UAAU,EAAE,kBAAkB,QAAQ,EAAE,OAAO,UAAU,OAAO,EAAE,OAAO;GACnF;GACD;;;;;;;;;;;;;;AC3qCJ,SAAgB,mBACd,QAC0B;CAC1B,IAAI,WAAW,KAAA,GACb,OAAO,KAAA;CAET,IAAI,OAAO,WAAW,UAAU;EAC9B,IAAI,OAAO,WAAW,GACpB,OAAO,KAAA;EACT,OAAO,CAAC;GAAE,MAAM;GAAQ,MAAM;GAAQ,CAAC;;CAKzC,IAAI,OAAO,WAAW,GACpB,OAAO,KAAA;CAOT,KAAK,MAAM,QAAQ,QAAQ;EACzB,IAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,OAAQ,KAA4B,SAAS,UACpF,MAAM,IAAI,MAAM,uEAAuE;EAEzF,MAAM,OAAQ,KAA0B;EACxC,IAAI,SAAS,UAAU,SAAS,WAAW,SAAS,YAClD,MAAM,IAAI,MAAM,4BAA4B,KAAK,4CAA4C;;CASjG,IAAI,CALsB,OAAO,MAAK,SACnC,KAAK,SAAS,UAAU,KAAK,KAAK,SAAS,KACzC,KAAK,SAAS,WACd,KAAK,SAAS,WAEG,EACpB,OAAO,KAAA;CAET,OAAO;;;;;;;;;;;;AAaT,SAAgB,qBAAqB,OAAqC;CACxE,MAAM,UAAiC,EAAE;CAEzC,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,KAAK,SAAS,QAAQ;GACxB,IAAI,KAAK,KAAK,SAAS,GACrB,QAAQ,KAAK;IAAE,MAAM;IAAQ,MAAM,KAAK;IAAM,CAAC;GACjD;;EAGF,IAAI,KAAK,SAAS,SAAS;GACzB,QAAQ,KAAK;IAAE,MAAM;IAAS,WAAW,KAAK;IAAW,MAAM,KAAK;IAAM,CAAC;GAC3E;;EAIF,IAAI,KAAK,aAAa,QAAQ;GAC5B,MAAM,SAAS,KAAK,OAChB,qBAAqB,KAAK,KAAK,gBAAgB,KAAK,UAAU,MAC9D,2BAA2B,KAAK,UAAU;GAC9C,QAAQ,KAAK;IAAE,MAAM;IAAQ,MAAM,GAAG,OAAO,IAAI,KAAK,KAAK;IAAkB,CAAC;GAC9E;;EAGF,MAAM,IAAI,MACR,+DAA+D,KAAK,UAAU,8FAE/E;;CAGH,OAAO;EAAE,MAAM;EAAQ;EAAS;;;;;;;AAQlC,SAAgB,mBAAmB,UAAoB,OAAqC;CAC1F,IAAI,SAAS,eACX,OAAO,SAAS,cAAc,MAAM;CACtC,OAAO,qBAAqB,MAAM;;;;;;;;;;;;;;;;;;;ACpFpC,SAAgB,uBACd,OACA,gBACA,cACY;CAIZ,MAAM,8BAAc,IAAI,KAAa;CAMrC,MAAM,iBAAyC,EAAE;CAEjD,eAAe,YAAY,KAKxB;EAED,IAAI,IAAI,SAAS,IAAI,WAAW,KAAA,GAC9B;EAGF,MAAM,SADc,gBACM,GAAG,IAAI;EACjC,IAAI,CAAC,QACH;EAEF,MAAM,MAAM,OAAO;EACnB,IAAI,OAAO,QAAQ,YAAY,OAAO,GACpC;EAKF,MAAM,QAAQ,eAAe,IAAI,SAAS;EAC1C,IAAI,QAAQ,KAAK;GAIf,eAAe,IAAI,QAAQ,QAAQ;GACnC;;EAMF,MAAM,WAAW,OAAO,YAAY;EACpC,IAAI;EACJ,IAAI;EACJ,IAAI,OAAO,aAAa,YACtB,IAAI;GACF,MAAM,MAAM,SAAS;IAAE,MAAM,IAAI;IAAM;IAAO;IAAK,CAAC;GACpD,OAAO,IAAI;GACX,UAAU,IAAI;UAEV;GACJ,OAAO;GACP,UAAU,oBAAoB,IAAI,MAAM,OAAO,IAAI;;OAGlD,IAAI,aAAa,SAAS;GAC7B,OAAO;GACP,UAAU,oBAAoB,IAAI,MAAM,IAAI;SAEzC;GACH,OAAO;GACP,UAAU,oBAAoB,IAAI,MAAM,OAAO,IAAI;;EAGrD,IAAI,SAAS,SAAS;GACpB,IAAI,QAAQ;GACZ,IAAI,SAAS;GACb,MAAM,MAAM,SAAS,wBAAwB;IAC3C,MAAM,IAAI;IACV;IACA;IACA,QAAQ,IAAI;IACZ,MAAM;IACP,CAAC;GACF;;EAKF,IAAI,CAAC,YAAY,IAAI,IAAI,KAAK,EAAE;GAC9B,YAAY,IAAI,IAAI,KAAK;GACzB,aAAa,QAAQ;GACrB,MAAM,MAAM,SAAS,wBAAwB;IAC3C,MAAM,IAAI;IACV;IACA;IACA,QAAQ,IAAI;IACZ,MAAM;IACP,CAAC;;;CAIN,MAAM,aAAa,MAAM,KAAK,aAAa,YAAY;CAEvD,OAAO,SAAS,YAAY;EAC1B,YAAY;EACZ,YAAY,OAAO;;;AAIvB,SAAS,oBAAoB,MAAc,OAAe,KAAqB;CAC7E,OAAO,0BAA0B,KAAK,oBAAoB,MAAM,wBAAwB,IAAI;;AAG9F,SAAS,oBAAoB,MAAc,KAAqB;CAC9D,OAAO,SAAS,KAAK,sCAAsC,IAAI;;;;;;;;;;;;AC5IjE,MAAM,cAAc;AACpB,MAAM,8BAA8B;AACpC,MAAM,wBAAwB;;;;;;AAO9B,SAAgB,iBAAiB,MAAc,aAAa,aAAsB;CAChF,MAAM,SAAS,KAAK,SAAS,aAAa,KAAK,MAAM,GAAG,WAAW,GAAG;CACtE,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KACjC,IAAI,OAAO,WAAW,EAAE,KAAK,GAC3B,OAAO;CAEX,OAAO;;;;;;;;;;AAWT,SAAgB,YAAY,MAAc,aAAa,aAAsB;CAC3E,MAAM,SAAS,KAAK,SAAS,aAAa,KAAK,MAAM,GAAG,WAAW,GAAG;CACtE,IAAI,OAAO,WAAW,GACpB,OAAO;CAET,IAAI,mBAAmB;CACvB,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EACtC,MAAM,OAAO,OAAO,WAAW,EAAE;EACjC,IAAI,SAAS,GACX,OAAO;EACT,IAAI,SAAS,OACX;;CAEJ,OAAO,oBAAoB,yBACtB,mBAAmB,OAAO,SAAS;;;;AC7B1C,SAAgB,qBAAqB,SAAyC;CAC5E,MAAM,SAAS,IAAI,IAAI,QAAQ,QAAQ,KAAI,MAAK,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;CAE7D,OAAO;EACL,MAAM;GACJ,MAAM;GACN,aACE;GAGF,aAAa;IACX,MAAM;IACN,YAAY;KACV,MAAM;MACJ,MAAM;MACN,MAAM,QAAQ,QAAQ,KAAI,MAAK,EAAE,KAAK;MACtC,aAAa;MACd;KACD,MAAM;MACJ,MAAM;MACN,aAAa;MACd;KACF;IACD,UAAU,CAAC,QAAQ,OAAO;IAC1B,sBAAsB;IACvB;GACF;EAED,MAAM,QAAQ,OAAO,KAAmC;GACtD,MAAM,YAAY,MAAM;GACxB,MAAM,UAAU,MAAM;GAEtB,MAAM,QAAQ,OAAO,IAAI,UAAU;GACnC,IAAI,CAAC,OACH,OAAO,yBAAyB,UAAU;GAE5C,IAAI,CAAC,QAAQ,MAAM,SAAS,UAAU,EACpC,OAAO,iBAAiB,UAAU,+CAA+C,UAAU;GAE7F,IAAI,CAAC,MAAM,SACT,OACE,iBAAiB,UAAU;GAK/B,MAAM,YAAY,qBAAqB,SAAS,MAAM,QAAQ;GAC9D,IAAI,CAAC,UAAU,OACb,OAAO,UAAU,UAAU;GAE7B,IAAI;GACJ,IAAI;IACF,UAAU,MAAM,IAAI,UAAU,SAAS,IAAI,QAAQ,UAAU,aAAa;YAErE,KAAK;IAEV,OAAO,kBAAkB,QAAQ,cAAc,UAAU,KADzC,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;;GAIlE,IAAI,iBAAiB,QAAQ,EAQ3B,OAAO,KAAK,UAAU;IACpB,MAAM;IACN,MAAM,UAAU;IAChB,MACE;IAEH,CAAC;GAGJ,OAAO;;EAEV;;;;;;;;;;AC3FH,MAAM,gBAAgB;AACtB,MAAM,kBAAkB;;;;;;;;;AAUxB,SAAgB,WAAW,KAAqB;CAC9C,IAAI,cAAc,KAAK,IAAI,EACzB,OAAO;CACT,OAAO,IAAI,IAAI,QAAQ,iBAAiB,QAAW,CAAC;;;;;;;AAQtD,SAAgB,YAAY,KAAqB;CAC/C,OAAO,IAAI,IAAI,QAAQ,iBAAiB,QAAW,CAAC;;;;ACRtD,MAAM,iBAAiB;AACvB,MAAM,sBAAsB;AAE5B,SAAgB,0BAA0B,SAA8C;CACtF,MAAM,SAAS,IAAI,IAAI,QAAQ,QAAQ,KAAI,MAAK,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;CAC7D,MAAM,YAAY,QAAQ,mBAAmB;CAE7C,OAAO;EACL,MAAM;GACJ,MAAM;GACN,aACE;GAGF,aAAa;IACX,MAAM;IACN,YAAY;KACV,MAAM;MACJ,MAAM;MACN,MAAM,QAAQ,QAAQ,KAAI,MAAK,EAAE,KAAK;MACtC,aAAa;MACd;KACD,QAAQ;MACN,MAAM;MACN,aAAa;MACd;KACD,MAAM;MACJ,MAAM;MACN,OAAO,EAAE,MAAM,UAAU;MACzB,aAAa;MACd;KACF;IACD,UAAU,CAAC,QAAQ,SAAS;IAC5B,sBAAsB;IACvB;GACF;EAED,MAAM,QAAQ,OAAO,KAAmC;GACtD,MAAM,YAAY,MAAM;GACxB,MAAM,YAAY,MAAM;GACxB,MAAM,OAAQ,MAAM,QAAiC,EAAE;GAEvD,MAAM,QAAQ,OAAO,IAAI,UAAU;GACnC,IAAI,CAAC,OACH,OAAO,yBAAyB,UAAU;GAE5C,IAAI,CAAC,QAAQ,MAAM,SAAS,UAAU,EACpC,OAAO,iBAAiB,UAAU,+CAA+C,UAAU;GAE7F,IAAI,CAAC,MAAM,SACT,OAAO,iBAAiB,UAAU;GAIpC,IAAI,UAAU,WAAW,IAAI,IAAI,eAAe,KAAK,UAAU,EAC7D,OAAO,2CAA2C,UAAU;GAI9D,MAAM,YAAY,qBADC,WAAW,YAAY,QAAQ,qBAAqB,IACtB,EAAE,MAAM,QAAQ;GACjE,IAAI,CAAC,UAAU,OACb,OAAO,UAAU,UAAU;GAK7B,MAAM,MAAM,CAAC,UAAU,cAAc,GAAG,KAAK,CAAC,IAAI,YAAY,CAAC,KAAK,IAAI;GACxE,IAAI;IACF,MAAM,SAAS,MAAM,IAAI,UAAU,KAAK,IAAI,QAAQ,KAAK,EACvD,SAAS,KAAK,IAAI,GAAG,KAAK,MAAM,YAAY,IAAK,CAAC,EACnD,CAAC;IACF,OAAO,KAAK,UAAU;KACpB,UAAU,OAAO;KACjB,QAAQ,OAAO;KACf,QAAQ,OAAO;KAChB,CAAC;YAEG,KAAK;IAEV,OAAO,yBAAyB,UAAU,eAAe,UAAU,KADnD,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;;;EAIrE;;;;AC7EH,MAAM,oBAAoB;AAE1B,SAAS,yBAAyB,OAAoB,MAAsB;CAC1E,MAAM,QAAkB,EAAE;CAC1B,MAAM,KAAK,wBAAwB,UAAU,MAAM,KAAK,CAAC,uBAAuB;CAChF,MAAM,KAAK,KAAK;CAEhB,IAAI,MAAM,SAAS;EACjB,MAAM,KAAK,GAAG;EACd,MAAM,KAAK,oBAAoB,MAAM,UAAU;EAC/C,MAAM,KAAK,iDAAiD;;CAG9D,IAAI,MAAM,WAAW,QAAQ;EAC3B,MAAM,KAAK,GAAG;EACd,MAAM,KAAK,oBAAoB;EAC/B,MAAM,QAAQ,MAAM,UAAU,MAAM,GAAG,kBAAkB;EACzD,KAAK,MAAM,OAAO,OAChB,MAAM,KAAK,iBAAiB,IAAI,KAAK,IAAI,UAAU,IAAI,KAAK,CAAC,SAAS;EAExE,IAAI,MAAM,UAAU,SAAS,mBAC3B,MAAM,KAAK,YAAY,MAAM,UAAU,SAAS,kBAAkB,YAAY;EAEhF,MAAM,KAAK,qBAAqB;;CAGlC,IAAI,MAAM,eAAe;EACvB,MAAM,KAAK,GAAG;EACd,MAAM,KAAK,kBAAkB,MAAM,gBAAgB;;CAGrD,IAAI,MAAM,cAAc,QACtB,MAAM,KAAK,kBAAkB,MAAM,aAAa,KAAK,IAAI,GAAG;CAG9D,MAAM,KAAK,mBAAmB;CAC9B,OAAO,MAAM,KAAK,KAAK;;;;;;;;;;AAWzB,SAAgB,oBAAoB,SAAwC;CAC1E,MAAM,SAAS,IAAI,IAAI,QAAQ,QAAQ,KAAI,MAAK,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;CAI7D,MAAM,wCAAwB,IAAI,KAAqB;CAEvD,OAAO;EACL,MAAM;GACJ,MAAM;GACN,aACE;GAIF,aAAa;IACX,MAAM;IACN,YAAY,EACV,MAAM;KACJ,MAAM;KACN,MAAM,QAAQ,QAAQ,KAAI,MAAK,EAAE,KAAK;KACtC,aAAa;KACd,EACF;IACD,UAAU,CAAC,OAAO;IAClB,sBAAsB;IACvB;GACF;EAED,MAAM,QAAQ,OAAO,KAAmC;GACtD,MAAM,YAAY,MAAM;GACxB,MAAM,QAAQ,OAAO,IAAI,UAAU;GACnC,IAAI,CAAC,OAEH,OAAO,yBAAyB,UAAU,uBADxB,CAAC,GAAG,OAAO,MAAM,CAAC,CAAC,KAAK,KAAK,IAAI,SACwB;GAK7E,IAAI,CAFc,QAAQ,MAAM,SAAS,UAE3B,EAAE;IAEd,IADgB,QAAQ,MAAM,SAAS,OAAO,QACnC,KAAK,eAEd,OACE,2BAA2B,UAAU,kEAFnB,QAAQ,MAAM,QAAQ,CAAC,KAAI,MAAK,EAAE,MAAM,KAAK,CAAC,KAAK,KAGnC,CAAC;IAGvC,MAAM,QAAQ,MAAM,SAAS,mBAAmB;KAAE;KAAO,KAAK;KAAS,CAAC;;GAK1E,IAAI,OAAO,sBAAsB,IAAI,UAAU;GAC/C,IAAI,SAAS,KAAA,GAAW;IACtB,OAAO,MAAM,aAAa,SAAS,KAAK,GACpC,MAAM,yBAAyB,MAAM,cAAc,IAAI,WAAW,IAAI,OAAO,GAC7E,MAAM;IACV,sBAAsB,IAAI,WAAW,KAAK;;GAG5C,OAAO,yBAAyB,OAAO,KAAK;;EAE/C;;;;AC7EH,MAAMA,kBAAgB;AAEtB,SAAS,YAAY,SAAmC,OAAgC;CACtF,MAAM,IAAI,MAAM,MAAM,CAAC,aAAa;CACpC,IAAI,CAAC,GACH,OAAO,CAAC,GAAG,QAAQ;CAKrB,MAAM,WAA4B,EAAE;CACpC,MAAM,WAA4B,EAAE;CACpC,KAAK,MAAM,SAAS,SAClB,IAAI,MAAM,KAAK,aAAa,CAAC,SAAS,EAAE,EACtC,SAAS,KAAK,MAAM;MACjB,IAAI,MAAM,YAAY,aAAa,CAAC,SAAS,EAAE,EAClD,SAAS,KAAK,MAAM;CAExB,OAAO,CAAC,GAAG,UAAU,GAAG,SAAS;;;;;;;;;;;;;;;;;AAkBnC,SAAS,qBAAqB,YAA4B;CACxD,OAAO,WAAW,QAAQ,MAAM,UAAU;;AAG5C,SAAS,YAAY,OAA8B;CACjD,MAAM,SAAS,qBAAqB,KAAK,UAAU,MAAM,YAAY,CAAC;CACtE,MAAM,aAAa,MAAM,SAAS,YAAY,UAAU,MAAM,OAAO,CAAC,KAAK;CAC3E,OAAO;EACL,iBAAiB,UAAU,MAAM,KAAK,CAAC,GAAG,WAAW;EACrD,oBAAoB,UAAU,MAAM,YAAY,CAAC;EACjD,qBAAqB,OAAO;EAC5B;EACD,CAAC,KAAK,KAAK;;;;;;;AAQd,SAAgB,qBAAqB,SAAyC;CAC5E,MAAM,eAAe,QAAQ,gBAAgBA;CAI7C,MAAM,SAAS,IAAI,IAAI,QAAQ,QAAQ,KAAI,MAAK,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;CAC7D,MAAM,2BAAW,IAAI,KAA8B;CACnD,KAAK,MAAM,SAAS,QAAQ,SAAS;EACnC,IAAI,CAAC,MAAM,QACT;EACF,MAAM,OAAO,SAAS,IAAI,MAAM,OAAO,IAAI,EAAE;EAC7C,KAAK,KAAK,MAAM;EAChB,SAAS,IAAI,MAAM,QAAQ,KAAK;;CAElC,MAAM,WAAW,KAAK,IAAI,QAAQ,QAAQ,QAAQ,EAAE;CAEpD,OAAO;EACL,MAAM;GACJ,MAAM;GACN,aACE;GAMF,aAAa;IACX,MAAM;IACN,YAAY;KACV,OAAO;MACL,MAAM;MACN,aAAa;MACd;KACD,OAAO;MACL,MAAM;MACN,OAAO,EAAE,MAAM,UAAU;MACzB,aAAa;MACd;KACD,QAAQ;MACN,MAAM;MACN,aAAa;MACd;KACD,OAAO;MACL,MAAM;MACN,SAAS;MACT,aAAa,qCAAqC,aAAa;MAChE;KACF;IACD,sBAAsB;IACvB;GACF;EAED,MAAM,QAAQ,OAAO,KAAmC;GAGtD,IAAI,IAAI,QAAQ,SACd,OAAO;GAMT,MAAM,SADW,OAAO,MAAM,UAAU,WAAW,MAAM,MAAM,MAAM,GAAG,KAAA,MAC9C,KAAA;GAC1B,MAAM,UAAU,MAAM,QAAQ,MAAM,MAAM,GACtC,MAAM,MAAM,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,SAAS,EAAE,GAC7E,KAAA;GACJ,MAAM,SAAS,OAAO,MAAM,WAAW,YAAY,MAAM,OAAO,SAAS,IAAI,MAAM,SAAS,KAAA;GAC5F,MAAM,UAAU,OAAO,MAAM,UAAU,YAAY,OAAO,SAAS,MAAM,MAAM,IAAI,MAAM,QAAQ,IAC7F,KAAK,MAAM,MAAM,MAAM,GACvB;GACJ,MAAM,QAAQ,KAAK,IAAI,SAAS,SAAS;GAEzC,IAAI,QAAQ,QAAQ,WAAW,GAC7B,OAAO;GAET,MAAM,UAA2B,EAAE;GACnC,MAAM,uBAAO,IAAI,KAAa;GAC9B,MAAM,SAAmB,EAAE;GAI3B,IAAI,WAAW,QAAQ,SAAS,GAC9B,KAAK,MAAM,KAAK,SAAS;IACvB,IAAI,KAAK,IAAI,EAAE,EACb;IACF,MAAM,QAAQ,OAAO,IAAI,EAAE;IAC3B,IAAI,OAAO;KACT,QAAQ,KAAK,MAAM;KACnB,KAAK,IAAI,EAAE;WAGX,OAAO,KAAK,EAAE;;GAKpB,IAAI,QAAQ;IACV,MAAM,OAAO,SAAS,IAAI,OAAO,IAAI,EAAE;IACvC,KAAK,MAAM,SAAS,MAAM;KACxB,IAAI,KAAK,IAAI,MAAM,KAAK,EACtB;KACF,QAAQ,KAAK,MAAM;KACnB,KAAK,IAAI,MAAM,KAAK;;;GAIxB,IAAI,UAAU,KAAA,GACZ,KAAK,MAAM,SAAS,YAAY,QAAQ,SAAS,MAAM,EAAE;IACvD,IAAI,KAAK,IAAI,MAAM,KAAK,EACtB;IACF,QAAQ,KAAK,MAAM;IACnB,KAAK,IAAI,MAAM,KAAK;;GAMxB,IAAI,CAAC,SAAS,UAAU,CAAC,UAAU,UAAU,KAAA,GAC3C,KAAK,MAAM,SAAS,QAAQ,SAAS;IACnC,QAAQ,KAAK,MAAM;IACnB,KAAK,IAAI,MAAM,KAAK;;GAIxB,MAAM,YAAY,QAAQ,SAAS;GACnC,MAAM,QAAQ,YAAY,QAAQ,MAAM,GAAG,MAAM,GAAG;GAIpD,KAAK,MAAM,SAAS,OAClB,QAAQ,SAAS,IAAI,MAAM,cAAc;GAE3C,MAAM,QAAkB,EAAE;GAC1B,MAAM,YAAY,QAAQ,WAAW,UAAU,MAAM,CAAC,KAAK;GAC3D,MAAM,aAAa,SAAS,YAAY,UAAU,OAAO,CAAC,KAAK;GAC/D,MAAM,KAAK,iCAAiC,MAAM,OAAO,WAAW,QAAQ,OAAO,GAAG,YAAY,WAAW,GAAG;GAChH,IAAI,MAAM,WAAW,GACnB,MAAM,KAAK,gFAAgF;QAExF;IACH,KAAK,MAAM,SAAS,OAClB,MAAM,KAAK,YAAY,MAAM,CAAC;IAChC,MAAM,KAAK,GAAG;IACd,MAAM,KAAK,2EAA2E;IACtF,IAAI,WACF,MAAM,KAAK,KAAK,QAAQ,SAAS,MAAM,OAAO,2EAA2E;;GAG7H,IAAI,OAAO,SAAS,GAClB,MAAM,KAAK,aAAa,OAAO,IAAI,UAAU,CAAC,KAAK,KAAK,CAAC,WAAW;GAEtE,MAAM,KAAK,yBAAyB;GAEpC,OAAO,MAAM,KAAK,KAAK;;EAE1B;;;;ACoKH,MAAM,iBAAsC,IAAI,IAAI;CA1DlD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGkE,CAAC;AAErE,SAAS,iBAAiB,OAA0C;CAClE,OAAO,eAAe,IAAI,MAAM;;AAsHlC,SAAS,gBACP,eACA,aACA;CACA,OAAO;EACL,eAAe,aAAa,iBAAiB,eAAe,iBAAiB;EAC7E,UAAU,aAAa,YAAY,eAAe;EAClD,WAAW,aAAa,aAAa,eAAe;EACpD,gBAAgB,aAAa,kBAAkB,eAAe;EAC9D,QAAQ,aAAa,UAAU,eAAe;EAC9C,OAAO,aAAa,SAAS,eAAe,SAAS;EACrD,kBAAkB,aAAa,oBAAoB,eAAe;EAClE,iBAAiB,aAAa,mBAAmB,eAAe,mBAAmB;EACnF,kBAAkB,aAAa,oBAAoB,eAAe;EAClE,kBAAkB,aAAa,oBAAoB,eAAe;EAClE,eAAe,aAAa,iBAAiB,eAAe;EAC5D,YAAY,aAAa,cAAc,eAAe;EACtD,YAAY,aAAa,cAAc,eAAe;EACtD,uBAAuB,aAAa,yBAAyB,eAAe;EAC5E,aAAa,aAAa,eAAe,eAAe;EACxD,iBAAiB,aAAa,mBAAmB,eAAe;EAChE,iBAAiB,aAAa,mBAAmB,eAAe;EAChE,gBAAgB,aAAa,kBAAkB,eAAe,kBAAkB;EAChF,YAAY,aAAa,cAAc,eAAe;EACvD;;;;;;;;;;;AAgBH,SAAS,qBACP,UACA,SAC6B;CAC7B,IAAI,CAAC,WAAW,QAAQ,WAAW,GACjC,OAAO,KAAA;CACT,IAAI;CACJ,IAAI,UAAU;CACd,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,SAAS,OAAO,OAAO,KAAK;EAClC,IAAI,SAAS,WAAW,OAAO,IAAI,OAAO,KAAK,SAAS,SAAS;GAC/D,OAAO;GACP,UAAU,OAAO,KAAK;;;CAG1B,OAAO;;;;;;;;;;;;;;;;;AA2BT,SAAS,wBACP,iBACA,cACA,SACA,YACA,aACkB;CAClB,MAAM,sCAAsB,IAAI,KAAa;CAC7C,MAAM,qCAAqB,IAAI,KAAa;CAC5C,MAAM,cAA+B,EAAE;CAEvC,SAAS,QAAQ,WAA2B;EAC1C,MAAM,UAAU,cAAc;EAC9B,OAAO,OAAO,YAAY,YAAY,QAAQ,SAAS,IAAI,UAAU;;CAGvE,KAAK,MAAM,CAAC,eAAe,QAAQ,OAAO,QAAQ,gBAAgB,EAAE;EAClE,IAAI,CAAC,aAAa,IAAI,cAAc,EAAE;GACpC,oBAAoB,IAAI,cAAc;GACtC;;EAEF,MAAM,SAAS,qBAAqB,eAAe,QAAQ;EAE3D,KADa,QAAQ,cAAc,gBACtB,QAAQ;GACnB,mBAAmB,IAAI,cAAc;GACrC,YAAY,KAAK;IACf,MAAM,QAAQ,cAAc;IAC5B;IACA,aAAa,IAAI,KAAK,eAAe;IACrC,aAAc,IAAI,KAAK,eAAe;KAAE,MAAM;KAAU,YAAY,EAAE;KAAE;IACxE,GAAI,SAAS,EAAE,QAAQ,OAAO,MAAM,GAAG,EAAE;IAC1C,CAAC;SAGF,oBAAoB,IAAI,cAAc;;CAI1C,OAAO;EAAE;EAAqB;EAAoB;EAAa;;AAajE,SAAS,uBACP,SACA,SACQ;CAIR,MAAM,2BAAW,IAAI,KAA8B;CACnD,MAAM,YAA6B,EAAE;CACrC,KAAK,MAAM,SAAS,SAAS;EAC3B,IAAI,CAAC,MAAM,QAAQ;GACjB,UAAU,KAAK,MAAM;GACrB;;EAEF,MAAM,OAAO,SAAS,IAAI,MAAM,OAAO,IAAI,EAAE;EAC7C,KAAK,KAAK,MAAM;EAChB,SAAS,IAAI,MAAM,QAAQ,KAAK;;CAOlC,MAAM,cAAc,CAAC,GAAG,SAAS,MAAM,CAAC,CAAC,MAAM;CAE/C,MAAM,QAAkB,EAAE;CAC1B,IAAI,QAAQ,mBACV,MAAM,KACJ,6FACA,cAAc,QAAQ,kBAAkB,gGACxC,GACD;CAEH,MAAM,KAAK,qBAAqB;CAChC,KAAK,MAAM,UAAU,aAAa;EAChC,MAAM,KAAK,mBAAmB,UAAU,OAAO,CAAC,IAAI;EACpD,KAAK,MAAM,SAAS,SAAS,IAAI,OAAO,EACtC,MAAM,KAAK,mBAAmB,UAAU,MAAM,KAAK,CAAC,IAAI,UAAU,MAAM,YAAY,CAAC,SAAS;EAChG,MAAM,KAAK,cAAc;;CAE3B,KAAK,MAAM,SAAS,WAClB,MAAM,KAAK,iBAAiB,UAAU,MAAM,KAAK,CAAC,IAAI,UAAU,MAAM,YAAY,CAAC,SAAS;CAC9F,MAAM,KAAK,sBAAsB;CACjC,OAAO,MAAM,KAAK,KAAK;;;;;;;;;;;;;;;AAgBzB,SAAS,0BACP,OACA,oBACA,UACA,mBACY;CACZ,IAAI,mBAAmB,SAAS,GAC9B,aAAa;CACf,OAAO,MAAM,KAAK,cAAc,QAAQ;EACtC,IAAI,IAAI,OACN;EACF,IAAI,CAAC,mBAAmB,IAAI,IAAI,KAAK,EACnC;EACF,IAAI,SAAS,IAAI,IAAI,KAAK,EACxB;EACF,IAAI,QAAQ;EACZ,IAAI,SAAS,oBACT,SAAS,IAAI,KAAK,mFAAmF,kBAAkB,wBAAwB,IAAI,KAAK,qCACxJ,SAAS,IAAI,KAAK;GACtB;;AAOJ,SAAgB,YAAY,EAAE,UAAU,MAAM,WAAW,QAAQ,aAAa,OAAO,YAAY,aAAa,UAAU,eAAe,WAAW,YAAY,SAAS,QAAQ,aAAa,cAAc,SAA8B;CACtO,MAAM,QAAQ,aAAyB;CACvC,MAAM,mBAAmB,aAAa,sBAAsB;CAC5D,MAAM,cAAc,cAAc,EAAE;CAEpC,IAAI;CACJ,IAAI,UAAU;CACd,IAAI;CACJ,IAAI;CACJ,IAAI,kBAA0C;CAC9C,IAAI,gBAAsC;CAK1C,IAAI,mBAAyC;CAC7C,MAAM,gBAAgB,cAAc,EAAE;CACtC,MAAM,gBAA0B,EAAE;CAClC,MAAM,gBAA0B,EAAE;CAClC,IAAI,oBAAmC,SAAS,MAAM,OAAO,IAAI,EAAE;CACnE,IAAI,aAAa,SAAS,KAAK,UAAU;CAGzC,MAAM,eAAe;CACrB,MAAM,qBAAqB,cAAc;CACzC,MAAM,iBAAiB,uBAAuB,SAAU,MAAM,QAAQ,mBAAmB,IAAI,mBAAmB,WAAW;CAC3H,IAAI,iBAAuC;CAC3C,IAAI,gBAA+B;CAKnC,IAAI,sBAAkC;CAItC,MAAM,uBAAuB,2BAA2B,EACtD,WAAW,cAAc,WAC1B,CAAC;CAEF,eAAe,IAAI,SAA+C;EAChE,IAAI,SACF,MAAM,IAAI,MAAM,2FAA2F;EAI7G,MAAM,kBAAkB,WAAW,QAAQ,MAAM,SAAS;EAC1D,IAAI,CAAC,QAAQ,UAAU,CAAC,iBACtB,MAAM,IAAI,MAAM,qEAAqE;EAEvF,IAAI,CAAC,QAAQ,UAAU,iBAAiB;GACtC,MAAM,WAAW,QAAS,MAAM,GAAG,GAAG;GACtC,IAAI,YAAY,SAAS,SAAS,QAChC,MAAM,IAAI,MAAM,yEAAyE;;EAI7F,UAAU;EACV,kBAAkB,IAAI,iBAAiB;EACvC,MAAM,QAAQ,OAAO,EAAE;EAMvB,MAAM,cAAc,OAAO,QAAQ,WAAW,WAC1C,QAAQ,SACR,MAAM,QAAQ,QAAQ,OAAO,GAC3B,QAAQ,OACL,QAAQ,MAA2C,EAAE,SAAS,OAAO,CACrE,KAAI,MAAK,EAAE,KAAK,CAChB,KAAK,KAAK,GACb;EAGN,SAAS,SAAS,OAAO,aAAa;GACpC,GAAI,QAAQ,cAAc,EAAE,aAAa,QAAQ,aAAa,GAAG,EAAE;GACnE,OAAO,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ;GAC5D,CAAC;EACF,IAAI,SAAS;GACX,MAAM,QAAQ,aAAa,UAAU;GACrC,MAAM,MAAM,SAAS,iBAAiB;IAAE,WAAW,QAAQ;IAAI;IAAO,QAAQ;IAAa,CAAC;;EAI9F,IAAI,QAAQ,QACV,IAAI,QAAQ,OAAO,SACjB,gBAAgB,OAAO;OAEpB;GACH,MAAM,wBAAwB,iBAAiB,OAAO;GACtD,QAAQ,OAAO,iBAAiB,SAAS,iBAAiB,EAAE,MAAM,MAAM,CAAC;;EAI7E,cAAc,IAAI,SAAe,YAAY;GAC3C,cAAc;IACd;EAGF,MAAM,gBAAiC,EAAE;EACzC,MAAM,sBAAsB,MAAM,KAAK,mBAAmB,QAAQ;GAChE,cAAc,KAAK,IAAI;IACvB;EAUF,MAAM,oBAAuC,EAAE;EAC/C,IAAI,QAAQ,OACV,KAAK,MAAM,CAAC,OAAO,YAAY,OAAO,QAAQ,QAAQ,MAAM,EAAE;GAC5D,IAAI,CAAC,iBAAiB,MAAM,EAC1B,MAAM,IAAI,MACR,uBAAuB,MAAM,qDAC9B;GAEH,MAAM,cAAc,MAAM,QAAQ,QAAQ,GAAG,UAAU,CAAC,QAAQ;GAChE,KAAK,MAAM,MAAM,aAAa;IAC5B,IAAI,OAAO,OAAO,YAChB;IAGF,kBAAkB,KAAK,MAAM,KAAK,OAAO,GAA+B,CAAC;;;EAM/E,IAAI,CAAC,iBACH,kBAAkB,MAAM,iBAAiB,OAAO;EAOlD,IAAI,cAAc,SAAS,KAAK,CAAC,eAC/B,MAAM,QAAQ;EAOhB,IAAI,CAAC,kBAAkB,gBAAgB,CAAC,gBAAgB;GACtD,MAAM,SAAS,MAAM,cAAc,aAAa;GAChD,iBAAiB,OAAO;GACxB,gBAAgB,OAAO;GACvB,MAAM,MAAM,SAAS,kBAAkB,EAAE,QAAQ,gBAAgB,CAAC;GAYlE,MAAM,uBAAuB,cAAc,SAAS,SAAS,eAAe,SAAS;GACrF,MAAM,aAAa;IACjB,SAAS,aAAa,gBAAgB,EAAE,sBAAsB,CAAC;IAC/D,QAAQ;IACT;GACD,MAAM,MAAM,SAAS,kBAAkB,WAAW;GAClD,gBAAgB,WAAW;;EAS7B,IAAI,kBAAkB,WAAW,QAAQ,MAAM,SAAS,KAAK,qBAAqB,QAAQ,CAAC,WAAW,GAAG;GACvG,MAAM,eAAe,IAAI,IAAI,eAAe,KAAI,MAAK,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;GAClE,KAAK,MAAM,QAAQ,QAAQ,OAAO;IAChC,IAAI,KAAK,SAAS,aAChB;IACF,KAAK,MAAM,SAAS,KAAK,SAAS;KAChC,IAAI,MAAM,SAAS,eAAe,MAAM,SAAS,cAC/C;KACF,MAAM,YAAa,MAAM,OAAyC;KAClE,IAAI,CAAC,WACH;KACF,MAAM,QAAQ,aAAa,IAAI,UAAU;KACzC,IAAI,CAAC,OACH;KACF,IAAI,qBAAqB,SAAS,OAAO,SAAS,KAAK,MACrD,MAAM,MAAM,SAAS,mBAAmB;MAAE;MAAO,KAAK;MAAU,CAAC;;;;EAMzE,MAAM,WAAW,QAAQ,YAAY;EACrC,MAAM,QAAQ,QAAQ,SAAS,SAAS,KAAK;EAC7C,MAAM,mBAAmB,gBAAgB,eAAe,QAAQ,SAAS;EACzE,MAAM,EAAE,eAAe,UAAU,WAAW,gBAAgB,QAAQ,OAAO,kBAAkB,iBAAiB,kBAAkB,kBAAkB,eAAe,YAAY,aAAa,iBAAiB,gBAAgB,eAAe;EAG1O,IAAI,SAAS,QAAQ,UAAU,eAAe;EAG9C,IAAI,eACF,SAAS,GAAG,OAAO,MAAM;EAI3B,MAAM,eAAe,QAAQ,UAAU,KAAA,IACnC,QAAQ,QACP,gBACG;GAAE,GAAG;GAAa,GAAG,cAAc;GAAO,GAC1C;EAKR,MAAM,eACF,QAAQ,UAAU,KAAA,KAAa,gBAC7B,IAAI,IAAI,OAAO,KAAK,cAAc,MAAM,CAAC,mBACzC,IAAI,KAAa;EAcvB,MAAM,mBALF,QAAQ,UAAU,KAAA,KACf,CAAC,CAAC,kBACF,eAAe,SAAS,KACxB,cAAc,SAAS,QAG1B;GAEE,YAAY,oBAAoB;IAC9B,SAAS;IACT,OAAO;IACP;IACD,CAAC;GACF,aAAa,qBAAqB;IAChC,SAAS;IACT,OAAO;IACR,CAAC;GACF,mBAAmB,0BAA0B;IAC3C,SAAS;IACT,OAAO;IACP,iBAAiB,cAAc;IAChC,CAAC;GACF,GAAG;GACJ,GACD;EAGJ,MAAM,iBAAkE,EAAE;EAC1E,KAAK,MAAM,QAAQ,OAAO,OAAO,iBAAiB,EAChD,eAAe,KAAK,KAAK,QAAQ;EAgBnC,MAAM,aAAa,wBAAwB,gBAAgB,cAAc,YAAY,gBAAgB,YAAY;EACjH,MAAM,WAAW,IAAI,IAAY,WAAW,oBAAoB;EAChE,MAAM,wBAAwB,CAAC,CAAC,eAAe;EAC/C,MAAM,yBACF,WAAW,YAAY,SAAS,KAC7B,YAAY,SAAS,SACrB,CAAC;EACR,IAAI,QAAQ;EACZ,IAAI,wBAAwB;GAC1B,MAAM,iBAAiB,qBAAqB;IAC1C,SAAS,WAAW;IACpB;IACA,GAAI,YAAY,UAAU,KAAA,IAAY,EAAE,cAAc,WAAW,OAAO,GAAG,EAAE;IAC9E,CAAC;GACF,QAAQ;IAAE,GAAG;KAAiB,eAAe,KAAK,OAAO;IAAgB;GACzE,SAAS,IAAI,eAAe,KAAK,KAAK;;EAQxC,MAAM,oBAAmC,yBACrC,gBACC,wBACI,aAAa,eAAe,gBAC7B;EAKR,IAAI,WAAW,YAAY,SAAS,GAClC,SAAS,GAAG,OAAO,MAAM,uBAAuB,WAAW,aAAa,EAAE,mBAAmB,CAAC;EAIhG,MAAM,YAAY,eAAe,aAAa,OAAO,KAAK,MAAM,CAAC;EAgBjE,MAAM,8BAA8B,0BAClC,OACA,WAAW,oBACX,UACA,kBACD;EAcD,SAAS,sBAAiC;GACxC,MAAM,QAAoB,EAAE;GAC5B,KAAK,MAAM,KAAK,OAAO,OAAO,MAAM,EAAE;IACpC,IAAI,CAAC,SAAS,IAAI,EAAE,KAAK,KAAK,EAC5B;IACF,MAAM,KAAK;KACT,MAAM,UAAU,iBAAiB,IAAI,EAAE,KAAK,KAAK,IAAI,EAAE,KAAK;KAC5D,aAAa,EAAE,KAAK,eAAe;KACnC,aAAa,EAAE,KAAK;KACrB,CAAC;;GAEJ,OAAO,MAAM,SAAS,IAAI,SAAS,YAAY,MAAM,GAAG,EAAE;;EAE5D,MAAM,iBAAiB,qBAAqB;EAG5C,MAAM,QAAuB,EAAE;EAY/B,MAAM,WAAW,WACZ,QAAQ,MAAM,SAAS,MACtB,QAAQ,KAAK,SAAS,KAAK,CAAC,QAAQ,WACrC,CAAC,QAAQ;EACd,IAAI,UAAU;GAcZ,MAAM,cAAc,IAAI,IACtB,QAAS,KAAK,QAAO,OAAM,EAAE,SAAS,KAAK,EAAE,CAAC,KAAI,MAAK,EAAE,GAAG,CAC7D;GACD,MAAM,UAAU,YAAY,SAAS,IACjC,QAAS,QACT,QAAS,MAAM,QAAO,MAAK,CAAC,EAAE,SAAS,CAAC,YAAY,IAAI,EAAE,MAAM,CAAC;GACrE,MAAM,KAAK,GAAG,QAAQ;;EAIxB,MAAM,eAAe,MAAM;EAE3B,IAAI,QAAQ,QACV,MAAM,MAAM,SAAS,iBAAiB,EAAE,QAAQ,QAAQ,QAAQ,CAAC;EAGnE,MAAM,cAAc,mBAAmB,QAAQ,OAAO;EACtD,IAAI,aAAa;GACf,MAAM,YAAY,mBAAmB,UAAU,YAAY;GAC3D,MAAM,KAAK;IACT,IAAI,OAAO,YAAY;IACvB;IACA,MAAM,UAAU;IAChB,SAAS,UAAU;IACnB,WAAW,KAAK,KAAK;IACtB,CAAC;;EAGJ,oBAAoB;EAGpB,IAAI,yBAAyB,WAAW,QAAS,MAAM,SAAS;EAOhE,IAAI,WAAW,MAAM,SAAS,wBAAwB;GACpD,MAAM,cAAc,MAAM,MAAM,uBAAuB;GACvD,MAAM,QAAQ,YAAY,YAAY;GACtC,yBAAyB,MAAM;GAC/B,MAAM,MAAM,SAAS,iBAAiB;IAAE,WAAW,QAAQ;IAAI,OAAO;IAAa,OAAO,MAAM;IAAQ,CAAC;;EAI3G,MAAM,wBAAwB,UAC1B,MAAM,KAAK,cAAc,YAAY;GACnC,MAAM,WAAW,MAAM,MAAM,uBAAuB;GACpD,IAAI,SAAS,SAAS,GAAG;IACvB,MAAM,QAAQ,YAAY,SAAS;IACnC,yBAAyB,MAAM;IAC/B,MAAM,MAAM,SAAS,iBAAiB;KAAE,WAAW,QAAQ;KAAI,OAAO;KAAU,OAAO,MAAM;KAAQ,CAAC;;IAExG,GACF,KAAA;EAGJ,eAAe,aAAa;GAC1B,IAAI,CAAC,SACH;GACF,MAAM,YAAY,MAAM,MAAM,uBAAuB;GACrD,IAAI,UAAU,SAAS,GAAG;IACxB,MAAM,QAAQ,YAAY,UAAU;IACpC,yBAAyB,MAAM;IAC/B,MAAM,MAAM,SAAS,iBAAiB;KAAE,WAAW,QAAQ;KAAI,OAAO;KAAW,OAAO,MAAM;KAAQ,CAAC;;;EAM3G,eAAe,sBAAsB;GACnC,KAAK,MAAM,UAAU,qBAAqB,OAAO,EAC/C,MAAM,MAAM,SAAS,qBAAqB;IAAE,OAAO,OAAO;IAAO,QAAQ;IAAW,CAAC;;EAIzF,eAAe,gBAAgB,QAA0B;GACvD,IAAI,CAAC,SACH;GACF,MAAM,MAAM,QAAQ,KAAK,MAAK,MAAK,EAAE,OAAO,MAAM;GAClD,IAAI,KACF,MAAM,QAAQ,UAAU,IAAI;GAC9B,MAAM,QAAQ,aAAa,WAAW,YAAY,SAAS,OAAO;GAClE,MAAM,MAAM,SAAS,eAAe;IAAE,WAAW,QAAQ;IAAI;IAAO;IAAQ,WAAW,CAAC,cAAc,MAAM,SAAS,EAAE;IAAE,CAAC;;EAK5H,MAAM,4BAA4B,wBAAwB,OAAO,qBAAqB;EAQtF,MAAM,uBAAuB,uBAC3B,aACM,cACN,QAAO,cAAc,KAAK,IAAI,CAC/B;EAMD,MAAM,sBAAsB,sBAC1B,aACM,kBACA,WAAW,KAAA,EAClB;EAED,MAAM,aAAa,KAAK,KAAK;EAE7B,MAAM,WAAW,OAAO,QAAQ,UAAU,WAAW,QAAQ,QAAQ;EAErE,IAAI;GACF,MAAM,QAAQ,MAAM,QAAQ;IAC1B;IACA;IACA;IACA;IACA,YAAY;IACZ,kBAAkB;IAClB,iBAAiB;IACjB;IAIA,eAAe;IACf;IACA;IACA,uBAAuB,WAAW,YAAY,SAAS,IAAI,sBAAsB,KAAA;IACjF;IACA;IACA;IACA;IACA;IACA,QAAQ,gBAAgB;IACxB,WAAW;IACX,QAAQ;IACR;IACA;IACA;IACA;IACA,sBAAsB,SAAS,gBAAgB,IAAI,OAAO,YAAY;IACtE;IACA;IACA,GAAI,UAAU,EAAE,SAAS,GAAG,EAAE;IAC9B,OAAO;IACP;IACA;IACA;IACA;IACA;IACA;IACA;IACA,GAAI,oBAAoB,KAAA,IAAY,EAAE,iBAAiB,GAAG,EAAE;IAC5D,GAAI,kBAAkB,KAAA,IAAY,EAAE,eAAe,GAAG,EAAE;IACxD;IACA,eAAe,EAAE;IAClB,CAAC;GASF,MAAM,iBAAiB,MAAM,WACzB,QAAQ,KAAK,MAAM,OAAO,EAAE,QAAQ,IAAI,EAAE,IAAI;GAOlD,IAAI,aAAa;GACjB,IAAI,cAAc;GAClB,IAAI,eAAe;GACnB,IAAI,oBAAoB;GACxB,IAAI,wBAAwB;GAC5B,KAAK,MAAM,KAAK,eAAe;IAC7B,cAAc,EAAE,MAAM;IACtB,eAAe,EAAE,MAAM;IACvB,gBAAgB,EAAE,MAAM,QAAQ;IAChC,qBAAqB,EAAE,MAAM;IAC7B,yBAAyB,EAAE,MAAM;;GAGnC,MAAM,iBAAiB,iBAAiB;GAExC,MAAM,aAAyB;IAC7B,GAAG;IACH,SAAS,MAAM,UAAU;IACzB,UAAU,MAAM,WAAW;IAC3B,gBAAgB,MAAM,iBAAiB;IACvC,oBAAoB,MAAM,qBAAqB;IAC/C,GAAI,iBAAiB,IAAI,EAAE,MAAM,gBAAgB,GAAG,EAAE;IACtD,UAAU,cAAc,SAAS,IAAI,gBAAgB,KAAA;IACtD;GAED,MAAM,YAAY;GAGlB,IAAI,gBAAgB,OAAO,SAAS;IAClC,SAAS,SAAS,MAAM;IACxB,MAAM,gBAAgB,UAAU;IAChC,MAAM,MAAM,SAAS,cAAc,WAAW;IAC9C,OAAO;;GAGT,SAAS,YAAY,OAAO;IAC1B,OAAO,MAAM;IACb,UAAU,MAAM;IAChB,WAAW,MAAM;IACjB,WAAW,MAAM;IACjB,MAAM,iBAAiB,IAAI,iBAAiB,KAAA;IAC7C,CAAC;GACF,MAAM,gBAAgB,YAAY;GAElC,MAAM,MAAM,SAAS,cAAc,WAAW;GAC9C,OAAO;WAEF,KAAK;GACV,MAAM,YAAY;GAGlB,IAAI,gBAAgB,OAAO,SAAS;IAClC,SAAS,SAAS,MAAM;IACxB,MAAM,gBAAgB,UAAU;IAChC,MAAM,QAAoB;KACxB,SAAS;KACT,UAAU;KACV,gBAAgB;KAChB,oBAAoB;KACpB,OAAO;KACP,SAAS;KACV;IACD,MAAM,MAAM,SAAS,cAAc,MAAM;IACzC,OAAO;;GAGT,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;GAChE,SAAS,SAAS,OAAO,QAAQ;GACjC,MAAM,gBAAgB,QAAQ;GAC9B,MAAM;YAEA;GAKN,MAAM,qBAAqB;GAG3B,2BAA2B;GAC3B,qBAAqB;GACrB,sBAAsB;GACtB,6BAA6B;GAE7B,qBAAqB;GACrB,yBAAyB;GACzB,KAAK,MAAM,cAAc,mBACvB,YAAY;GACd,UAAU;GACV,kBAAkB,KAAA;GAClB,cAAc,SAAS;GACvB,cAAc,SAAS;GACvB,eAAe;GACf,cAAc,KAAA;GACd,cAAc,KAAA;;;CAIlB,SAAS,QAAQ;EACf,iBAAiB,OAAO;;CAG1B,SAAS,MAAM,SAAiB;EAC9B,cAAc,KAAK,QAAQ;;CAG7B,SAAS,WAAW,SAAiB;EACnC,cAAc,KAAK,QAAQ;;CAG7B,SAAS,cAA6B;EACpC,OAAO,eAAe,QAAQ,SAAS;;CAGzC,eAAe,QAAQ;EAQrB,IAAI,SACF,MAAM,IAAI,MACR,yGACD;EAEH,oBAAoB,EAAE;EACtB,cAAc,SAAS;EACvB,cAAc,SAAS;EAMvB,MAAM,UAAU,qBAAqB,OAAO;EAC5C,KAAK,MAAM,UAAU,SACnB,MAAM,MAAM,SAAS,qBAAqB;GAAE,OAAO,OAAO;GAAO,QAAQ;GAAS,CAAC;;CAGvF,eAAe,cAAc,MAA6B;EACxD,IAAI,CAAC,gBACH,MAAM,IAAI,MACR,0BAA0B,KAAK,oJAEhC;EAEH,MAAM,QAAQ,eAAe,MAAK,MAAK,EAAE,SAAS,KAAK;EACvD,IAAI,CAAC,OAAO;GACV,MAAM,YAAY,eAAe,KAAI,MAAK,EAAE,KAAK,CAAC,KAAK,KAAK,IAAI;GAChE,MAAM,IAAI,MAAM,kBAAkB,KAAK,uBAAuB,UAAU,GAAG;;EAE7E,MAAM,UAAU,qBAAqB,SAAS,OAAO,WAAW;EAChE,IAAI,YAAY,eACd,MAAM,IAAI,MACR,0BAA0B,KAAK,2BAA2B,cAAc,UAAU,oBACnF;EAEH,IAAI,YAAY,MACd,MAAM,MAAM,SAAS,mBAAmB;GAAE;GAAO,KAAK;GAAY,CAAC;;CAGvE,eAAe,gBAAgB,MAA6B;EAC1D,MAAM,UAAU,qBAAqB,WAAW,KAAK;EACrD,IAAI,SACF,MAAM,MAAM,SAAS,qBAAqB;GAAE,OAAO,QAAQ;GAAO,QAAQ;GAAY,CAAC;;CAI3F,IAAI,SAAS;EACX,MAAM,eAAe,QAAQ,KAAK,KAAK,QAAQ;EAC/C,MAAM,kBAAkB,QAAQ,QAAQ,KAAK,QAAQ;EAErD,QAAQ,OAAO,YAAY;GACzB,MAAM,cAAc;GACpB,MAAM,MAAM,SAAS,gBAAgB,EAAE,WAAW,QAAQ,IAAI,CAAC;;EASjE,QAAQ,WAAW,KAAa,UAAmB;GACjD,gBAAgB,KAAK,MAAM;GAM3B,QAAa,QAAQ,MAAM,SAAS,gBAAgB;IAAE,WAAW,QAAQ;IAAI;IAAK;IAAO,CAAC,CAAC,CAAC,OAAO,QAAiB;IAClH,QAAQ,MAAM,4CAA4C,IAAI;KAC9D;;;CAIN,IAAI,YAAY;;;;;;;;CAShB,eAAe,SAAwB;EAKrC,IAAI,WACF;EACF,IAAI,iBAAiB,cAAc,WAAW,GAC5C;EACF,IAAI,kBACF,OAAO;EAET,oBAAoB,YAAY;GAC9B,MAAM,aAAa,eACf,MAAM,aAAa,cAAc,GACjC,MAAM,kBAAkB,eAAe,KAAA,GAAW,MAAM;GAM5D,IAAI,WAAW;IACb,MAAM,WAAW,OAAO,CAAC,YAAY,GAAG;IACxC;;GAEF,gBAAgB;MACd;EAEJ,IAAI;GACF,MAAM;WAED,KAAK;GAKV,mBAAmB;GACnB,MAAM;;;CAIV,eAAe,UAAU;EAGvB,IAAI,WACF;EACF,YAAY;EAIZ,IAAI,kBACF,IAAI;GACF,MAAM;UAEF;EAKR,IAAI,eAAe;GACjB,MAAM,cAAc,OAAO;GAC3B,gBAAgB;;EAElB,IAAI,iBAAiB;GACnB,MAAM,iBAAiB,QAAQ,gBAAgB;GAC/C,kBAAkB;;EAIpB,eAAe;EACf,sBAAsB;;CASxB,IAAI,SAAS,cAAc,SAAS,GAClC,QAAa,CAAC,YAAY,GAAG;CAG/B,OAAO;EACL;EACA;EACA;EACA;EACA,UAAU;EACV;EACA;EACA;EACA;EACA;EACA;EACA,IAAI,YAAY;GAAE,OAAO;;EACzB,IAAI,QAAQ;GAAE,OAAO;;EACrB,IAAI,YAAY;GAAE,OAAO;;EACzB,IAAI,SAAS;GAAE,OAAO;;EACtB,IAAI,UAAU;GAAE,OAAO,WAAW;;EAClC,IAAI,eAAe;GAAE,OAAO,qBAAqB,QAAQ;;EAMzD,MAAM,OAAO,OAAO,EAAE,GAAG,SAAS,MAAM,CAAC;EAC1C;;;;;;;;;;;;;;;ACrnDH,SAAgB,kBAAkB,UAAkB,QAAwB;CAC1E,IAAI,OAAO,WAAW,GACpB,OAAO;CACT,IAAI,QAAQ;CACZ,IAAI,MAAM;CACV,OAAO,MAAM;EACX,MAAM,OAAO,SAAS,QAAQ,QAAQ,IAAI;EAC1C,IAAI,SAAS,IACX;EACF;EACA,MAAM,OAAO,OAAO;;CAEtB,OAAO;;;AAuBT,SAAgB,gBAAgB,KAAqB;CACnD,OAAO,IACJ,WAAA,KAAoC,IAAK,CACzC,WAAA,KAAqC,IAAK,CAC1C,WAAA,KAAoC,KAAI,CACxC,WAAA,KAAqC,KAAI;;;;;;;;;;AAW9C,MAAM,kBAA4D;CAChE,CAAC,SAAS,qBAAqB;CAC/B,CAAC,OAAO,SAAS;CACjB,CAAC,QAAQ,UAAU;CACnB,CAAC,OAAO,WAAW;CACnB,CAAC,QAAQ,YAAY;CACrB,CAAC,OAAO,UAAU;CAClB,CAAC,QAAQ,WAAW;CACpB,CAAC,OAAO,WAAW;CACnB,CAAC,QAAQ,YAAY;CACrB,CAAC,OAAO,WAAW;CACnB,CAAC,QAAQ,YAAY;CACrB,CAAC,kBAAkB,eAAe;CAClC,CAAC,gBAAgB,aAAa;CAC9B,CAAC,WAAW,QAAQ;CACpB,CAAC,YAAY,SAAS;CACtB,CAAC,WAAW,QAAQ;CACpB,CAAC,UAAU,aAAa;CACxB,CAAC,UAAU,iBAAiB;CAC7B;;;;;;;AAQD,SAAgB,WAAW,GAAmB;CAC5C,IAAI,MAAM;CACV,KAAK,MAAM,CAAC,MAAM,OAAO,iBACvB,MAAM,IAAI,WAAW,MAAM,GAAG;CAChC,OAAO;;;;;;;;;;;;;;AAeT,MAAM,wBAAwB;AAC9B,SAAgB,wBAAwB,GAAmB;CACzD,OAAO,EAAE,QAAQ,uBAAuB,GAAG;;;;;;;;;;;;;AA2C7C,SAAS,eACP,UACA,UACA,QACA,KACsB;CACtB,MAAM,MAAM,SAAS,QAAQ,OAAO;CACpC,IAAI,QAAQ,IACV,OAAO;CACT,MAAM,SAAS,SAAS,MAAM,KAAK,MAAM,OAAO,OAAO;CACvD,IAAI,MAAM;CACV,IAAI,SAAS;CACb,OAAO,MAAM;EACX,MAAM,OAAO,SAAS,QAAQ,QAAQ,OAAO;EAC7C,IAAI,SAAS,IACX;EACF;EACA,SAAS,OAAO,OAAO;;CAEzB,OAAO;EAAE;EAAQ,aAAa;EAAK;EAAK;;AAG1C,SAAgB,iBAAiB,UAAkB,QAAsC;CAEvF,MAAM,QAAQ,kBAAkB,UAAU,OAAO;CACjD,IAAI,QAAQ,GACV,OAAO;EAAE,QAAQ;EAAQ,aAAa;EAAO,KAAK;EAAS;CAM7D,MAAM,aAAa,gBAAgB,OAAO;CAC1C,MAAM,WAAW,gBAAgB,SAAS;CAC1C,IAAI,eAAe,UAAU,aAAa,UAAU;EAClD,MAAM,IAAI,eAAe,UAAU,UAAU,YAAY,SAAS;EAClE,IAAI,GACF,OAAO;;CAMX,MAAM,QAAQ,WAAW,OAAO;CAChC,IAAI,UAAU,QAAQ;EACpB,MAAM,aAAa,kBAAkB,UAAU,MAAM;EACrD,IAAI,aAAa,GACf,OAAO;GAAE,QAAQ;GAAO,aAAa;GAAY,KAAK;GAAc;;CAMxE,MAAM,QAAQ,WAAW,WAAW;CACpC,IAAI,UAAU,QAAQ;EACpB,MAAM,IAAI,eAAe,UAAU,UAAU,OAAO,oBAAoB;EACxE,IAAI,GACF,OAAO;;CAcX,MAAM,WAAW,wBAAwB,OAAO;CAChD,IAAI,aAAa,UAAU,SAAS,MAAM,CAAC,SAAS,GAAG;EACrD,MAAM,QAAQ,kBAAkB,UAAU,SAAS;EACnD,IAAI,QAAQ,GACV,OAAO;GAAE,QAAQ;GAAU,aAAa;GAAO,KAAK;GAAgB;EAItE,MAAM,eAAe,gBAAgB,SAAS;EAC9C,IAAI,iBAAiB,YAAY,aAAa,UAAU;GACtD,MAAM,IAAI,eAAe,UAAU,UAAU,cAAc,sBAAsB;GACjF,IAAI,GACF,OAAO;;;CAIb,OAAO;;;;;;;;;AAUT,SAAgB,uBACd,aACA,KACA,QACQ;CACR,IAAI,MAAM;CACV,IAAI,QAAQ,gBAAgB,QAAQ,qBAClC,MAAM,WAAW,IAAI;CACvB,IAAI,QAAQ,kBAAkB,QAAQ,uBACpC,MAAM,wBAAwB,IAAI;CACpC,IAAI,QAAQ,YAAY,QAAQ,uBAAuB,QAAQ,uBAC7D,MAAM,mBAAmB,QAAQ,IAAI;CACvC,OAAO;;;;;;;;;;;;;AAcT,SAAgB,mBAAmB,QAAgB,aAA6B;CAC9E,MAAM,YAAY,OAAO,SAAA,IAAiC,IAAI,OAAO,SAAA,IAAkC;CACvG,MAAM,YAAY,OAAO,SAAA,IAAiC,IAAI,OAAO,SAAA,IAAkC;CACvG,IAAI,CAAC,aAAa,CAAC,WACjB,OAAO;CAET,IAAI,MAAM;CACV,IAAI,WACF,MAAM,WAAW,KAAK,MAAA,KAAA,KAAwD,MAAM;CACtF,IAAI,WACF,MAAM,WAAW,KAAK,KAAA,KAAA,KAAyD,KAAK;CACtF,OAAO;;AAGT,SAAS,WACP,GACA,UACA,MACA,OACA,kBACQ;CACR,MAAM,QAAQ,CAAC,GAAG,EAAE;CACpB,MAAM,SAAmB,EAAE;CAC3B,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,IAAI,MAAM,OAAO,UAAU;GACzB,OAAO,KAAK,MAAM,GAAG;GACrB;;EAEF,IAAI,kBAAkB;GACpB,MAAM,OAAO,IAAI,IAAI,MAAM,IAAI,KAAK;GACpC,MAAM,OAAO,IAAI,MAAM,SAAS,IAAI,MAAM,IAAI,KAAK;GAEnD,IAAI,SAAS,KAAK,KAAK,IAAI,SAAS,KAAK,KAAK,EAAE;IAC9C,OAAO,KAAK,MAAM;IAClB;;;EAGJ,OAAO,KAAK,iBAAiB,OAAO,EAAE,GAAG,OAAO,MAAM;;CAExD,OAAO,OAAO,KAAK,GAAG;;AAGxB,SAAS,iBAAiB,OAAiB,GAAoB;CAC7D,IAAI,MAAM,GACR,OAAO;CACT,MAAM,OAAO,MAAM,IAAI;CACvB,OAAO,SAAS,OAAO,SAAS,OAAQ,SAAS,QAAQ,SAAS,QAC7D,SAAS,OAAO,SAAS,OAAO,SAAS,OACzC,SAAS,OAAY,SAAS;;;;;;;;;;;;AC9SrC,eAAsB,gBACpB,WACA,QACA,MACwB;CACxB,MAAM,QAAQ,KAAK,YAAY,IAAI;CACnC,MAAM,MAAM,UAAU,KAAK,MAAO,KAAK,MAAM,GAAG,MAAM,IAAI;CAC1D,MAAM,SAAS,UAAU,KAAK,OAAO,KAAK,MAAM,QAAQ,EAAE;CAC1D,MAAM,MAAM,OAAO,YAAY,IAAI;CACnC,MAAM,aAAa,QAAQ,KAAK,SAAS,OAAO,MAAM,GAAG,IAAI;CAE7D,IAAI,WAAW,WAAW,GACxB,OAAO;CAET,IAAI;CACJ,IAAI;EACF,UAAU,MAAM,UAAU,UAAU,QAAQ,IAAI;SAE5C;EACJ,OAAO;;CAGT,KAAK,MAAM,SAAS,SAAS;EAC3B,IAAI,UAAU,QACZ;EACF,MAAM,WAAW,MAAM,YAAY,IAAI;EAEvC,KADkB,aAAa,KAAK,QAAQ,MAAM,MAAM,GAAG,SAAS,MAClD,YAChB,OAAO;;CAEX,OAAO;;;;;;;AAQT,eAAsB,cACpB,WACA,QACA,MACiB;CACjB,MAAM,UAAU,MAAM,gBAAgB,WAAW,QAAQ,KAAK;CAC9D,OAAO,UAAU,iBAAiB,QAAQ,KAAK;;;;;;;;;;;;ACrDjD,MAAa,OAAgB;CAC3B,MAAM;EACJ,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,YAAY;IACV,MAAM;KAAE,MAAM;KAAU,aAAa;KAAuB;IAC5D,YAAY;KAAE,MAAM;KAAU,aAAa;KAA4B;IACvE,YAAY;KAAE,MAAM;KAAU,aAAa;KAA0B;IACrE,aAAa;KAAE,MAAM;KAAW,aAAa;KAA6C;IAC3F;GACD,UAAU;IAAC;IAAQ;IAAc;IAAa;GAC/C;EACF;CACD,MAAM,QAAQ,EAAE,MAAM,YAAY,YAAY,eAAe,KAAkB;EAC7E,MAAM,SAAS;EACf,MAAM,OAAO;EACb,MAAM,cAAc;EACpB,MAAM,aAAa,gBAAgB;EAEnC,IAAI,SAAS,aACX,OAAO,8EAA8E,OAAO;EAE9F,IAAI,KAAK,WAAW,GAClB,OAAO;EAET,IAAI;EACJ,IAAI;GACF,WAAW,MAAM,IAAI,UAAU,SAAS,IAAI,QAAQ,OAAO;UAEvD;GAEJ,OAAO,+BAA+B,OAAO,GAAG,MAD7B,cAAc,IAAI,WAAW,IAAI,QAAQ,OAAO;;EAUrE,IAAI,IAAI,UAAU,yBAAyB,IAAI,SAAS;GACtD,MAAM,YAAY,aAAa,IAAI,QAAQ;GAC3C,MAAM,SAAS,GAAG,IAAI,OAAO,IAAI,IAAI;GACrC,MAAM,QAAQ,WAAW,IAAI,OAAO;GACpC,IAAI,CAAC,OACH,OAAO,eAAe,OAAO;GAC/B,IAAI,MAAM,gBAAgB,YAAY,SAAS,EAC7C,OAAO,eAAe,OAAO;;EAQjC,MAAM,QAAQ,iBAAiB,UAAU,KAAK;EAE9C,IAAI,CAAC,OAAO;GACV,MAAM,UAAU,oBAAoB,UAAU,KAAK;GACnD,OAAO,UACH,uCAAuC,OAAO,+BAA+B,YAC7E,uCAAuC,OAAO;;EAGpD,MAAM,EAAE,QAAQ,aAAa,QAAQ;EAErC,IAAI,cAAc,KAAK,CAAC,YACtB,OAAO,kCAAkC,YAAY,YAAY,OAAO;EAE1E,MAAM,oBAAoB,uBAAuB,aAAa,KAAK,OAAO;EAE1E,MAAM,UAAU,aACZ,SAAS,MAAM,OAAO,CAAC,KAAK,kBAAkB,GAC9C,SAAS,QAAQ,QAAQ,kBAAkB;EAE/C,IAAI,YAAY,UACd,OAAO,iDAAiD,OAAO;EAEjE,MAAM,IAAI,UAAU,UAAU,IAAI,QAAQ,QAAQ,QAAQ;EAM1D,IAAI,IAAI,SAAS;GACf,MAAM,YAAY,aAAa,IAAI,QAAQ;GAC3C,MAAM,SAAS,GAAG,IAAI,OAAO,IAAI,IAAI;GACrC,MAAM,QAAQ,WAAW,IAAI,OAAO;GACpC,IAAI,aAAa,OACf,UAAU,IAAI,QAAQ;IAAE,GAAG;IAAO,aAAa,YAAY,QAAQ;IAAE,SAAS,KAAK,KAAK;IAAE,CAAC;;EAI/F,OAAO,UAAU,OAAO,aAAa,YAAY,aAAa,gBAAgB,IAAI,KAAK,IAAI;;CAE9F;;;;;;;;;;AAWD,SAAS,oBAAoB,UAAkB,QAA+B;CAK5E,MAAM,kBADmB,wBAAwB,OACT,CAAC,MAAM,KAAK,CAAC;CACrD,IAAI,gBAAgB,SAAS,GAC3B,OAAO;CAET,MAAM,QAAQ,SAAS,MAAM,KAAK;CAClC,IAAI,YAAY;CAChB,IAAI,UAAU;CACd,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,QAAQ,mBAAmB,MAAM,IAAI,gBAAgB;EAC3D,IAAI,QAAQ,WAAW;GACrB,YAAY;GACZ,UAAU;;;CAGd,IAAI,UAAU,KAAK,YAAY,KAAK,IAAI,GAAG,KAAK,MAAM,gBAAgB,SAAS,EAAE,CAAC,EAChF,OAAO;CAET,MAAM,UAAU,MAAM,SAAS,MAAM,GAAG,GAAG;CAC3C,OAAO,QAAQ,UAAU,EAAE,IAAI,KAAK,UAAU,QAAQ;;AAGxD,SAAS,mBAAmB,GAAW,GAAmB;CACxD,MAAM,MAAM,KAAK,IAAI,EAAE,QAAQ,EAAE,OAAO;CACxC,IAAI,IAAI;CACR,OAAO,IAAI,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,EACnD;CACF,OAAO;;;;;;;;;;;;;;;;;;;;;ACpIT,MAAM,gBAAgB;AAKtB,MAAM,uBAAuB;AAE7B,eAAe,cAAc,SAAiB,KAAa,OAAkC;CAE3F,MAAM,OAAO,IAAI,IAAI,KAAK,QAAQ;CAClC,MAAM,UAAoB,EAAE;CAC5B,WAAW,MAAM,QAAQ,KAAK,KAAK,EAAE,KAAK,CAAC,EAAE;EAC3C,QAAQ,KAAK,KAAK;EAClB,IAAI,QAAQ,UAAU,OACpB;;CAEJ,OAAO,QAAQ,MAAM;;AAGvB,eAAe,aAAa,SAAiB,KAAkB,OAAkC;CAG/F,IAAI,CAAC,qBAAqB,KAAK,QAAQ,EACrC,MAAM,IAAI,MAAM,qGAAqG;CASvH,MAAM,YAAY,GAHH,CADM,QAAQ,SAAS,IAAI,GAEtC,yBAAyB,QAAQ,KACjC,2BAA2B,QAAQ,GACX,gDAAgD;CAC5E,MAAM,SAAS,MAAM,IAAI,UAAU,KAAK,IAAI,QAAQ,UAAU;CAC9D,IAAI,OAAO,aAAa,KAAK,CAAC,OAAO,QACnC,OAAO,EAAE;CACX,OAAO,OAAO,OAAO,MAAM,KAAK,CAAC,QAAO,SAAQ,KAAK,SAAS,EAAE;;AAGlE,MAAa,OAAgB;CAC3B,MAAM;EACJ,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,YAAY;IACV,SAAS;KACP,MAAM;KACN,aAAa;KACd;IACD,OAAO;KACL,MAAM;KACN,aAAa,iDAAiD,cAAc;KAC7E;IACD,UAAU;KACR,MAAM;KACN,aAAa;KACd;IACF;GACD,UAAU,CAAC,UAAU;GACtB;EACF;CACD,MAAM,QAAQ,EAAE,SAAS,OAAO,YAAY,KAAkB;EAC5D,MAAM,MAAM;EACZ,MAAM,MAAM,OAAO,UAAU,YAAY,QAAQ,IAAI,QAAQ;EAC7D,MAAM,eAAe,aAAa;EAElC,IAAI;GACF,MAAM,UAAU,IAAI,UAAU,SAAS,YACnC,MAAM,cAAc,KAAK,IAAI,OAAO,KAAK,IAAI,GAC7C,MAAM,aAAa,KAAK,KAAK,IAAI;GACrC,IAAI,QAAQ,WAAW,GACrB,OAAO;GAKT,IAAI,CAAC,gBAAgB,IAAI,UAAU,SAAS,WAC1C,OAAO,QAAQ,KAAK,KAAK;GAa3B,QAAO,MAXY,QAAQ,IAAI,QAAQ,IAAI,OAAO,QAAQ;IACxD,IAAI;KACF,MAAM,IAAI,MAAM,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,CAAC;KAClD,OAAO,GAAG,IAAI,IAAI,EAAE,KAAK,IAAI,IAAI,KAAK,EAAE,QAAQ,CAAC,aAAa;YAE1D;KAGJ,OAAO,GAAG,IAAI;;KAEhB,CAAC,EACS,KAAK,KAAK;WAEjB,KAAK;GAEV,OAAO,eADS,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;;;CAIrE;;;;;;;;;;;;;;;;;;;;AClGD,MAAM,qBAAqB;AAC3B,MAAM,sBAAkC;AAoBxC,MAAa,OAAgB;CAC3B,MAAM;EACJ,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,YAAY;IACV,WAAW;KAAE,MAAM;KAAU,aAAa;KAA6D;IACvG,QAAQ;KAAE,MAAM;KAAU,aAAa;KAA8C;IACrF,QAAQ;KAAE,MAAM;KAAU,aAAa;KAAyD;IAChG,QAAQ;KAAE,MAAM;KAAU,aAAa;KAA0E;IACjH,eAAe;KAAE,MAAM;KAAU,MAAM;MAAC;MAAW;MAAsB;MAAQ;KAAE,aAAa;KAAkC;IAClI,MAAM;KAAE,MAAM;KAAW,aAAa;KAA2B;IACjE,MAAM;KAAE,MAAM;KAAW,aAAa;KAAoD;IAC1F,MAAM;KAAE,MAAM;KAAW,aAAa;KAA6C;IACnF,MAAM;KAAE,MAAM;KAAW,aAAa;KAA4C;IAClF,MAAM;KAAE,MAAM;KAAW,aAAa;KAA4E;IAClH,aAAa;KAAE,MAAM;KAAW,aAAa;KAAmD;IAChG,cAAc;KAAE,MAAM;KAAW,aAAa;KAA0D;IACxG,UAAU;KAAE,MAAM;KAAW,aAAa;KAAqC;IAChF;GACD,UAAU,CAAC,UAAU;GACtB;EACF;CACD,MAAM,QAAQ,UAAU,KAAkB;EACxC,MAAM,QAAQ;EAGd,IAAI,MADgB,mBAAmB,IAAI,EAEzC,OAAO,cAAc,OAAO,IAAI;EAElC,IAAI,IAAI,UAAU,SAAS,WACzB,OAAO,aAAa,OAAO,IAAI;EAEjC,OAAO;;CAEV;;;;;;;;;AAcD,eAAe,mBAAmB,KAAoC;CAEpE,QAAO,MADc,IAAI,UAAU,KAAK,IAAI,QAAQ,eAAe,EACrD,aAAa;;AAG7B,eAAe,cAAc,OAAkB,KAAmC;CAChF,MAAM,OAAO,CAAC,KAAK;CACnB,MAAM,OAAQ,MAAM,eAAe;CAEnC,IAAI,SAAS,sBACX,KAAK,KAAK,uBAAuB;MAC9B,IAAI,SAAS,SAChB,KAAK,KAAK,UAAU;MAEpB,KAAK,KAAM,MAAM,SAAS,OAAQ,kBAAkB,mBAAmB;CAEzE,IAAI,MAAM,OACR,KAAK,KAAK,KAAK;CAEjB,IAAI,SAAS,WAAW;EACtB,IAAI,OAAO,MAAM,UAAU,UACzB,KAAK,KAAK,MAAM,OAAO,MAAM,MAAM,CAAC;EACtC,IAAI,OAAO,MAAM,UAAU,UACzB,KAAK,KAAK,MAAM,OAAO,MAAM,MAAM,CAAC;EACtC,IAAI,OAAO,MAAM,UAAU,YAAY,OAAO,MAAM,UAAU,YAAY,OAAO,MAAM,UAAU,UAC/F,KAAK,KAAK,MAAM,OAAO,MAAM,MAAM,CAAC;;CAGxC,IAAI,MAAM,WACR,KAAK,KAAK,eAAe,qBAAqB;CAEhD,IAAI,MAAM,MACR,KAAK,KAAK,UAAU,MAAM,KAAK;CAEjC,IAAI,MAAM,MACR,KAAK,KAAK,UAAU,MAAM,KAAK;CAEjC,KAAK,KAAK,MAAM,MAAM,QAAQ;CAI9B,KAAK,KAAK,MAAM,QAAQ,IAAI;CAE5B,MAAM,UAAU,KAAK,IAAI,WAAW,CAAC,KAAK,IAAI;CAC9C,MAAM,SAAS,MAAM,IAAI,UAAU,KAAK,IAAI,QAAQ,QAAQ;CAG5D,IAAI,OAAO,aAAa,KAAK,OAAO,aAAa,GAC/C,OAAO,eAAe,OAAO,OAAO,MAAM,IAAI,uBAAuB,OAAO;CAG9E,OAAO,gBAAgB,OAAO,QAAQ,MAAM;;AAO9C,eAAe,aAAa,OAAkB,KAAmC;CAC/E,MAAM,OAAQ,MAAM,eAAe;CACnC,MAAM,QAAQ,GAAG,MAAM,QAAQ,MAAM,KAAK,MAAM,YAAY,MAAM,KAAK,SAAS,YAAY,KAAK;CAEjG,IAAI;CACJ,IAAI;EACF,QAAQ,IAAI,OAAO,MAAM,SAAS,SAAS,KAAA,EAAU;UAEhD,KAAK;EACV,OAAO,8BAA+B,IAAc;;CAGtD,MAAM,QAAQ,MAAM,eAAe,OAAO,IAAI;CAC9C,MAAM,kBAAkB,MAAM,SAAS;CACvC,MAAM,SAAU,MAAM,SAAS,MAAM,SAAS;CAC9C,MAAM,QAAS,MAAM,SAAS,MAAM,SAAS;CAE7C,MAAM,QAAkB,EAAE;CAC1B,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI;EACJ,IAAI;GACF,UAAU,MAAM,IAAI,UAAU,SAAS,IAAI,QAAQ,KAAK;UAEpD;GACJ;;EAEF,IAAI,MAAM,WAAW;GAEnB,MAAM,aAAa,CAAC,GAAG,QAAQ,SAAS,IAAI,OAAO,MAAM,QAAQ,GAAG,MAAM,QAAQ,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC;GAChG,IAAI,WAAW,WAAW,GACxB;GACF,IAAI,SAAS,sBAAsB;IACjC,MAAM,KAAK,KAAK;IAChB;;GAEF,IAAI,SAAS,SAAS;IACpB,MAAM,KAAK,GAAG,KAAK,GAAG,WAAW,SAAS;IAC1C;;GAGF,KAAK,MAAM,KAAK,YAAY;IAC1B,MAAM,YAAY,QAAQ,YAAY,MAAM,EAAE,QAAS,EAAE,GAAG;IAC5D,MAAM,UAAU,QAAQ,QAAQ,MAAM,EAAE,MAAO;IAC/C,MAAM,UAAU,QAAQ,MAAM,WAAW,YAAY,KAAK,KAAA,IAAY,QAAQ;IAC9E,MAAM,SAAS,QAAQ,MAAM,GAAG,EAAE,MAAO,CAAC,MAAM,KAAK,CAAC;IACtD,MAAM,KAAK,kBAAkB,MAAM,QAAQ,SAAS,gBAAgB,CAAC;;GAEvE;;EAGF,MAAM,YAAY,QAAQ,MAAM,KAAK;EACrC,MAAM,UAAoB,EAAE;EAC5B,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;GACzC,MAAM,YAAY;GAClB,IAAI,MAAM,KAAK,UAAU,GAAG,EAC1B,QAAQ,KAAK,EAAE;;EAEnB,IAAI,QAAQ,WAAW,GACrB;EAEF,IAAI,SAAS,sBAAsB;GACjC,MAAM,KAAK,KAAK;GAChB;;EAEF,IAAI,SAAS,SAAS;GACpB,MAAM,KAAK,GAAG,KAAK,GAAG,QAAQ,SAAS;GACvC;;EAGF,MAAM,iCAAiB,IAAI,KAAa;EACxC,KAAK,MAAM,KAAK,SACd,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,IAAI,OAAO,EAAE,KAAK,KAAK,IAAI,UAAU,SAAS,GAAG,IAAI,MAAM,EAAE,KACpF,eAAe,IAAI,EAAE;EAEzB,MAAM,SAAS,CAAC,GAAG,eAAe,CAAC,MAAM,GAAG,MAAM,IAAI,EAAE;EACxD,IAAI,OAAO;EACX,KAAK,MAAM,UAAU,QAAQ;GAC3B,IAAI,SAAS,OAAO,KAAK,MAAM,SAAS,GACtC,MAAM,KAAK,KAAK;GAClB,MAAM,UAAU,UAAU;GAC1B,MAAM,KAAK,kBAAkB,MAAM,SAAS,GAAG,SAAS,gBAAgB,CAAC;GACzE,OAAO;;;CAIX,OAAO,gBAAgB,MAAM,KAAK,KAAK,EAAE,MAAM;;AAGjD,SAAS,kBAAkB,MAAc,QAAgB,SAAiB,iBAAkC;CAC1G,OAAO,kBAAkB,GAAG,KAAK,GAAG,OAAO,GAAG,YAAY,GAAG,KAAK,GAAG;;AAGvE,eAAe,eAAe,OAAkB,KAAqC;CACnF,MAAM,MAAM,IAAI,OAAO;CACvB,MAAM,OAAO,MAAM,QAAQ;CAI3B,IAAI,MAAM,QAAQ,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,EACtE,IAAI;EAEF,KAAI,MADe,IAAI,UAAU,KAAK,IAAI,QAAQ,WAAW,WAAW,MAAM,KAAK,CAAC,2BAA2B,EACtG,OAAO,MAAM,KAAK,QACzB,OAAO,CAAC,MAAM,KAAK;SAEjB;CAGR,MAAM,UAAU,MAAM,QAAQ;CAC9B,MAAM,OAAO,IAAI,IAAI,KAAK,QAAQ;CAClC,MAAM,MAAgB,EAAE;CACxB,MAAM,WAAW,SAAS,MAAM,MAAM,GAAG,IAAI,QAAQ,OAAO,GAAG,CAAC,GAAG,KAAK,QAAQ,SAAS,GAAG;CAC5F,WAAW,MAAM,QAAQ,KAAK,KAAK;EAAE,KAAK;EAAU,WAAW;EAAM,CAAC,EACpE,IAAI,KAAK,SAAS,MAAM,OAAO,GAAG,KAAK,QAAQ,OAAO,GAAG,CAAC,GAAG,OAAO;CAEtE,OAAO,IAAI,MAAM;;AAGnB,SAAS,gBAAgB,MAAc,OAA0B;CAC/D,MAAM,YAAY,OAAO,MAAM,eAAe,YAAY,MAAM,cAAc,IAC1E,MAAM,aACN;CACJ,MAAM,SAAS,OAAO,MAAM,WAAW,YAAY,MAAM,SAAS,IAC9D,KAAK,MAAM,MAAM,OAAO,GACxB;CAEJ,IAAI,CAAC,KAAK,MAAM,EACd,OAAO;CAET,MAAM,QAAQ,KAAK,MAAM,KAAK,CAAC,QAAO,MAAK,EAAE,SAAS,EAAE;CACxD,MAAM,QAAQ,MAAM;CAEpB,MAAM,SAAS,cAAc,IACzB,MAAM,MAAM,OAAO,GACnB,MAAM,MAAM,QAAQ,SAAS,UAAU;CAE3C,IAAI,OAAO,WAAW,GACpB,OAAO;CAET,MAAM,gBAAgB,SAAS;CAC/B,MAAM,gBAAgB,YAAY,KAAK,SAAS,YAAY;CAE5D,IAAI,MAAM,OAAO,KAAK,KAAK;CAC3B,IAAI,eACF,MAAM,KAAK,OAAO,8BAA8B;CAClD,IAAI,eACF,MAAM,GAAG,IAAI,MAAM,QAAQ,SAAS,UAAU,oCAAoC,SAAS,UAAU;CACvG,OAAO;;;;;;;;;;;AClQT,SAAgB,sBAAsB,SAA0C;CAI9E,OAAO;EACL,MAAM;GACJ,MALS,QAAQ,QAAQ;GAMzB,aALgB,QAAQ,eAAe;GAMvC,aAAa,QAAQ;GACtB;EACD,MAAM,QAAQ,OAAO,KAAK;GACxB,MAAM,SAAS,MAAM,QAAQ,UAAU,OAAO,IAAI;GAElD,OAAO,OAAO,WAAW,WAAW,SAAS,KAAK,UAAU,OAAO;;EAEtE;;;;ACnDH,MAAa,YAAqB;CAChC,MAAM;EACJ,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,YAAY,EACV,MAAM;IAAE,MAAM;IAAU,aAAa;IAA0C,EAChF;GACD,UAAU,EAAE;GACb;EACF;CACD,MAAM,QAAQ,EAAE,QAAQ,KAAkB;EACxC,IAAI;GAEF,QAAO,MADe,IAAI,UAAU,UAAU,IAAI,QAAS,QAAmB,IAAI,EACnE,KAAK,KAAK,IAAI;UAEzB;GACJ,OAAO,wBAAwB;;;CAGpC;;;ACCD,MAAa,YAAqB;CAChC,MAAM;EACJ,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,YAAY;IACV,MAAM;KAAE,MAAM;KAAU,aAAa;KAAuB;IAC5D,OAAO;KACL,MAAM;KACN,aAAa;KACb,OAAO;MACL,MAAM;MACN,YAAY;OACV,YAAY,EAAE,MAAM,UAAU;OAC9B,YAAY,EAAE,MAAM,UAAU;OAC9B,aAAa,EAAE,MAAM,WAAW;OACjC;MACD,UAAU,CAAC,cAAc,aAAa;MACvC;KACF;IACF;GACD,UAAU,CAAC,QAAQ,QAAQ;GAC5B;EACF;CACD,MAAM,QAAQ,EAAE,MAAM,SAAS,KAAkB;EAC/C,MAAM,SAAS;EACf,MAAM,QAAQ;EAEd,IAAI,CAAC,MAAM,QAAQ,MAAM,IAAI,MAAM,WAAW,GAC5C,OAAO;EAET,IAAI;EACJ,IAAI;GACF,UAAU,MAAM,IAAI,UAAU,SAAS,IAAI,QAAQ,OAAO;UAEtD;GAEJ,OAAO,qCAAqC,OAAO,GAAG,MADnC,cAAc,IAAI,WAAW,IAAI,QAAQ,OAAO;;EAMrE,IAAI,IAAI,UAAU,yBAAyB,IAAI,SAAS;GACtD,MAAM,YAAY,aAAa,IAAI,QAAQ;GAC3C,MAAM,SAAS,GAAG,IAAI,OAAO,IAAI,IAAI;GACrC,MAAM,QAAQ,WAAW,IAAI,OAAO;GACpC,IAAI,CAAC,OACH,OAAO,qBAAqB,OAAO;GACrC,IAAI,MAAM,gBAAgB,YAAY,QAAQ,EAC5C,OAAO,qBAAqB,OAAO;;EAGvC,IAAI,UAAU;EACd,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;GACrC,MAAM,OAAO,MAAM;GACnB,MAAM,OAAO,KAAK;GAClB,MAAM,cAAc,KAAK;GACzB,MAAM,aAAa,KAAK,gBAAgB;GAExC,IAAI,OAAO,SAAS,YAAY,OAAO,gBAAgB,UACrD,OAAO,2BAA2B,IAAI,EAAE;GAE1C,IAAI,KAAK,WAAW,GAClB,OAAO,2BAA2B,IAAI,EAAE;GAE1C,IAAI,SAAS,aACX,OAAO,2BAA2B,IAAI,EAAE;GAE1C,MAAM,QAAQ,iBAAiB,SAAS,KAAK;GAC7C,IAAI,CAAC,OACH,OAAO,2BAA2B,IAAI,EAAE,2BAA2B,OAAO;GAE5E,MAAM,EAAE,QAAQ,aAAa,QAAQ;GACrC,IAAI,cAAc,KAAK,CAAC,YACtB,OAAO,2BAA2B,IAAI,EAAE,sBAAsB,YAAY;GAE5E,MAAM,oBAAoB,uBAAuB,aAAa,KAAK,OAAO;GAE1E,UAAU,aACN,QAAQ,MAAM,OAAO,CAAC,KAAK,kBAAkB,GAC7C,QAAQ,QAAQ,QAAQ,kBAAkB;GAC9C,WAAW;;EAGb,MAAM,IAAI,UAAU,UAAU,IAAI,QAAQ,QAAQ,QAAQ;EAG1D,IAAI,IAAI,SAAS;GACf,MAAM,YAAY,aAAa,IAAI,QAAQ;GAC3C,MAAM,SAAS,GAAG,IAAI,OAAO,IAAI,IAAI;GACrC,MAAM,QAAQ,WAAW,IAAI,OAAO;GACpC,IAAI,aAAa,OACf,UAAU,IAAI,QAAQ;IAAE,GAAG;IAAO,aAAa,YAAY,QAAQ;IAAE,SAAS,KAAK,KAAK;IAAE,CAAC;;EAI/F,OAAO,UAAU,OAAO,YAAY,MAAM,OAAO,OAAO,MAAM,WAAW,IAAI,KAAK,IAAI,IAAI,QAAQ,cAAc,YAAY,IAAI,KAAK,IAAI;;CAE5I;;;;;;;;;ACnGD,SAAgB,kBAAkB,MAAkC;CAClE,MAAM,MAAM,KAAK,YAAY,IAAI;CACjC,IAAI,QAAQ,IACV,OAAO,KAAA;CAET,QADY,KAAK,MAAM,MAAM,EAAE,CAAC,aACrB,EAAX;EACE,KAAK,OACH,OAAO;EACT,KAAK;EACL,KAAK,QACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,SACE;;;;;;;;;;;;AAaN,eAAsB,iBACpB,WACA,QACA,MACiD;CACjD,IAAI,UAAU,gBAAgB;EAC5B,MAAM,QAAQ,MAAM,UAAU,eAAe,QAAQ,KAAK;EAE1D,OAAO;GAAE,QADG,OAAO,KAAK,MAAM,QAAQ,MAAM,YAAY,MAAM,WAAW,CAAC,SAAS,SAC/D;GAAE,YAAY,MAAM;GAAY;;CAOtD,MAAM,MAAM,YAAY,YAAY,KAAK;CACzC,MAAM,SAAS,MAAM,UAAU,KAAK,QAAQ,IAAI;CAChD,IAAI,OAAO,aAAa,GACtB,MAAM,IAAI,MAAM,uBAAuB,OAAO,UAAU,QAAQ,OAAO,aAAa;CAEtF,MAAM,MAAM,OAAO,OAAO,QAAQ,QAAQ,GAAG;CAC7C,OAAO;EAAE,QAAQ;EAAK,YAAY,wBAAwB,IAAI;EAAE;;;;;;;AAQlE,SAAS,wBAAwB,KAAqB;CACpD,IAAI,IAAI,WAAW,GACjB,OAAO;CACT,IAAI,MAAM;CACV,IAAI,IAAI,SAAS,KAAK,EACpB,MAAM;MACH,IAAI,IAAI,SAAS,IAAI,EACxB,MAAM;CACR,OAAO,KAAK,IAAI,GAAI,IAAI,SAAS,IAAK,IAAI,IAAI;;;;;;;;;;;;;;;;ACrEhD,MAAM,qBAAqB;AAC3B,MAAM,mBAAmB;;;;;;;;AASzB,MAAM,yBAAyB,IAAI,OAAO;AAE1C,MAAaC,aAAoB;CAC/B,MAAM;EACJ,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,YAAY;IACV,MAAM;KAAE,MAAM;KAAU,aAAa;KAAuB;IAC5D,QAAQ;KAAE,MAAM;KAAW,aAAa;KAAoD;IAC5F,OAAO;KAAE,MAAM;KAAW,aAAa;KAA4D;IACnG,UAAU;KAAE,MAAM;KAAW,aAAa;KAAgO;IAC1Q,aAAa;KAAE,MAAM;KAAW,aAAa;KAAqI;IACnL;GACD,UAAU,CAAC,OAAO;GACnB;EACF;CACD,MAAM,QAAQ,EAAE,MAAM,QAAQ,OAAO,UAAU,eAAe,KAAkB;EAM9E,MAAM,WAAW,kBAAkB,KAAe;EAClD,IAAI,UAAU;GACZ,MAAM,UAAU,aAAa,KAAA,IAAY,iBAAiB,UAAU,uBAAuB,GAAG;GAC9F,IAAI;IACF,MAAM,EAAE,QAAQ,eAAe,MAAM,iBAAiB,IAAI,WAAW,IAAI,QAAQ,KAAe;IAChG,IAAI,UAAU,KAAK,aAAa,SAC9B,OAAO,+BAA+B,KAAK,IAAI,WAAW,cAAc,QAAQ;IAMlF,OAAO,CAHL;KAAE,MAAM;KAAQ,MAAM,UAAU,KAAK,IAAI,WAAW,UAAU,SAAS;KAAI,EAC3E;KAAE,MAAM;KAAS,WAAW;KAAU,MAAM;KAAQ,CAExC;YAET,KAAK;IAGV,OAAO,sBAAsB,KAAK,KAFtB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,CAEjB,GAAG,MAD3B,cAAc,IAAI,WAAW,IAAI,QAAQ,KAAe;;;EAK/E,IAAI;EACJ,IAAI;GACF,MAAM,MAAM,IAAI,UAAU,SAAS,IAAI,QAAQ,KAAe;UAE1D;GAEJ,OAAO,mBAAmB,KAAK,GAAG,MADf,cAAc,IAAI,WAAW,IAAI,QAAQ,KAAe;;EAI7E,MAAM,aAAa,OAAO,WAAW,IAAI;EAWzC,MAAM,YADe,IAAI,UAAU,eAAe,QACjB,aAAa,IAAI,QAAQ,GAAG,KAAA;EAC7D,MAAM,SAAS,GAAG,IAAI,OAAO,IAAI,IAAI;EACrC,MAAM,eAAe,iBAAiB,QAAQ,EAAE;EAChD,MAAM,cAAc,iBAAiB,OAAO,mBAAmB;EAC/D,MAAM,iBAAiB,iBAAiB,UAAU,iBAAiB;EACnE,MAAM,kBAAkB,OAAO,gBAAgB,YAC3C,cACC,IAAI,UAAU,mBAAmB;EACtC,MAAM,cAAc,YAAY,YAAY,IAAI,GAAG;EACnD,IAAI,WAAW;GACb,MAAM,QAAQ,UAAU,IAAI,OAAO;GACnC,IACE,SACG,MAAM,gBAAgB,eACtB,MAAM,WAAW,gBACjB,MAAM,UAAU,eAChB,MAAM,aAAa,kBAKnB,MAAM,gBAAgB,iBAEzB,OAAO,QAAQ,KAAK;;EAQxB,IAAI,YAAY,IAAI,EAClB,OAAO,iBAAiB,KAAK,IAAI,WAAW;EAG9C,MAAM,UAAU;EAChB,MAAM,SAAS;EACf,MAAM,YAAY;EAElB,MAAM,QAAQ,IAAI,MAAM,KAAK;EAC7B,MAAM,aAAa,MAAM;EAGzB,MAAM,WAAW,KAAK,IAAI,GAAG,UAAU,EAAE;EACzC,MAAM,SAAS,SAAS,IAAI,KAAK,IAAI,YAAY,WAAW,OAAO,GAAG;EACtE,IAAI,QAAQ,MAAM,MAAM,UAAU,OAAO;EAOzC,IAAI,WAAW;EACf,IAAI,YAAY,GAAG;GACjB,MAAM,iBAA2B,EAAE;GACnC,IAAI,YAAY;GAChB,KAAK,MAAM,QAAQ,OAAO;IACxB,MAAM,YAAY,OAAO,WAAW,KAAK,GAAG;IAC5C,IAAI,YAAY,YAAY,aAAa,eAAe,SAAS,GAAG;KAClE,WAAW;KACX;;IAEF,eAAe,KAAK,KAAK;IACzB,aAAa;IACb,IAAI,aAAa,WAEf;;GAGJ,IAAI,eAAe,SAAS,MAAM,QAChC,WAAW;GACb,QAAQ;;EAQV,IAAI,aAAa;EACjB,IAAI,YAAY,KAAK,MAAM,SAAS;OAChB,OAAO,WAAW,MAAM,KAAK,KAAK,CACvC,GAAG,WAAW;IACzB,MAAM,UAAU,MAAM,SAAS;IAC/B,MAAM,WAAW,MAAM;IACvB,MAAM,aAAa,UAAU,IACzB,OAAO,WAAW,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,KAAK,CAAC,GAAG,IACxD;IACJ,MAAM,gBAAgB,KAAK,IAAI,GAAG,YAAY,WAAW;IAIzD,IAAI,MAAM,KAAK,IAAI,SAAS,QAAQ,cAAc;IAClD,OAAO,MAAM,KAAK,OAAO,WAAW,SAAS,MAAM,GAAG,IAAI,CAAC,GAAG,eAC5D;IACF,MAAM,WAAW,SAAS,MAAM,GAAG,IAAI;IACvC,aAAa;IACb,WAAW;;;EAKf,MAAM,eAAe,WADC,MAAM;EAS5B,MAAM,OAAO,kBACT,MAAM,KAAK,MAAM,MAAM,GAAG,WAAW,IAAI,EAAE,IAAI,OAAO,CAAC,KAAK,KAAK,GACjE,MAAM,KAAK,KAAK;EAEpB,IAAI,WACF,UAAU,IAAI,QAAQ;GACpB,aAAa;GACb,QAAQ;GACR,OAAO;GACP,UAAU;GACV,aAAa;GACb,SAAS,KAAK,KAAK;GACpB,CAAC;EAGJ,MAAM,iBAAiB,SAAS,cAAc;EAC9C,IAAI,CAAC,kBAAkB,YAAY,GACjC,OAAO;EAET,IAAI,CAAC,gBAEH,OAAO,GAAG,KAAK,kBAAkB,QAAQ,GAAG,aAAa,MAAM,WAAW;EAG5E,IAAI,YAMF,OAAO,GAAG,KAAK,kCAAkC,aAAa,aAAa,UAAU,sBAAsB,WAAW,UAAU,WAAW;EAI7I,OAAO,GAAG,KAAK,yBAAyB,aAAa,IADtC,WAAW,aAAa,UAAU,aAAa,eAAe,OAAO,WACpB,cAAc,WAAW,UAAU,WAAW,qCAAqC,eAAe,EAAE;;CAEvK;AAED,SAAS,iBAAiB,OAAgB,UAA0B;CAClE,IAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,MAAM,EACtD,OAAO;CAGT,IAAI,QAAQ,GACV,OAAO;CACT,OAAO,KAAK,MAAM,MAAM;;;;ACrO1B,MAAM,oBAAoC,cAAa;CACrD,SAAS,aAAa;CACtB,SAAS,aAAa,IAAI,iCAAiC,aAAa,KAAA;CACzE;AAED,MAAM,oBAA0D,IAAI,IAA6B;CAE/F,CAAC,SAAQ,UAAS;EAAE,SAAS,QAAQ;EAAG,SAAS,SAAS,IAAI,qBAAqB,KAAA;EAAW,EAAE;CAChG,CAAC,OAAM,UAAS;EAAE,SAAS,QAAQ;EAAG,SAAS,SAAS,IAAI,qBAAqB,KAAA;EAAW,EAAE;CAE9F,CAAC,SAAQ,UAAS;EAAE,SAAS,QAAQ;EAAG,SAAS,SAAS,IAAI,iBAAiB,KAAA;EAAW,EAAE;CAE5F,CAAC,SAAQ,UAAS;EAAE,SAAS,QAAQ;EAAG,SAAS,SAAS,IAAI,uCAAuC,KAAA;EAAW,EAAE;CAElH,CAAC,SAAQ,UAAS;EAAE,SAAS,QAAQ;EAAG,SAAS,SAAS,IAAI,uBAAuB,KAAA;EAAW,EAAE;CAClG,CAAC,MAAK,UAAS;EAAE,SAAS,QAAQ;EAAG,SAAS,SAAS,IAAI,uBAAuB,KAAA;EAAW,EAAE;CAChG,CAAC;;;;;;;AAQF,SAAgB,qBACd,SACA,UACuB;CACvB,MAAM,OAAO,uBAAuB,QAAQ;CAE5C,QADiB,kBAAkB,IAAI,KAAK,IAAI,kBAChC,SAAS;;AAG3B,SAAS,uBAAuB,SAAyB;CAIvD,MAAM,WAAW,QAAQ,MAAM,iBAAiB;CAKhD,QAJa,SAAS,SAAS,SAAS,IAAI,MAAM,IAAI,SAGlC,MAAM,MAAM,CAAC,QAAO,MAAK,CAAC,eAAe,KAAK,EAAE,CACvD,CAAC,MAAM;;;;;;;;;;;;;;;;;AC9CtB,MAAM,2BAA2B;AAEjC,MAAa,QAAiB;CAC5B,MAAM;EACJ,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,YAAY;IACV,SAAS;KAAE,MAAM;KAAU,aAAa;KAAyB;IACjE,SAAS;KAAE,MAAM;KAAW,aAAa;KAAqC;IAC9E,gBAAgB;KAAE,MAAM;KAAW,aAAa;KAAgG;IAChJ,UAAU;KAAE,MAAM;KAAW,aAAa;KAAyF;IACpI;GACD,UAAU,CAAC,UAAU;GACtB;EACF;CACD,MAAM,QAAQ,EAAE,SAAS,SAAS,gBAAgB,YAAY,KAAkB;EAI9E,MAAM,WAAiC,EAAE;EACzC,IAAI,OAAO,YAAY,YAAY,OAAO,SAAS,QAAQ,IAAI,UAAU,GACvE,SAAS,UAAU,KAAK,IAAI,GAAG,KAAK,KAAK,UAAU,IAAK,CAAC;EAE3D,MAAM,MAAM;EACZ,MAAM,eAAe,aAAa;EAClC,MAAM,YAAY,KAAK,KAAK;EAC5B,MAAM,SAAS,MAAM,IAAI,UAAU,KAAK,IAAI,QAAQ,KAAK,SAAS;EAClE,MAAM,aAAa,KAAK,KAAK,GAAG;EAEhC,MAAM,MAAM,aAAa,eAAe;EACxC,MAAM,WAAW,qBAAqB,KAAK,OAAO,SAAS;EAK3D,IAAI,OAAO,aAAa,GAAG;GACzB,MAAM,aAAa,aAAa,OAAO,UAAU,eAAe,IAAI;GACpE,IAAI,CAAC,cACH,OAAO;GACT,MAAM,gBAAgB,OAAO,OAAO,MAAM;GAI1C,OAAO,GAAG,aAHY,gBAClB,eAAe,aAAa,eAAe,KAAK,IAAI,KAAK,KAAK,CAAC,KAC/D,GACiC,aAAa,WAAW;;EAO/D,IAAI,CAAC,SAAS,SAAS;GAErB,MAAM,OAAO,cADC,OAAO,UAAU,OAAO,UAAU,IAAI,MACtB,EAAE,IAAI;GACpC,MAAM,iBAAiB,SAAS,UAAU,MAAM,SAAS,QAAQ,KAAK;GACtE,MAAM,eAAe,eAAe,WAAW,OAAO,SAAS,IAAI,WAAW,OAAO;GAErF,OAAO,GADM,KAAK,SAAS,IAAI,OAAQ,SAAS,WAAW,gBAC1C,iBAAiB;;EAOpC,MAAM,WAAW,GAAG,OAAO,OAAO,IAAI,OAAO,SAAS,MAAM;EAI5D,OAAO,GAHQ,eACX,aAAa,OAAO,SAAS,IAAI,WAAW,OAC5C,aAAa,OAAO,WACP,IAAI,aAAa,UAAU,IAAI;;CAEnD;AAED,SAAS,aAAa,OAAwB;CAC5C,IAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,MAAM,EACtD,OAAO;CACT,IAAI,QAAQ,GACV,OAAO;CACT,OAAO,KAAK,MAAM,MAAM;;;;;;;;;;;;AAa1B,SAAS,aAAa,MAAc,KAAqB;CACvD,IAAI,QAAQ,GACV,OAAO;CAET,MAAM,aAAa,OAAO,WAAW,KAAK;CAC1C,IAAI,cAAc,KAChB,OAAO;CAKT,IAAI,QAAQ;CACZ,IAAI,UAAU,KAAK;CACnB,OAAO,UAAU,GAAG;EAClB,MAAM,KAAK,KAAK,UAAU;EAC1B,MAAM,UAAU,OAAO,WAAW,GAAG;EACrC,IAAI,QAAQ,UAAU,KACpB;EACF,SAAS;EACT;;CAGF,MAAM,OAAO,KAAK,MAAM,QAAQ;CAEhC,OAAO,KADc,aAAa,OAAO,WAAW,KAAK,CAChC,gCAAgC;;;;AC7C3D,MAAM,iBAAiB;CACrB;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,sBAAsB,CAC1B,aACA,gBACD;AAQD,MAAM,mBAA2D;CAC/D,eAAe;CACf,mBAAmB;CACnB,cAAc;CACd,eAAe;CACf,cAAc;CACd,cAAc;CACd,cAAc;CACf;AAED,MAAM,wBAAoE;CACxE,aAAa;CACb,iBAAiB;CAClB;AAwBD,MAAM,uCAAuB,IAAI,SAA0B;AAE3D,SAAS,kBAAkB,SAA0B;CACnD,IAAI,UAAU,qBAAqB,IAAI,QAAQ;CAC/C,IAAI,YAAY,KAAA,GACd,UAAU,QAAQ,KAAK,QAAO,OAAM,EAAE,SAAS,KAAK,EAAE,CAAC;CACzD,WAAW;CACX,qBAAqB,IAAI,SAAS,QAAQ;CAC1C,OAAO,SAAS;;AAOlB,SAAS,YAAY,SAA0B;CAC7C,IAAI,CAAC,WAAW,OAAO,YAAY,UACjC,OAAO;CAET,MAAM,MAAM;CAEZ,IAAI,OAAO,IAAI,YAAY,UACzB,OAAO,IAAI;CAEb,IAAI,MAAM,QAAQ,IAAI,QAAQ,EAC5B,OAAO,IAAI,QACR,QAAQ,UAA4C,CAAC,CAAC,SAAS,OAAO,UAAU,YAAa,MAAkC,SAAS,OAAO,CAC/I,KAAI,UAAS,MAAM,KAAK,CACxB,KAAK,KAAK;CAGf,OAAO;;;;;;;;;;;;;;AAeT,eAAe,gBACb,MACA,WACY;CACZ,IAAI,CAAC,aAAa,aAAa,GAC7B,OAAO;CAET,IAAI;CACJ,IAAI;EACF,OAAO,MAAM,IAAI,SAAY,SAAS,WAAW;GAC/C,QAAQ,iBAAiB,OAAO,IAAI,kBAAkB,UAAU,CAAC,EAAE,UAAU;GAC7E,KAAK,KAAK,SAAS,OAAO;IAC1B;WAEI;EACN,IAAI,OACF,aAAa,MAAM;;;AAIzB,IAAM,oBAAN,cAAgC,MAAM;CACpC;CACA,YAAY,WAAmB;EAC7B,MAAM,+BAA+B,UAAU,IAAI;EACnD,KAAK,OAAO;EACZ,KAAK,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BrB,SAAS,YACP,YACA,aACA,SACA,OACY;CACZ,MAAM,cAAiC,EAAE;CAIzC,MAAM,OAAO,YAAY;CAOzB,KAAK,MAAM,OAAO,gBAAgB;EAChC,MAAM,YAAY,iBAAiB;EACnC,MAAM,aAAa,WAAW,KAAK,MAAM,QAAgB;GACvD,KAAU,WAAW;IAAE,GAAI;IAAiC;IAAS;IAAO,CAAC;IAC7E;EACF,YAAY,KAAK,WAAW;;CAM9B,MAAM,YAAY,QAAiC;EACjD,IAAI,UAAU;EACd,IAAI,QAAQ;;CAEd,KAAK,MAAM,OAAO,qBAAqB;EACrC,MAAM,YAAY,sBAAsB;EACxC,MAAM,aAAa,WAAW,KAAK,KAAK,OAAO,QAAgB;GAC7D,SAAS,IAA+B;GACxC,MAAM,KAAK,WAAW,IAA+B;IACrD;EACF,YAAY,KAAK,WAAW;;CAM9B,MAAM,YAAY,WAAW;CAI7B,KAAK,MAAM,OAAO,gBAAgB;EAChC,MAAM,YAAY,iBAAiB;EACnC,YAAY,KAAK,UAAU,YAAY,QAAQ;GAC7C,KAAU,WAAW,IAA+B;IACpD,CAAC;;CAEL,KAAK,MAAM,OAAO,qBAAqB;EACrC,MAAM,YAAY,sBAAsB;EACxC,YAAY,KAAK,UAAU,WAAW,OAAO,QAAQ;GAInD,MAAM,KAAK,WAAW,IAA+B;IACrD,CAAC;;CAGL,aAAa;EACX,KAAK,MAAM,KAAK,aAAa,GAAG;;;;;;;;;;;AA2DpC,SAAgB,gBAAgB,UAA4B,EAAE,EAA4B;CACxF,MAAM,gCAAgB,IAAI,KAAyB;CACnD,IAAI,eAAe;CACnB,IAAI,mBAAmB;CACvB,MAAM,gBAAgB,QAAQ,iBAAiB;CAC/C,MAAM,WAAW,QAAQ,YAAY;CACrC,MAAM,eAAe,QAAQ,gBAAgB;CAE7C,MAAM,aAAyB;EAC7B,SAAS;EACT,UAAU;EACV,gBAAgB;EAChB,oBAAoB;EACpB,OAAO;EACP,SAAS;EACV;CAED,OAAO;EACL,IAAI,WAAW;GAAE,OAAO;;EACxB,IAAI,kBAAkB;GAAE,OAAO,EAAE,GAAG,YAAY;;EAEhD,MAAM;GACJ,MAAM;GACN,aAAa;GACb,aAAa;IACX,MAAM;IACN,YAAY;KACV,MAAM;MACJ,MAAM;MACN,aAAa;MACd;KACD,QAAQ;MACN,MAAM;MACN,aAAa;MACd;KACF;IACD,UAAU,CAAC,OAAO;IACnB;GACF;EAED,MAAM,QAAQ,OAAgC,KAAmC;GAC/E,MAAM,OAAO,MAAM;GACnB,MAAM,iBAAiB,MAAM;GAC7B,MAAM,cAAc,IAAI,SAAS;GACjC,MAAM,aAAa,cAAc;GAKjC,IAAI,aAAa,UACf,OAAO,0BAA0B,SAAS,yBAAyB,YAAY;GAGjF,IAAI,oBAAoB,eACtB,OAAO,iBAAiB,iBAAiB,GAAG,cAAc;GAM5D,IAAI,IAAI,OAAO,SACb,OAAO,wEAAwE,KAAK,MAAM,GAAG,GAAG,CAAC;GAQnG,MAAM,KAAK,IAAI,UACX,kBAAkB,IAAI,QAAQ,GAC9B,SAAS,EAAE;GACf;GACA,MAAM,QAAoB;IAAE;IAAI;IAAM,WAAW,KAAK,KAAK;IAAE,OAAO;IAAY;GAChF,cAAc,IAAI,IAAI,MAAM;GAE5B,IAAI;GACJ,IAAI,iBAAuD;GAC3D,IAAI;GACJ,IAAI,SAAS;GAIb,IAAI;GAEJ,IAAI;IAUF,MAAM,QAAQ,YAAY;KARxB,GAAI,IAAI,SAAS,KAAA,IAAY,EAAE,MAAM,IAAI,MAAM,GAAG,EAAE;KACpD,GAAI,IAAI,WAAW,KAAA,IAAY,EAAE,QAAQ,IAAI,QAAQ,GAAG,EAAE;KAC1D,OAAO,IAAI;KACX,GAAI,IAAI,gBAAgB,KAAA,IAAY,EAAE,aAAa,IAAI,aAAa,GAAG,EAAE;KACzE,GAAI,IAAI,eAAe,KAAA,IAAY,EAAE,YAAY,IAAI,YAAY,GAAG,EAAE;KACtE,GAAI,IAAI,WAAW,KAAA,IAAY,EAAE,QAAQ,IAAI,QAAQ,GAAG,EAAE;KAC1D,GAAI,IAAI,aAAa,KAAA,IAAY,EAAE,UAAU,IAAI,UAAU,GAAG,EAAE;KAIhE,GAAG,QAAQ;KACX,UAAU,IAAI;KACd,WAAW,IAAI;KAIf,GAAI,QAAQ,WAAW,IAAI,UAAU,EAAE,SAAS,IAAI,SAAS,GAAG,EAAE;KACnE,CAAC;IAEF,IAAI,cACF,WAAW,YAAY,MAAM,OAAO,IAAI,OAAO,IAAI,WAAW;IAEhE,QAAQ,UAAU,MAAM;IACxB,MAAM,IAAI,MAAM,SAAS,gBAAgB;KAAE;KAAI;KAAM,OAAO;KAAY,CAAC;IAOzE,MAAM,aAAa,MAAM,IAAI;KAC3B,QAAQ;KACR,OAAO,QAAQ;KACf,QAAQ,kBAAkB,QAAQ;KAClC,UAAU,QAAQ;KAClB,QAAQ,IAAI;KACZ,OAAO;KACP,GAAI,QAAQ,WAAW,IAAI,QAAQ,EAAE,aAAa,IAAI,OAAO,GAAG,EAAE;KACnE,CAAC;IAEF,IAAI;KACF,aAAa,MAAM,gBAAgB,YAAY,QAAQ,UAAU;KAOjE,MAAM,YAAY,aAAa,WAAW,CAAC;KAI3C,MAAM,QAAQ,iBAAiB,WAAW;KAC1C,IAAI,IAAI,OAAO,SAAS;MACtB,iBAAiB;MACjB,SAAS,CACP,cAAc,GAAG,kBAAkB,UAAU,UAAU,WAAW,QAAQ,MAC1E,WAAW,QACZ,CAAC,KAAK,KAAK;YAET;MACH,MAAM,WAAW,YAAY,MAAM,MAAM,GAAG,GAAG,CAAC;MAChD,SAAS;OACP,cAAc,GAAG,iBAAiB,UAAU,UAAU,WAAW,QAAQ;OACzE,WAAW;OACX;OACA,YAAY;OACb,CAAC,KAAK,KAAK;;aAGT,KAAK;KACV,IAAI,eAAe,mBAAmB;MACpC,iBAAiB;MACjB,MAAM,OAAO;MAIb,IAAI;OACF,aAAa,MAAM;cAEf;OACJ,aAAa;QACX,SAAS;QACT,UAAU;QACV,gBAAgB;QAChB,oBAAoB;QACpB,OAAO;QACP,SAAS,IAAI;QACd;;MAEH,SAAS,cAAc,GAAG,oBAAoB,IAAI,UAAU;YAEzD;MACH,MAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC;MACjE,iBAAiB;MACjB,aAAa;OACX,SAAS;OACT,UAAU;OACV,gBAAgB;OAChB,oBAAoB;OACpB,OAAO;OACP,SAAS;OACV;MACD,SAAS,cAAc,GAAG,WAAW,MAAM;MAC3C,MAAM,IAAI,MAAM,SAAS,eAAe;OAAE;OAAI;OAAM,OAAO;OAAY;OAAO,CAAC;;cAG3E;KAGN,IAAI;MACF,MAAM,MAAM,SAAS;cAEhB,KAAK;MACV,eAAe,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC;;;IAMtE,IAAI,YAAY;KACd,WAAW,WAAW,WAAW;KACjC,WAAW,YAAY,WAAW;KAClC,WAAW,kBAAkB,WAAW;KACxC,WAAW,sBAAsB,WAAW;KAC5C,WAAW,SAAS,WAAW;KAI/B,WAAW,WAAW,WAAW;;IAMnC,MAAM,gBAA+B;KACnC;KACA;KACA,OAAO;KACP,OAAO;KACP,QAAQ;KACR,GAAI,WAAY,SAAS,EAAE,QAAQ,WAAY,QAAQ,GAAG,EAAE;KAC7D;IACD,QAAQ,aAAa,OAAO,YAAa,eAAe;IACxD,MAAM,IAAI,MAAM,SAAS,kBAAkB,cAAc;IAEzD,IAAI,cAGF,MAAM,IAAI,MAAM,SAAS,eAAe;KACtC;KACA;KACA,OAAO;KACP,OAAO;KACR,CAAC;IAGJ,OAAO;aAED;IACN,YAAY;IACZ;IACA,cAAc,OAAO,GAAG;;;EAG7B;;;;;;;;;;;;;;;;;;;ACzlBH,MAAaC,cAAqB;CAChC,MAAM;EACJ,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,YAAY;IACV,MAAM;KAAE,MAAM;KAAU,aAAa;KAAuB;IAC5D,SAAS;KAAE,MAAM;KAAU,aAAa;KAAiB;IAC1D;GACD,UAAU,CAAC,QAAQ,UAAU;GAC9B;EACF;CACD,MAAM,QAAQ,EAAE,MAAM,WAAW,KAAkB;EACjD,MAAM,aAAa;EACnB,MAAM,gBAAgB;EAEtB,IAAI;EACJ,IAAI;GACF,WAAW,MAAM,IAAI,UAAU,SAAS,IAAI,QAAQ,WAAW;UAE3D;EAKN,MAAM,QAAQ,OAAO,WAAW,cAAc;EAE9C,IAAI,aAAa,eACf,OAAO,qBAAqB,WAAW,4BAA4B,MAAM;EAE3E,MAAM,IAAI,UAAU,UAAU,IAAI,QAAQ,YAAY,cAAc;EAEpE,OAAO,aAAa,KAAA,IAChB,WAAW,WAAW,IAAI,MAAM,YAChC,WAAW,WAAW,IAAI,MAAM;;CAEvC"}
|