@narumitw/pi-sync 0.54.0 → 0.54.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/ui/merge-review.ts", "../../src/ui/sync-confirmation.ts", "../../src/ui/merged-sync-summary.ts", "../../src/sync/conflict-artifact-ownership.ts", "../../src/sync/conflict-resolution.ts", "../../src/sync/conflict-retention.ts", "../../src/sync/content-conflicts.ts", "../../src/sync/merge-apply.ts", "../../src/snapshot/snapshot-apply.ts", "../../src/sync/merge-transfer-error.ts", "../../src/sync/partial-progress.ts", "../../src/sync/settings-conflicts.ts", "../../src/sync/settings-merge.ts", "../../src/ui/sync-format.ts", "../../src/sync/sync-decision.ts", "../../src/sync/merged-sync.ts"],
4
+ "sourcesContent": ["import type { ExtensionCommandContext, ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { truncateToWidth } from \"@earendil-works/pi-tui\";\nimport { defineMenu, runCustomInteraction, runDocumentReview, runMenu } from \"@narumitw/pi-tui-kit\";\nimport { createSyncConfirmation, type SyncConfirmationChoice } from \"./sync-confirmation.js\";\nimport { safeTerminalText } from \"./terminal-text.js\";\n\ntype ReviewContext = ExtensionCommandContext | ExtensionContext;\n\n/** One approval screen; full details are optional and never authorize a transfer. */\nexport async function confirmMergeReview(\n ctx: ReviewContext,\n title: string,\n content: string,\n signal: AbortSignal | undefined,\n isCurrent: () => boolean,\n confirmationLabel = \"apply changes\",\n summaryLines?: readonly string[],\n) {\n const lines = summaryLines ?? [\n ...content\n .split(\"\\n\")\n .slice(0, 6)\n .map((line) => truncateToWidth(safeTerminalText(line), 100)),\n \"View details for the complete review.\",\n ];\n while (isCurrent() && !signal?.aborted) {\n const choice: { value: \"cancel\" | \"approve\" | \"details\" } = { value: \"cancel\" };\n const menu = defineMenu<undefined, \"confirm\", \"choose\", ReviewContext>({\n start: \"confirm\",\n screens: {\n confirm: () => ({\n kind: \"choice\",\n title,\n lines,\n initialItemId: \"cancel\",\n items: [\n { id: \"cancel\", label: \"No, cancel\" },\n { id: \"approve\", label: `Yes, ${confirmationLabel}` },\n { id: \"details\", label: \"View details\" },\n ],\n action: \"choose\",\n hint: \"close\",\n }),\n },\n actions: {\n choose: ({ itemId }) => {\n if (itemId === \"approve\" || itemId === \"details\") choice.value = itemId;\n return { kind: \"close\" };\n },\n },\n });\n const result =\n ctx.mode === \"tui\" && ctx.hasUI\n ? await runCustomInteraction<SyncConfirmationChoice, ReviewContext>(ctx, {\n create: ({ tui, theme, keybindings, complete }) =>\n createSyncConfirmation({ title, lines, confirmationLabel, tui, theme, keybindings, complete }),\n signal,\n isCurrent,\n onError: () => {},\n })\n : await runMenu(ctx, menu, { getState: () => undefined, signal, isCurrent, onError: () => {} });\n if (!isCurrent() || signal?.aborted) return false;\n if (result.kind === \"error\") throw new Error(\"Merge review failed; no transfer was performed.\");\n if (result.kind === \"unsupported\")\n throw new Error(\"Merge review requires observable TUI or RPC; review the plan before using --yes.\");\n if (result.kind === \"completed\") choice.value = result.value;\n else if (result.kind !== \"closed\") return false;\n // Keep authorization separate from UI termination in both adapters.\n if (choice.value === \"approve\") return true;\n if (choice.value !== \"details\") return false;\n const detail = await runDocumentReview(ctx, {\n title: \"Sync change details\",\n content,\n format: { kind: \"text\" },\n viewportSize: \"adaptive\",\n hint: \"back\",\n signal,\n isCurrent,\n onError: () => {},\n });\n if (!isCurrent() || signal?.aborted) return false;\n if (detail.kind === \"error\") throw new Error(\"Merge review failed; no transfer was performed.\");\n if (detail.kind !== \"cancelled\" || detail.reason !== \"back\") return false;\n // A fresh menu discards remembered selection: returning from details always selects No.\n // Unlike Pi's native Yes-first dialog, approval requires moving off the safe default.\n }\n return false;\n}\n", "import type { KeybindingsManager, Theme } from \"@earendil-works/pi-coding-agent\";\nimport { Key, matchesKey, SelectList, type TUI, type TuiMouseEvent, truncateToWidth } from \"@earendil-works/pi-tui\";\nimport { HorizontalRule, hardWrapTerminalDocument, sanitizeTerminalText } from \"@narumitw/pi-tui-kit\";\n\nexport type SyncConfirmationChoice = \"cancel\" | \"approve\" | \"details\";\n\n/** Kit choice context is clipped on short terminals; this summary must remain reviewable. */\nexport function createSyncConfirmation(options: {\n title: string;\n lines: readonly string[];\n confirmationLabel: string;\n tui: TUI;\n theme: Theme;\n keybindings: KeybindingsManager;\n complete(choice: SyncConfirmationChoice): void;\n}) {\n const { tui, theme, keybindings } = options;\n const choices: SyncConfirmationChoice[] = [\"cancel\", \"approve\", \"details\"];\n const list = new SelectList(\n [\n { value: \"cancel\", label: \"No, cancel\" },\n { value: \"approve\", label: `Yes, ${sanitizeTerminalText(options.confirmationLabel)}` },\n { value: \"details\", label: \"View details\" },\n ],\n 3,\n {\n selectedPrefix: (text) => theme.fg(\"accent\", text),\n selectedText: (text) => theme.fg(\"accent\", text),\n description: (text) => theme.fg(\"muted\", text),\n scrollInfo: (text) => theme.fg(\"dim\", text),\n noMatch: (text) => theme.fg(\"muted\", text),\n },\n );\n const rule = new HorizontalRule({ ruleStyle: (text) => theme.fg(\"border\", text) });\n let selected = 0;\n let offset = 0;\n let maximumOffset = 0;\n let lastWidth = 0;\n let lastRows = 0;\n let seen = new Set<number>();\n let summary: readonly string[] = [];\n let reviewed = false;\n let disposed = false;\n let finished = false;\n let summaryStart = 0;\n let summaryEnd = 0;\n let actionsStart = 0;\n const finish = (choice: SyncConfirmationChoice) => {\n if (disposed || finished) return;\n finished = true;\n options.complete(choice);\n };\n const select = (index: number) => {\n selected = (index + choices.length) % choices.length;\n list.setSelectedIndex(selected);\n };\n list.onSelectionChange = (item) => {\n selected = Math.max(0, choices.indexOf(item.value as SyncConfirmationChoice));\n };\n list.onSelect = (item) => {\n const choice = choices[selected] ?? \"cancel\";\n if (item.value === choice && (choice !== \"approve\" || reviewed)) finish(choice);\n };\n const component = {\n render(width: number, expose = true): string[] {\n if (!Number.isFinite(width) || width <= 0) {\n reviewed = false;\n return [];\n }\n const cells = Math.floor(width);\n const rows = Math.max(1, Math.floor(tui.terminal.rows) - 3);\n if (cells !== lastWidth || rows !== lastRows) {\n // Reflow can expose previously unseen rows or hide the selected action.\n // Reset proof and selection rather than carry approval across a resize.\n summary = options.lines.flatMap((line) => hardWrapTerminalDocument(line, cells));\n seen = new Set();\n offset = 0;\n select(0);\n lastWidth = cells;\n lastRows = rows;\n }\n const framed = rows >= 9;\n const actions = list.render(cells);\n const viewport = Math.max(0, rows - actions.length - 3 - (framed ? 2 : 0));\n maximumOffset = Math.max(0, summary.length - viewport);\n offset = Math.min(offset, maximumOffset);\n const visible = summary.slice(offset, offset + viewport);\n if (expose) for (let index = offset; index < offset + visible.length; index++) seen.add(index);\n reviewed = viewport > 0 && seen.size === summary.length;\n // Describe actions without advertising configured keys that can be invalid,\n // aliased, or shadowed by an earlier cancellation/navigation binding.\n const hint = reviewed ? \"Select an action.\" : \"Navigation keys scroll the summary before selecting Yes.\";\n const body = [\n theme.fg(\"accent\", theme.bold(hardWrapTerminalDocument(options.title, cells).join(\" \"))),\n ...visible.map((line) => theme.fg(\"text\", line)),\n theme.fg(\n \"muted\",\n `Summary ${visible.length ? offset + 1 : 0}-${offset + visible.length}/${summary.length}${reviewed ? \"\" : \" \u2014 review before Yes\"}`,\n ),\n ...actions,\n theme.fg(\"dim\", hint),\n ];\n summaryStart = Number(framed) + 1;\n summaryEnd = summaryStart + visible.length;\n actionsStart = summaryEnd + 1;\n const frame = framed ? [...rule.render(cells), ...body, ...rule.render(cells)] : body;\n // Very small terminals cannot display the summary and all choices together.\n // Keep cancellation available, but never approve a zero-row summary viewport.\n return frame.slice(0, rows).map((line) => truncateToWidth(line, cells, \"\"));\n },\n invalidate() {\n list.invalidate();\n rule.invalidate();\n },\n handleInput(data: string) {\n if (disposed || finished) return;\n if (matchesKey(data, Key.ctrl(\"c\")) || keybindings.matches(data, \"tui.select.cancel\")) {\n finish(\"cancel\");\n return;\n }\n // Refresh height/width proof before handling an input racing with terminal resize.\n component.render(tui.terminal.columns ?? lastWidth, false);\n if (keybindings.matches(data, \"tui.select.up\")) {\n if (!reviewed || (selected === 0 && offset > 0)) offset = Math.max(0, offset - 1);\n else select(selected - 1);\n } else if (keybindings.matches(data, \"tui.select.down\")) {\n if (!reviewed || (selected === 0 && offset < maximumOffset)) offset = Math.min(maximumOffset, offset + 1);\n else select(selected + 1);\n } else if (keybindings.matches(data, \"tui.select.confirm\")) {\n const choice = choices[selected] ?? \"cancel\";\n if (choice !== \"approve\" || reviewed) finish(choice);\n }\n tui.requestRender();\n },\n handleMouse(event: TuiMouseEvent) {\n if (disposed || finished || event.width !== lastWidth) return undefined;\n component.render(event.width, false);\n if (event.y >= summaryStart && event.y < summaryEnd && event.type === \"wheel\" && event.wheelDelta) {\n offset = Math.max(0, Math.min(maximumOffset, offset + (event.wheelDelta < 0 ? -1 : 1)));\n select(0);\n tui.requestRender();\n return { handled: true, render: true };\n }\n if (event.y < actionsStart || event.y >= actionsStart + choices.length || event.y >= lastRows) return undefined;\n return list.handleMouse({ ...event, y: event.y - actionsStart, height: choices.length });\n },\n dispose() {\n disposed = true;\n seen.clear();\n },\n };\n return component;\n}\n", "import { truncateToWidth } from \"@earendil-works/pi-tui\";\nimport type { PublicationCapability } from \"../backends/sync-backend.js\";\nimport type { Snapshot } from \"../snapshot/snapshot-types.js\";\nimport type { FileMergeDecision } from \"../sync/file-merge-planner.js\";\nimport { fileHashMap } from \"../sync/sync-state.js\";\nimport { safeTerminalText, snapshotPathLabel } from \"./terminal-text.js\";\n\ninterface FileChange {\n path: string;\n action: \"Add\" | \"Update\" | \"Delete\";\n}\n\nexport interface MergedSyncSummaryInput {\n setupName: string;\n destination: string;\n localBefore: Snapshot;\n localAfter: Snapshot;\n remoteBefore: Snapshot;\n remoteAfter: Snapshot;\n publish: boolean;\n sessions: boolean;\n groups: readonly { paths: readonly string[] }[];\n decisions: readonly FileMergeDecision[];\n capability: PublicationCapability;\n}\n\n/** Presentation only: counts describe snapshot differences, not planner decisions. */\nexport function mergedSyncSummary(input: MergedSyncSummaryInput) {\n const local = changes(input.localBefore, input.localAfter);\n const remote = changes(input.remoteBefore, input.remoteAfter);\n const all = [...local, ...remote];\n const updatesOnly = all.length > 0 && all.every((change) => change.action === \"Update\");\n const verb = updatesOnly ? \"Update\" : \"Apply changes to\";\n const title =\n local.length && remote.length\n ? \"Apply local and remote changes?\"\n : all.length\n ? `${verb} ${all.length} ${local.length ? \"local\" : \"remote\"} ${all.length === 1 ? \"file\" : \"files\"}?`\n : input.publish\n ? \"Publish a new remote snapshot?\"\n : \"Pi Sync is already up to date.\";\n const confirmationLabel =\n local.length && remote.length\n ? \"apply local and remote changes\"\n : all.length\n ? `${updatesOnly ? \"update\" : \"apply changes to\"} ${local.length ? \"local\" : \"remote\"} ${all.length === 1 ? \"file\" : \"files\"}`\n : \"publish remote snapshot\";\n const sources = new Map(\n input.decisions.filter((item) => item.kind === \"accepted\").map((item) => [item.path, item.source]),\n );\n const label = (change: FileChange, side: \"local\" | \"remote\") => {\n const source = sources.get(change.path);\n const suffix =\n source === \"merged\"\n ? \" (merged content)\"\n : side === \"local\" && source === \"remote\"\n ? change.action === \"Delete\"\n ? \" (deleted remotely)\"\n : \" from remote\"\n : \"\";\n return `${change.action} ${snapshotPathLabel(change.path)}${suffix}`;\n };\n const section = (items: FileChange[], side: \"local\" | \"remote\", compact: boolean) => {\n const heading = side === \"local\" ? \"Local changes\" : \"Remote file changes\";\n if (!items.length) return [`${heading}: none`];\n const counts = [\"Add\", \"Update\", \"Delete\"].flatMap((action) => {\n const count = items.filter((item) => item.action === action).length;\n return count ? [`${count} ${action.toLowerCase()}`] : [];\n });\n return [\n `${heading}: ${counts.join(\", \")}`,\n ...(compact ? items.slice(0, 3) : items).map(\n (item) => ` ${compact ? truncateToWidth(label(item, side), 80) : label(item, side)}`,\n ),\n ...(compact && items.length > 3 ? [` ${items.length - 3} more files \u2014 View details`] : []),\n ];\n };\n const context = [`Setup: ${safeTerminalText(input.setupName)}`, `Remote: ${safeTerminalText(input.destination)}`];\n const safety = [\n `Remote snapshot publication: ${input.publish ? \"yes\" : \"no\"}`,\n `Sessions: ${input.sessions ? \"included \u2014 may contain private conversations\" : \"not included\"}`,\n input.groups.length\n ? `Unresolved groups: ${input.groups.length} \u2014 these paths stay unchanged on each side`\n : \"Conflicts: none\",\n ...(input.publish && input.capability === \"read-check-write-verify\"\n ? [\"Warning: simultaneous remote writes can still race; visible changes are rejected.\"]\n : []),\n ...(input.publish && input.capability === \"conditional-required\"\n ? [\"Remote publication requires verified conditional writes; verification failure stops the transfer.\"]\n : []),\n \"The current session is protected. A backup and recovery journal will be saved.\",\n \"Resources will not reload automatically.\",\n ];\n return {\n title,\n confirmationLabel,\n lines: [\n ...context.map((line) => truncateToWidth(line, 100)),\n ...section(local, \"local\", true),\n ...section(remote, \"remote\", true),\n ...safety,\n ],\n content: [\n ...context,\n \"\",\n ...section(local, \"local\", false),\n \"\",\n ...section(remote, \"remote\", false),\n \"\",\n ...safety,\n ...input.groups.flatMap((group) =>\n group.paths.map((filePath) => `Unchanged (unresolved): ${snapshotPathLabel(filePath)}`),\n ),\n ].join(\"\\n\"),\n };\n}\n\nfunction changes(before: Snapshot, after: Snapshot): FileChange[] {\n const beforeMap = fileHashMap(before);\n const afterMap = fileHashMap(after);\n return [...new Set([...Object.keys(beforeMap), ...Object.keys(afterMap)])]\n .sort()\n .flatMap((filePath): FileChange[] => {\n if (!Object.hasOwn(beforeMap, filePath)) return [{ path: filePath, action: \"Add\" }];\n if (!Object.hasOwn(afterMap, filePath)) return [{ path: filePath, action: \"Delete\" }];\n return beforeMap[filePath] !== afterMap[filePath] ? [{ path: filePath, action: \"Update\" }] : [];\n });\n}\n", "import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport { syncDirectory } from \"../state/json-file.js\";\nimport { readStateForConfig, statePathForConfig } from \"../state/sync-state-store.js\";\nimport {\n type ConflictArtifact,\n type CreatedConflictArtifact,\n conflictArtifactFingerprint,\n conflictDirectory,\n} from \"./conflict-artifacts.js\";\nimport { readMergeJournal } from \"./merge-journal.js\";\n\n/** Attempt-owned cleanup only: unknown evidence remains the retention policy's responsibility. */\nexport async function releaseConflictArtifacts(\n config: AnySyncConfig,\n statePath: string,\n created: readonly CreatedConflictArtifact[],\n) {\n if (!created.length || statePathForConfig(config) !== statePath) return;\n try {\n const state = await readStateForConfig(config);\n if (statePathForConfig(config) !== statePath) return;\n const journal = await readMergeJournal(config);\n if (statePathForConfig(config) !== statePath) return;\n const referenced = new Set([\n ...(state.unresolved ?? []).map((group) => group.artifact),\n ...(journal?.progress?.groups ?? []).map((group) => group.artifact),\n ]);\n for (const lease of created) {\n if (referenced.has(lease.token) || lease.target !== path.join(conflictDirectory(config), `${lease.token}.json`))\n continue;\n try {\n const stat = await fs.lstat(lease.target);\n if (\n !stat.isFile() ||\n stat.nlink !== 1 ||\n stat.dev !== lease.dev ||\n stat.ino !== lease.ino ||\n stat.size !== lease.size\n )\n continue;\n const artifact = JSON.parse(await fs.readFile(lease.target, \"utf8\")) as ConflictArtifact;\n if (conflictArtifactFingerprint(artifact) !== lease.fingerprint || statePathForConfig(config) !== statePath)\n continue;\n const latest = await fs.lstat(lease.target);\n if (\n latest.dev !== lease.dev ||\n latest.ino !== lease.ino ||\n latest.nlink !== 1 ||\n statePathForConfig(config) !== statePath\n )\n continue;\n await fs.unlink(lease.target);\n await syncDirectory(path.dirname(lease.target));\n } catch {\n /* Missing, replaced or unreadable evidence is not ours to delete. */\n }\n }\n } catch {\n /* Invalid state/journal or unavailable storage cannot prove lack of references. */\n }\n}\n", "import type { RemoteHead, SyncBackend } from \"../backends/sync-backend.js\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport type { Snapshot } from \"../snapshot/snapshot-types.js\";\nimport type { SyncState } from \"../state/state-types.js\";\nimport { syncStateFingerprint } from \"../state/sync-state-store.js\";\nimport { conflictArtifactFingerprint, readConflictArtifact } from \"./conflict-artifacts.js\";\nimport { type FileMergePlan, mergePathIdentity, planFileMerge } from \"./file-merge-planner.js\";\nimport { fileHashMap } from \"./sync-state.js\";\nexport interface ConflictResolution {\n token: string;\n group: number;\n source: \"local\" | \"remote\";\n stateIdentity: string;\n artifactIdentity: string;\n}\nexport async function resolveReviewedGroup(\n config: AnySyncConfig,\n backend: SyncBackend,\n state: SyncState,\n local: Snapshot,\n remote: Snapshot,\n head: RemoteHead,\n plan: FileMergePlan,\n resolution: ConflictResolution,\n protectedPaths: ReadonlySet<string>,\n): Promise<FileMergePlan> {\n const artifact = await readConflictArtifact(config, backend.identity, resolution.token);\n const group = artifact.groups[resolution.group];\n if (\n conflictArtifactFingerprint(artifact) !== resolution.artifactIdentity ||\n !group ||\n plan.kind !== \"planned\" ||\n !state.unresolved?.some(\n (item) => item.artifact === resolution.token && JSON.stringify(item.paths) === JSON.stringify(group.paths),\n ) ||\n syncStateFingerprint(state) !== resolution.stateIdentity ||\n state.lastObservedSnapshot !== head.snapshotId ||\n !state.lastObservedRevision ||\n !backend.sameRevision(state.lastObservedRevision, head.revision)\n )\n throw new Error(\"Conflict review is stale; refresh sync and review again.\");\n const ours = fileHashMap(local);\n const theirs = fileHashMap(remote);\n const oldOurs = fileHashMap(artifact.local);\n const oldTheirs = fileHashMap(artifact.remote);\n if (\n group.paths.some(\n (filePath) =>\n ours[filePath] !== oldOurs[filePath] ||\n theirs[filePath] !== oldTheirs[filePath] ||\n state.lastFileHashes[filePath] !== artifact.state.lastFileHashes[filePath],\n )\n )\n throw new Error(\"Conflict versions changed; no resolution was applied.\");\n if (\n group.paths.some((filePath) =>\n [...protectedPaths].some((value) => mergePathIdentity(value) === mergePathIdentity(filePath)),\n )\n )\n throw new Error(\n \"Current session conflict cannot be resolved from the loaded session; preserve evidence and close Pi.\",\n );\n const selected = resolution.source === \"local\" ? local : remote;\n const paths = new Set(group.paths);\n for (const snapshot of [selected, local]) {\n const layout = planFileMerge({\n baseline: {},\n local: snapshot.files.filter((file) => paths.has(file.path)),\n remote: [],\n selectionCompatible: true,\n });\n if (layout.kind !== \"planned\" || layout.conflicts.length)\n throw new Error(\n \"Selected/current local group still has path collisions; preserve evidence, repair the layout manually and refresh sync.\",\n );\n }\n const selectedFiles = new Map(selected.files.map((file) => [file.path, file]));\n const decisions = plan.decisions.map((item) =>\n paths.has(item.path)\n ? {\n kind: \"accepted\" as const,\n path: item.path,\n source: resolution.source,\n file: selectedFiles.get(item.path),\n }\n : item,\n );\n return {\n kind: \"planned\",\n decisions,\n conflicts: decisions.filter((item): item is Extract<typeof item, { kind: \"conflict\" }> => item.kind === \"conflict\"),\n };\n}\n", "import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport type { Snapshot } from \"../snapshot/snapshot-types.js\";\nimport { syncDirectory } from \"../state/json-file.js\";\nimport type { SyncState } from \"../state/state-types.js\";\nimport { conflictDirectory, readConflictArtifact } from \"./conflict-artifacts.js\";\nimport { fileHashMap } from \"./sync-state.js\";\n/** Only after accepted state and journal retirement, under the operation lock. Unknown/unresolved evidence is never pruned. */\nexport async function pruneCompletedConflicts(\n config: AnySyncConfig,\n backend: string,\n state: SyncState,\n local: Snapshot,\n remote: Snapshot,\n validate: () => void,\n) {\n validate();\n const directory = conflictDirectory(config);\n let names: string[];\n try {\n const stat = await fs.lstat(directory);\n validate();\n if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error(\"Unsafe conflict retention directory.\");\n names = await fs.readdir(directory);\n validate();\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return;\n throw error;\n }\n const pinned = new Set(state.unresolved?.map((group) => group.artifact) ?? []);\n const ours = fileHashMap(local);\n const theirs = fileHashMap(remote);\n const completed: { token: string; modified: number }[] = [];\n for (const name of names) {\n validate();\n const token = name.replace(/\\.json$/u, \"\");\n if (!/^[a-f0-9-]{36}\\.json$/u.test(name) || pinned.has(token)) continue;\n try {\n const artifact = await readConflictArtifact(config, backend, token);\n validate();\n const originalLocal = fileHashMap(artifact.local);\n const originalRemote = fileHashMap(artifact.remote);\n if (\n !artifact.groups.every((group) =>\n group.paths.every(\n (filePath) =>\n state.lastFileHashes[filePath] === ours[filePath] &&\n ours[filePath] === theirs[filePath] &&\n (ours[filePath] === originalLocal[filePath] || ours[filePath] === originalRemote[filePath]),\n ),\n )\n )\n continue;\n const stat = await fs.lstat(path.join(directory, name));\n validate();\n if (stat.isFile()) completed.push({ token, modified: stat.mtimeMs });\n } catch {\n validate(); /* Corrupt/unknown evidence remains. */\n }\n }\n completed.sort((left, right) => right.modified - left.modified || left.token.localeCompare(right.token));\n for (const entry of completed.slice(32)) {\n validate();\n await fs.rm(path.join(directory, `${entry.token}.json`));\n validate();\n }\n if (completed.length > 32) {\n await syncDirectory(directory);\n validate();\n }\n}\n", "import { createHash } from \"node:crypto\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport type { Snapshot, SnapshotFile } from \"../snapshot/snapshot-types.js\";\nimport { readMergeAncestors } from \"../state/merge-baseline-store.js\";\nimport type { SyncState } from \"../state/state-types.js\";\nimport { type FileMergePlan, mergePathIdentity } from \"./file-merge-planner.js\";\nimport { mergeSession } from \"./session-merge.js\";\nimport { isMergeTextPath, mergeText, TEXT_MERGE_WORK_LIMIT, type TextMergeBudget } from \"./text-merge.js\";\nexport function snapshotFile(filePath: string, bytes: Buffer): SnapshotFile {\n return {\n path: filePath,\n contentBase64: bytes.toString(\"base64\"),\n sha256: createHash(\"sha256\").update(bytes).digest(\"hex\"),\n };\n}\nexport async function resolveContentConflicts(\n config: AnySyncConfig,\n state: SyncState,\n local: Snapshot,\n remote: Snapshot,\n plan: FileMergePlan,\n protectedPaths: ReadonlySet<string>,\n options: { textBudget?: TextMergeBudget; signal?: AbortSignal } = {},\n): Promise<FileMergePlan> {\n if (plan.kind !== \"planned\" || !config.mergeContent) return plan;\n options.signal?.throwIfAborted();\n const budget = options.textBudget ?? { remaining: TEXT_MERGE_WORK_LIMIT };\n const decisions = [...plan.decisions];\n let ancestors: SnapshotFile[] = [];\n try {\n ancestors = (await readMergeAncestors(config, state)) ?? [];\n } catch {\n options.signal?.throwIfAborted();\n return plan;\n }\n options.signal?.throwIfAborted();\n const oursByPath = new Map(local.files.map((file) => [file.path, file]));\n const theirsByPath = new Map(remote.files.map((file) => [file.path, file]));\n const ancestorsByPath = new Map(ancestors.map((file) => [file.path, file]));\n const decisionIndex = new Map(decisions.map((decision, index) => [decision.path, index]));\n const protectedKeys = new Set([...protectedPaths].map(mergePathIdentity));\n for (const conflict of plan.conflicts) {\n options.signal?.throwIfAborted();\n if (conflict.reason !== \"both-changed\" || protectedKeys.has(mergePathIdentity(conflict.path))) continue;\n const session = conflict.path.startsWith(\"sessions/\") && conflict.path.endsWith(\".jsonl\");\n if (!session && (!isMergeTextPath(conflict.path) || budget.remaining === 0)) continue;\n const ours = oursByPath.get(conflict.path);\n const theirs = theirsByPath.get(conflict.path);\n if (!ours || !theirs) continue;\n const ancestor = ancestorsByPath.get(conflict.path);\n const base = ancestor ? Buffer.from(ancestor.contentBase64, \"base64\") : undefined;\n if (!base) continue;\n const localBytes = Buffer.from(ours.contentBase64, \"base64\");\n const remoteBytes = Buffer.from(theirs.contentBase64, \"base64\");\n const bytes = session\n ? mergeSession(base, localBytes, remoteBytes)\n : mergeText(base, localBytes, remoteBytes, { budget, signal: options.signal });\n if (!bytes) continue;\n const index = decisionIndex.get(conflict.path);\n if (index === undefined) continue;\n decisions[index] = {\n kind: \"accepted\",\n path: conflict.path,\n source: \"merged\",\n file: snapshotFile(conflict.path, bytes),\n };\n }\n return {\n kind: \"planned\",\n decisions,\n conflicts: decisions.filter((item): item is Extract<typeof item, { kind: \"conflict\" }> => item.kind === \"conflict\"),\n };\n}\n", "import { createHash, randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { withFileMutationQueue } from \"@earendil-works/pi-coding-agent\";\nimport { agentDir } from \"../snapshot/session-paths.js\";\nimport { createSnapshot, snapshotTarget } from \"../snapshot/snapshot.js\";\nimport { preflightSnapshotApply, preflightSnapshotMutations } from \"../snapshot/snapshot-apply.js\";\nimport { sessionStorageRoot } from \"../snapshot/snapshot-paths.js\";\nimport type { Snapshot, SnapshotOptions } from \"../snapshot/snapshot-types.js\";\nimport { syncDirectory } from \"../state/json-file.js\";\nimport { syncMutationParents } from \"../state/mutation-directory-sync.js\";\nimport { mergePathIdentity } from \"./file-merge-planner.js\";\nimport { fileHashMap } from \"./sync-state.js\";\n\n/** Read-only filesystem applicability check before publishing a combined result. */\nexport async function preflightMergedTargets(\n before: Snapshot,\n after: Snapshot,\n options: SnapshotOptions,\n protectedTarget?: string,\n) {\n const root = agentDir();\n const beforeHashes: Record<string, string> = Object.assign(Object.create(null), fileHashMap(before));\n const afterHashes: Record<string, string> = Object.assign(Object.create(null), fileHashMap(after));\n const paths = [...new Set([...Object.keys(beforeHashes), ...Object.keys(afterHashes)])].sort();\n const changed = new Set(paths.filter((item) => beforeHashes[item] !== afterHashes[item]));\n await assertCanonicalMergedTargets(root, changed, options);\n await assertDistinctMergedTargets(root, paths, changed, options, protectedTarget, new Set(Object.keys(afterHashes)));\n const removed = replacementPaths(\n new Set(paths.filter((item) => changed.has(item) && !afterHashes[item])),\n afterHashes,\n );\n const removedTargets = new Set([...removed].map((item) => snapshotTarget(root, item, options.sessionDir)));\n for (const relative of paths) {\n if (changed.has(relative)) await assertFilesystemTarget(root, relative, options, removedTargets, beforeHashes);\n }\n}\n\nfunction replacementPaths(removed: Set<string>, afterHashes: Readonly<Record<string, string>>) {\n for (const relative of [...removed]) {\n let parent = path.posix.dirname(relative);\n while (parent !== \".\") {\n if (afterHashes[parent]) {\n for (\n let directory = path.posix.dirname(relative);\n directory !== parent;\n directory = path.posix.dirname(directory)\n )\n removed.add(directory);\n removed.add(parent);\n break;\n }\n parent = path.posix.dirname(parent);\n }\n }\n return removed;\n}\n\n/** Snapshot collection canonicalizes top-level names, but merged journals own exact physical paths. */\nasync function assertCanonicalMergedTargets(root: string, changed: Iterable<string>, options: SnapshotOptions) {\n const topLevel = new Map(\n [...changed].filter((relative) => !relative.includes(\"/\")).map((relative) => [relative.toLowerCase(), relative]),\n );\n if (topLevel.size === 0) return;\n options.signal?.throwIfAborted();\n options.validateMutation?.();\n let names: string[];\n try {\n names = await fs.readdir(root);\n } catch (error) {\n options.signal?.throwIfAborted();\n options.validateMutation?.();\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n return;\n }\n options.signal?.throwIfAborted();\n options.validateMutation?.();\n for (const name of names) {\n const canonical = topLevel.get(name.toLowerCase());\n if (canonical !== undefined && name !== canonical)\n throw new Error(\n \"Merged target has a noncanonical case variant; normalize selected top-level file spelling before retrying. Journal retained if already committed.\",\n );\n }\n}\n\n/** Even an unchanged virtual alias must not describe different bytes for a changed physical file. */\nasync function assertDistinctMergedTargets(\n root: string,\n paths: string[],\n changed: ReadonlySet<string>,\n options: SnapshotOptions,\n protectedTarget?: string,\n finalPaths: ReadonlySet<string> = new Set(paths),\n) {\n const protectedKey = protectedTarget\n ? mergePathIdentity(await resolvedTargetIdentity(path.resolve(protectedTarget), options))\n : undefined;\n options.signal?.throwIfAborted();\n options.validateMutation?.();\n const keys = new Map<string, string>();\n for (const relative of paths) {\n options.signal?.throwIfAborted();\n const target = snapshotTarget(root, relative, options.sessionDir);\n const key = mergePathIdentity(await resolvedTargetIdentity(target, options));\n options.signal?.throwIfAborted();\n options.validateMutation?.();\n const existing = keys.get(key);\n if (\n existing &&\n (mergePathIdentity(existing) !== mergePathIdentity(relative) ||\n (finalPaths.has(existing) && finalPaths.has(relative)))\n )\n throw new Error(\"Merged paths resolve to the same file; reviewed directional recovery is required.\");\n if (key === protectedKey && changed.has(relative))\n throw new Error(\"A merged transfer targets the current session; review is required.\");\n keys.set(key, relative);\n }\n}\n\nasync function assertReviewedTree(directory: string, relative: string, beforeHashes: Readonly<Record<string, string>>) {\n for (const name of await fs.readdir(directory)) {\n const child = path.join(directory, name);\n const childRelative = `${relative}/${name}`;\n const stat = await fs.lstat(child);\n if (stat.isDirectory()) {\n await assertReviewedTree(child, childRelative, beforeHashes);\n } else if (\n stat.isFile() &&\n stat.nlink === 1 &&\n beforeHashes[childRelative] ===\n createHash(\"sha256\")\n .update(await fs.readFile(child))\n .digest(\"hex\")\n ) {\n continue;\n } else {\n throw new Error(\"Reviewed directory contains unknown or changed files; publication refused.\");\n }\n }\n}\n\nfunction hasBlockingFileAncestor(target: string, files: ReadonlySet<string>) {\n for (let parent = path.dirname(target); parent !== path.dirname(parent); parent = path.dirname(parent))\n if (files.has(parent)) return true;\n return false;\n}\n\nasync function resolvedTargetIdentity(target: string, options: SnapshotOptions) {\n // Resolve the nearest existing ancestor too: roots may alias even when a target is absent.\n let ancestor = target;\n while (true) {\n options.signal?.throwIfAborted();\n try {\n const resolved = await fs.realpath(ancestor);\n return path.resolve(resolved, path.relative(ancestor, target));\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\" && code !== \"ENOTDIR\") throw error;\n const parent = path.dirname(ancestor);\n if (parent === ancestor) return target;\n ancestor = parent;\n }\n }\n}\n\nasync function assertFilesystemTarget(\n root: string,\n relative: string,\n options: SnapshotOptions,\n removedTargets: ReadonlySet<string> = new Set(),\n beforeHashes?: Readonly<Record<string, string>>,\n) {\n const target = snapshotTarget(root, relative, options.sessionDir);\n const boundary =\n relative.startsWith(\"sessions/\") && options.sessionDir\n ? path.resolve(sessionStorageRoot(root, options.sessionDir))\n : path.resolve(root);\n for (\n let parent = path.dirname(target);\n mergePathIdentity(parent) !== mergePathIdentity(boundary);\n parent = path.dirname(parent)\n ) {\n options.signal?.throwIfAborted();\n if (path.dirname(parent) === parent) throw new Error(\"Unowned merged target.\");\n try {\n const stat = await fs.lstat(parent);\n if (\n (!stat.isDirectory() || stat.isSymbolicLink()) &&\n !(stat.isFile() && stat.nlink === 1 && removedTargets.has(parent))\n )\n throw new Error(\"Unsafe merge filesystem layout; review the selected paths before transfer.\");\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\") throw error;\n }\n }\n options.signal?.throwIfAborted();\n try {\n const stat = await fs.lstat(target);\n if ((!stat.isFile() && !removedTargets.has(target)) || (stat.isFile() && stat.nlink > 1))\n throw new Error(\"Merge target is non-regular or hard-linked; review a directional operation before transfer.\");\n if (stat.isDirectory() && beforeHashes) await assertReviewedTree(target, relative, beforeHashes);\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\" && !(code === \"ENOTDIR\" && removedTargets.size > 0)) throw error;\n }\n}\n\n/** Roll forward only while each target is still its reviewed preimage or committed postimage. */\nexport async function applyMergedSnapshot(\n before: Snapshot,\n after: Snapshot,\n protectedPaths: Set<string>,\n options: SnapshotOptions,\n validate: () => Promise<void>,\n protectedTarget?: string,\n) {\n const root = agentDir();\n const beforeHashes: Record<string, string> = Object.assign(Object.create(null), fileHashMap(before));\n const afterHashes: Record<string, string> = Object.assign(Object.create(null), fileHashMap(after));\n const paths = [...new Set([...Object.keys(beforeHashes), ...Object.keys(afterHashes)])].sort();\n const replacements = replacementPaths(\n new Set(paths.filter((item) => beforeHashes[item] && !afterHashes[item])),\n afterHashes,\n );\n const intermediateDirectories = [...replacements].filter((item) => !beforeHashes[item] && !afterHashes[item]);\n const changed = [\n ...new Set([...paths.filter((item) => beforeHashes[item] !== afterHashes[item]), ...intermediateDirectories]),\n ].sort();\n const protectedKeys = new Set([...protectedPaths].map(mergePathIdentity));\n if (changed.some((item) => protectedKeys.has(mergePathIdentity(item)))) {\n throw new Error(\"A merged transfer targets the current session; review is required.\");\n }\n // Exact file queues, not a directory pseudo-lock: Pi edit/write tools use these keys.\n const targets = changed.map((item) => snapshotTarget(root, item, options.sessionDir));\n const relativeByTarget = new Map(targets.map((target, index) => [target, changed[index]]));\n const targetSet = new Set(targets);\n await assertDistinctMergedTargets(\n root,\n paths,\n new Set(changed),\n options,\n protectedTarget,\n new Set(Object.keys(afterHashes)),\n );\n // Existing case aliases share Pi's non-reentrant realpath queue. Reserve the\n // missing destination separately only after deleting its reviewed preimage.\n const targetsByQueue = new Map<string, string[]>();\n const queueTargets: string[] = [];\n const deferredTargets: string[] = [];\n for (const target of targets) {\n let key = path.resolve(target);\n try {\n key = await fs.realpath(target);\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\" && code !== \"ENOTDIR\") throw error;\n }\n options.signal?.throwIfAborted();\n options.validateMutation?.();\n const aliases = targetsByQueue.get(key) ?? [];\n aliases.push(target);\n targetsByQueue.set(key, aliases);\n }\n for (const [key, aliases] of targetsByQueue) {\n queueTargets.push(key);\n if (aliases.length > 1) deferredTargets.push(...aliases.filter((target) => path.resolve(target) !== key));\n }\n async function acquire(index: number): Promise<void> {\n const target = queueTargets[index];\n if (target) return withFileMutationQueue(target, () => acquire(index + 1));\n await validate();\n await assertCanonicalMergedTargets(root, changed, options);\n await validate();\n const current = await createSnapshot(before.profile, options);\n const currentHashes: Record<string, string> = Object.assign(Object.create(null), fileHashMap(current));\n const blockingFiles = new Set(\n paths\n .filter(\n (relative) =>\n (beforeHashes[relative] && !afterHashes[relative]) ||\n (afterHashes[relative] && currentHashes[relative] === afterHashes[relative]),\n )\n .map((relative) => snapshotTarget(root, relative, options.sessionDir)),\n );\n for (const item of changed) {\n if (currentHashes[item] !== beforeHashes[item] && currentHashes[item] !== afterHashes[item]) {\n throw new Error(\n \"Local content changed during merged transfer; journal retained for review. No newer bytes were replaced.\",\n );\n }\n const target = snapshotTarget(root, item, options.sessionDir);\n try {\n const stat = await fs.lstat(target);\n if ((!stat.isFile() && !stat.isDirectory()) || (stat.isFile() && stat.nlink > 1))\n throw new Error(\"Merged transfer target is no longer an independent regular file.\");\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\" && !(code === \"ENOTDIR\" && hasBlockingFileAncestor(target, blockingFiles))) throw error;\n }\n }\n const plan = preflightSnapshotApply(root, after, current, options);\n plan.writes = plan.writes.filter((item) => targetSet.has(item.target));\n plan.deletes = plan.deletes.filter((target) => targetSet.has(target));\n await preflightSnapshotMutations(root, plan, options.sessionDir, options);\n const deletedTargets = new Set(plan.deletes);\n for (const relative of intermediateDirectories) {\n for (let parent = path.posix.dirname(relative); parent !== \".\"; parent = path.posix.dirname(parent)) {\n if (afterHashes[parent] && deletedTargets.has(snapshotTarget(root, parent, options.sessionDir))) {\n plan.deletes.push(snapshotTarget(root, relative, options.sessionDir));\n break;\n }\n }\n }\n // A parent must remain until every reviewed leaf and intermediate directory is gone.\n plan.deletes.sort(\n (left, right) => right.split(path.sep).length - left.split(path.sep).length || left.localeCompare(right),\n );\n const removed = replacementPaths(\n new Set(paths.filter((relative) => deletedTargets.has(snapshotTarget(root, relative, options.sessionDir)))),\n afterHashes,\n );\n const removedTargets = new Set([...removed].map((item) => snapshotTarget(root, item, options.sessionDir)));\n await assertCanonicalMergedTargets(root, changed, options);\n await validate();\n const revalidateTarget = async (target: string) => {\n await validate();\n const relative = relativeByTarget.get(target);\n if (!relative) throw new Error(\"Unowned merge target.\");\n await assertFilesystemTarget(root, relative, options, removedTargets, currentHashes);\n await validate();\n let hash: string | undefined;\n try {\n const stat = await fs.lstat(target);\n if (stat.isDirectory() && removed.has(relative)) {\n if ((await fs.readdir(target)).length)\n throw new Error(\"Reviewed directory has remaining contents; journal retained for review.\");\n } else {\n if (!stat.isFile() || stat.nlink > 1)\n throw new Error(\"Merged transfer target is no longer an independent regular file.\");\n hash = createHash(\"sha256\")\n .update(await fs.readFile(target))\n .digest(\"hex\");\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n }\n options.signal?.throwIfAborted();\n options.validateMutation?.();\n if (hash !== beforeHashes[relative] && hash !== afterHashes[relative])\n throw new Error(\"Local content changed at the apply boundary; journal retained, newer bytes untouched.\");\n };\n for (const target of plan.deletes) {\n await revalidateTarget(target);\n try {\n const stat = await fs.lstat(target);\n await validate();\n if (stat.isDirectory())\n await fs.rmdir(target); // Only an empty, reviewed directory may be replaced.\n else await fs.rm(target, { force: true });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n }\n await syncDirectory(path.dirname(target));\n }\n const requireAbsentDestinations = async () => {\n await validate();\n for (const target of deferredTargets) {\n try {\n await fs.lstat(target);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n continue;\n }\n throw new Error(\"Case replacement destination changed before queue reservation; journal retained for review.\");\n }\n await validate();\n };\n async function acquireDestinations(index: number): Promise<void> {\n const target = deferredTargets[index];\n if (target) return withFileMutationQueue(target, () => acquireDestinations(index + 1));\n // Writers registered after deletion must finish first; never accept their\n // bytes as our own, even if they match a recognizable pre/postimage.\n await requireAbsentDestinations();\n await writeTargets();\n }\n await requireAbsentDestinations();\n await acquireDestinations(0);\n async function writeTargets() {\n for (const item of plan.writes) {\n await validate();\n const relative = relativeByTarget.get(item.target);\n if (!relative) throw new Error(\"Unowned merge write target.\");\n await assertFilesystemTarget(root, relative, options, new Set());\n await fs.mkdir(path.dirname(item.target), { recursive: true });\n const temporary = path.join(path.dirname(item.target), `.pi-sync.json.${randomUUID()}.apply`);\n let mode = 0o600;\n try {\n mode = (await fs.stat(item.target)).mode & 0o777;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n }\n try {\n const handle = await fs.open(temporary, \"wx\", mode);\n try {\n await handle.writeFile(item.content);\n await handle.sync();\n } finally {\n await handle.close();\n }\n await revalidateTarget(item.target);\n await fs.rename(temporary, item.target);\n await syncDirectory(path.dirname(item.target));\n } finally {\n await fs.rm(temporary, { force: true });\n }\n }\n await syncMutationParents(\n targets,\n [root, ...(options.sessionDir ? [sessionStorageRoot(root, options.sessionDir)] : [])],\n options,\n );\n await validate();\n }\n }\n await acquire(0);\n}\n", "import { createHash } from \"node:crypto\";\nimport type { Dirent, Stats } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { assertWithinRoot, isDeniedPath, isPathInside, parentPaths, safeJoin, toPosix } from \"../paths.js\";\nimport { syncDirectory } from \"../state/json-file.js\";\nimport { agentDir } from \"./session-paths.js\";\nimport {\n createSnapshot,\n isSessionFilePath,\n isSessionPath,\n sessionStorageRoot,\n snapshotIncludesSessions,\n snapshotTarget,\n} from \"./snapshot.js\";\nimport { applySnapshotTransaction, recoverPendingSnapshotTransactions } from \"./snapshot-transaction.js\";\nimport type { Snapshot, SnapshotApplyPlan, SnapshotOptions } from \"./snapshot-types.js\";\n\nfunction sha256(value: Buffer) {\n return createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nfunction fileHashMap(snapshot: Snapshot) {\n return Object.fromEntries(snapshot.files.map((file) => [file.path, file.sha256]));\n}\n\nexport async function applySnapshot(\n snapshot: Snapshot,\n protectedRelativePaths = new Set<string>(),\n options: Pick<\n SnapshotOptions,\n | \"include\"\n | \"sessionDir\"\n | \"syncFiles\"\n | \"syncSessions\"\n | \"extraFiles\"\n | \"signal\"\n | \"validateMutation\"\n | \"expectedFileHashes\"\n > = {},\n) {\n const root = agentDir();\n const { sessionDir } = options;\n const transactionOptions = {\n sessionDir,\n signal: options.signal,\n validateMutation: options.validateMutation,\n protectedTargets: [...protectedRelativePaths].map((relative) => snapshotTarget(root, relative, sessionDir)),\n expectedPreimages: new Map(\n Object.entries(options.expectedFileHashes ?? {}).map(([relative, hash]) => [\n snapshotTarget(root, relative, sessionDir),\n hash === null ? \"missing\" : `file:${hash}`,\n ]),\n ),\n };\n options.validateMutation?.();\n await recoverPendingSnapshotTransactions(transactionOptions);\n const current = await createSnapshot(snapshot.profile, {\n ...options,\n ...(options.include === undefined ? { syncSessions: snapshotIncludesSessions(snapshot) } : {}),\n sessionDir,\n });\n const plan = await addTopLevelCaseVariantDeletes(\n root,\n protectSnapshotApplyPlan(\n root,\n preflightSnapshotApply(root, snapshot, current, { sessionDir }),\n protectedRelativePaths,\n sessionDir,\n ),\n snapshot,\n );\n await preflightSnapshotMutations(root, plan, sessionDir, options);\n await applySnapshotTransaction(plan, transactionOptions);\n return appliedFileHashMap(snapshot, current, protectedRelativePaths);\n}\n\nexport function preflightSnapshotApply(\n root: string,\n snapshot: Snapshot,\n current: Snapshot,\n options: { sessionDir?: string } = {},\n): SnapshotApplyPlan {\n const seenPaths = new Set<string>();\n const remotePaths = new Set<string>();\n const writes: Array<{ target: string; content: Buffer }> = [];\n const deletes: string[] = [];\n\n for (const file of snapshot.files) {\n const normalized = toPosix(file.path);\n if (!isSafeSnapshotPath(file.path)) {\n throw new Error(`Unsafe path in snapshot: ${file.path}`);\n }\n if (isSessionPath(normalized) && !isSessionFilePath(normalized)) {\n throw new Error(`Unsafe session path in snapshot: ${file.path}`);\n }\n if (seenPaths.has(normalized)) throw new Error(`Duplicate path in snapshot: ${normalized}`);\n seenPaths.add(normalized);\n remotePaths.add(normalized);\n\n const target = snapshotTarget(root, normalized, options.sessionDir);\n const content = decodeBase64Strict(file.contentBase64, normalized);\n if (sha256(content) !== file.sha256) throw new Error(`Checksum mismatch in snapshot file: ${normalized}`);\n writes.push({ target, content });\n }\n\n const deletePaths = new Set<string>();\n for (const file of current.files) {\n const normalized = toPosix(file.path);\n if (!remotePaths.has(normalized)) {\n deletePaths.add(snapshotTarget(root, normalized, options.sessionDir));\n }\n for (const remotePath of parentPaths(normalized)) {\n if (remotePaths.has(remotePath)) {\n deletePaths.add(snapshotTarget(root, remotePath, options.sessionDir));\n }\n }\n }\n deletes.push(...deletePaths);\n\n return { writes, deletes };\n}\n\nexport function protectSnapshotApplyPlan(\n root: string,\n plan: SnapshotApplyPlan,\n protectedRelativePaths: Set<string>,\n sessionDir?: string,\n): SnapshotApplyPlan {\n if (protectedRelativePaths.size === 0) return plan;\n const protectedTargets = new Set(\n [...protectedRelativePaths].map((relativePath) => snapshotTarget(root, relativePath, sessionDir)),\n );\n return {\n writes: plan.writes.filter((item) => !protectedTargets.has(item.target)),\n deletes: plan.deletes.filter((target) => !protectedTargets.has(target)),\n };\n}\n\nexport async function addTopLevelCaseVariantDeletes(\n root: string,\n plan: SnapshotApplyPlan,\n snapshot: Pick<Snapshot, \"files\">,\n): Promise<SnapshotApplyPlan> {\n const topLevelPaths = new Map<string, string>();\n for (const file of snapshot.files) {\n const normalized = toPosix(file.path);\n if (!normalized.includes(\"/\") && isSafeSnapshotPath(file.path)) {\n topLevelPaths.set(normalized.toLowerCase(), normalized);\n }\n }\n if (topLevelPaths.size === 0) return plan;\n\n let entries: Dirent[];\n try {\n entries = await fs.readdir(root, { withFileTypes: true });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return plan;\n throw error;\n }\n\n const deletes = new Set(plan.deletes);\n for (const entry of entries) {\n const canonicalPath = topLevelPaths.get(entry.name.toLowerCase());\n if (canonicalPath && entry.name !== canonicalPath && (entry.isFile() || entry.isSymbolicLink())) {\n deletes.add(safeJoin(root, entry.name));\n }\n }\n return { ...plan, deletes: [...deletes] };\n}\n\nexport function appliedFileHashMap(snapshot: Snapshot, current: Snapshot, protectedRelativePaths: Set<string>) {\n const hashes = fileHashMap(snapshot);\n if (protectedRelativePaths.size === 0) return hashes;\n const currentHashes = fileHashMap(current);\n for (const relativePath of protectedRelativePaths) {\n const normalized = toPosix(relativePath);\n if (currentHashes[normalized]) {\n hashes[normalized] = currentHashes[normalized];\n } else {\n delete hashes[normalized];\n }\n }\n return hashes;\n}\n\nfunction isSafeSnapshotPath(relativePath: string) {\n if (relativePath.includes(\"\\\\\")) return false;\n const normalized = toPosix(relativePath);\n return (\n Boolean(normalized) &&\n normalized !== \".\" &&\n normalized !== \"..\" &&\n !normalized.startsWith(\"../\") &&\n !path.posix.isAbsolute(normalized) &&\n path.posix.normalize(normalized) === normalized &&\n !isDeniedPath(normalized)\n );\n}\n\nfunction decodeBase64Strict(value: string, filePath: string) {\n if (!/^[A-Za-z0-9+/]*={0,2}$/.test(value) || value.length % 4 !== 0) {\n throw new Error(`Invalid base64 content in snapshot file: ${filePath}`);\n }\n return Buffer.from(value, \"base64\");\n}\n\ntype MutationGuards = Pick<SnapshotOptions, \"signal\" | \"validateMutation\">;\n\nexport async function preflightSnapshotMutations(\n root: string,\n plan: { deletes: string[]; writes: Array<{ target: string; content: Buffer }> },\n sessionDir?: string,\n options: MutationGuards = {},\n) {\n assertMutationCurrent(options);\n const deletePaths = new Set(plan.deletes);\n for (const target of plan.deletes) {\n await assertNoSymlinkParents(rootForTarget(root, target, sessionDir), target, options);\n assertMutationCurrent(options);\n }\n for (const item of plan.writes) {\n await prepareSnapshotWrite(rootForTarget(root, item.target, sessionDir), item.target, deletePaths, options);\n assertMutationCurrent(options);\n }\n}\n\nfunction assertMutationCurrent(options: MutationGuards) {\n options.validateMutation?.();\n options.signal?.throwIfAborted();\n}\n\nasync function guardedStat(target: string, options: MutationGuards) {\n assertMutationCurrent(options);\n let stat: Stats;\n try {\n stat = await fs.lstat(target);\n } catch (error) {\n assertMutationCurrent(options);\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n throw error;\n }\n assertMutationCurrent(options);\n return stat;\n}\n\nfunction rootForTarget(root: string, target: string, sessionDir?: string) {\n const sessionRoot = sessionDir ? sessionStorageRoot(root, sessionDir) : undefined;\n if (sessionRoot && isPathInside(sessionRoot, target)) return sessionRoot;\n return root;\n}\n\nasync function prepareSnapshotWrite(root: string, target: string, deletePaths: Set<string>, options: MutationGuards) {\n const parentWillBeReplaced = await ensureSafeDirectory(root, path.dirname(target), deletePaths, options);\n assertMutationCurrent(options);\n if (parentWillBeReplaced) return;\n const stat = await guardedStat(target, options);\n assertMutationCurrent(options);\n if (stat?.isSymbolicLink()) throw new Error(`Refusing to overwrite symlink during snapshot apply: ${target}`);\n if (stat?.isDirectory() && !deletePaths.has(target)) {\n throw new Error(`Refusing to overwrite directory during snapshot apply: ${target}`);\n }\n}\n\nasync function ensureSafeDirectory(root: string, directory: string, deletePaths: Set<string>, options: MutationGuards) {\n assertMutationCurrent(options);\n assertWithinRoot(root, directory);\n const rootPath = path.resolve(root);\n const relative = path.relative(rootPath, path.resolve(directory));\n let current = rootPath;\n for (const part of relative.split(path.sep).filter(Boolean)) {\n current = path.join(current, part);\n const stat = await guardedStat(current, options);\n assertMutationCurrent(options);\n if (stat) {\n if (stat.isSymbolicLink()) throw new Error(`Refusing to follow symlink during snapshot apply: ${current}`);\n if (!stat.isDirectory()) {\n if (deletePaths.has(current)) return true;\n throw new Error(`Snapshot path parent is not a directory: ${current}`);\n }\n } else {\n await fs.mkdir(current);\n assertMutationCurrent(options);\n await syncDirectory(path.dirname(current));\n assertMutationCurrent(options);\n }\n }\n return false;\n}\n\nasync function assertNoSymlinkParents(root: string, target: string, options: MutationGuards) {\n assertMutationCurrent(options);\n assertWithinRoot(root, target);\n const rootPath = path.resolve(root);\n const relative = path.relative(rootPath, path.resolve(target));\n let current = rootPath;\n const parts = relative.split(path.sep).filter(Boolean);\n for (const part of parts.slice(0, -1)) {\n current = path.join(current, part);\n const stat = await guardedStat(current, options);\n assertMutationCurrent(options);\n if (!stat) return;\n if (stat.isSymbolicLink()) throw new Error(`Refusing to follow symlink during snapshot apply: ${current}`);\n if (!stat.isDirectory()) throw new Error(`Snapshot path parent is not a directory: ${current}`);\n }\n}\n", "import type { ResolvedSyncBackend } from \"../backends/backend-types.js\";\nimport { safeTerminalText } from \"../ui/terminal-text.js\";\n\nconst MAX_CAUSES = 4;\nconst MAX_DETAIL_LENGTH = 600;\n\n/** Only the sanitized message is displayed; retain the original cause for outcome handling. */\nexport function mergeTransferError(error: unknown, backend: ResolvedSyncBackend): Error {\n const messages: string[] = [];\n const seen = new Set<Error>();\n let current = error;\n while (current instanceof Error && !seen.has(current) && seen.size < MAX_CAUSES) {\n seen.add(current);\n const code = (current as NodeJS.ErrnoException).code;\n const status = (current as Error & { status?: unknown }).status;\n const metadata = [\n typeof code === \"string\" && /^[A-Z][A-Z0-9_]{1,63}$/u.test(code) ? code : undefined,\n typeof status === \"number\" && Number.isInteger(status) && status >= 100 && status <= 599\n ? `HTTP ${status}`\n : undefined,\n ].filter(Boolean);\n const message = `${current.message}${metadata.length ? ` (${metadata.join(\", \")})` : \"\"}`;\n if (message && !messages.includes(message)) messages.push(message);\n current = current.cause;\n }\n let detail = messages.join(\" \u2192 \") || \"No error details available.\";\n // Redact before truncation or terminal escaping, including overlapping and encoded credentials.\n for (const secret of credentialVariants(backend)) detail = detail.replaceAll(secret, \"[REDACTED]\");\n detail = detail.replace(/\\b(Bearer|Basic)\\s+[^\\s<>\"']+/giu, \"$1 [REDACTED]\");\n detail = safeTerminalText(detail);\n if (detail.length > MAX_DETAIL_LENGTH) detail = `${detail.slice(0, MAX_DETAIL_LENGTH)}\u2026 (details truncated)`;\n return new Error(\n `Merged transfer interrupted; journal and backup retained. Run /sync sync to reconcile before further mutations. Transfer failure: ${detail}`,\n { cause: error },\n );\n}\n\nfunction credentialVariants(backend: ResolvedSyncBackend): string[] {\n const secrets: string[] = [];\n let address: string;\n switch (backend.type) {\n case \"s3\":\n secrets.push(backend.profile.accessKeyId, backend.profile.secretAccessKey, backend.profile.sessionToken ?? \"\");\n address = backend.profile.endpoint;\n break;\n case \"webdav\":\n secrets.push(\n backend.profile.username,\n backend.profile.password,\n Buffer.from(`${backend.profile.username}:${backend.profile.password}`).toString(\"base64\"),\n );\n address = backend.profile.url;\n break;\n case \"git\":\n address = backend.profile.remote;\n break;\n }\n try {\n const url = new URL(address);\n secrets.push(url.username, url.password, ...url.searchParams.values());\n for (const value of [url.username, url.password]) secrets.push(decodeURIComponent(value));\n } catch {\n // Git SSH shorthand is not a URL; configured Git remotes cannot contain credentials.\n }\n return [\n ...new Set(\n secrets\n .filter(Boolean)\n .flatMap((value) => [value, encodeURIComponent(value), JSON.stringify(value).slice(1, -1)]),\n ),\n ].sort((left, right) => right.length - left.length);\n}\n", "import type { RemoteHead } from \"../backends/sync-backend.js\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport type { Snapshot, SnapshotFile } from \"../snapshot/snapshot-types.js\";\nimport type { SyncState } from \"../state/state-types.js\";\nimport type { FileMergeDecision } from \"./file-merge-planner.js\";\nimport { fileHashMap } from \"./sync-state.js\";\n/** Withholding preserves the complete local version, including explicit absence. */\nexport function acceptedMergeFiles(\n decisions: readonly FileMergeDecision[],\n localFiles: readonly SnapshotFile[],\n withheld: ReadonlySet<string>,\n) {\n const localByPath = new Map(localFiles.map((file) => [file.path, file]));\n return decisions.flatMap((decision) => {\n const file = withheld.has(decision.path)\n ? localByPath.get(decision.path)\n : decision.kind === \"accepted\"\n ? decision.file\n : undefined;\n return file ? [file] : [];\n });\n}\n\nexport interface PartialProgress {\n previous: SyncState;\n groups: { paths: string[]; artifact: string }[];\n}\nexport function progressState(\n config: AnySyncConfig,\n head: RemoteHead,\n snapshot: Snapshot,\n progress: PartialProgress,\n): SyncState {\n const withheld = new Set(progress.groups.flatMap((group) => group.paths));\n const current = fileHashMap(snapshot);\n const hashes = Object.assign(Object.create(null) as Record<string, string>, progress.previous.lastFileHashes);\n for (const key of new Set([...Object.keys(hashes), ...Object.keys(current)])) {\n if (withheld.has(key)) continue;\n const value = current[key];\n if (value === undefined) delete hashes[key];\n else hashes[key] = value;\n }\n return {\n ...progress.previous,\n version: 3,\n profile: config.snapshotIdentity,\n lastFileHashes: hashes,\n include: [...config.include],\n localFields: config.localFields,\n lastObservedSnapshot: head.snapshotId,\n lastObservedRevision: head.revision,\n unresolved: progress.groups,\n };\n}\n", "import { createHash } from \"node:crypto\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport type { Snapshot } from \"../snapshot/snapshot-types.js\";\nimport { readMergeAncestor } from \"../state/merge-baseline-store.js\";\nimport type { SyncState } from \"../state/state-types.js\";\nimport type { FileMergePlan } from \"./file-merge-planner.js\";\nimport { mergeSettingsJson } from \"./settings-merge.js\";\n\nexport async function resolveSettingsConflicts(\n config: AnySyncConfig,\n state: SyncState,\n local: Snapshot,\n remote: Snapshot,\n plan: FileMergePlan,\n): Promise<{ plan: FileMergePlan; fields: string[] }> {\n if (plan.kind !== \"planned\") return { plan, fields: [] };\n const fields: string[] = [];\n const decisions = [...plan.decisions];\n for (let index = 0; index < decisions.length; index++) {\n const decision = decisions[index];\n if (decision?.kind !== \"conflict\" || decision.reason !== \"both-changed\" || decision.path !== \"settings.json\")\n continue;\n const left = local.files.find((file) => file.path === decision.path);\n const right = remote.files.find((file) => file.path === decision.path);\n if (!left || !right) continue; // File deletion/addition is not a JSON field merge.\n const ancestor = await readMergeAncestor(config, state, decision.path);\n if (!ancestor) continue;\n const merged = mergeSettingsJson(\n ancestor,\n Buffer.from(left.contentBase64, \"base64\"),\n Buffer.from(right.contentBase64, \"base64\"),\n );\n if (merged.kind === \"review\") {\n fields.push(...merged.fields);\n continue;\n }\n decisions[index] = {\n kind: \"accepted\",\n path: decision.path,\n source: \"merged\",\n file: {\n path: decision.path,\n contentBase64: merged.content.toString(\"base64\"),\n sha256: createHash(\"sha256\").update(merged.content).digest(\"hex\"),\n },\n };\n }\n return {\n plan: { kind: \"planned\", decisions, conflicts: decisions.filter((decision) => decision.kind === \"conflict\") },\n fields,\n };\n}\n", "import {\n type JsonDocument,\n type JsonNode,\n jsonEqual,\n parseSettingsDocument,\n renderSettingsMembers,\n} from \"./json-document.js\";\n\nexport type SettingsMergeResult =\n | { kind: \"merged\"; content: Buffer }\n | { kind: \"review\"; reason: \"unsupported-format\" | \"field-conflict\"; fields: string[] };\n\nconst COUPLED_FIELDS = [\n [\"defaultProvider\", \"defaultModel\"],\n [\"queueMode\", \"steeringMode\"],\n [\"websockets\", \"transport\"],\n [\"skills\", \"enableSkillCommands\"],\n [\"enableAnalytics\", \"trackingId\"],\n] as const;\n\n/** Only global settings.json; objects/arrays are atomic units until their invariants are proven. */\nexport function mergeSettingsJson(ancestor: Buffer, local: Buffer, remote: Buffer): SettingsMergeResult {\n let documents: JsonDocument[];\n try {\n documents = [ancestor, local, remote].map(parseSettingsDocument);\n } catch {\n return { kind: \"review\", reason: \"unsupported-format\", fields: [] };\n }\n const [base, left, right] = documents as [JsonDocument, JsonDocument, JsonDocument];\n const selected = new Map<string, { document: JsonDocument; node: JsonNode }>();\n const fields = new Set(documents.flatMap((document) => [...document.root.members.keys()]));\n const units: string[][] = COUPLED_FIELDS.map((group) => [...group]);\n const coupled = new Set(units.flat());\n units.push(...[...fields].filter((field) => !coupled.has(field)).map((field) => [field]));\n const conflicts: string[] = [];\n for (const unit of units) {\n const equal = (first: JsonDocument, second: JsonDocument) =>\n unit.every((field) =>\n jsonEqual(first.root.members.get(field)?.node.value, second.root.members.get(field)?.node.value),\n );\n const source = equal(left, right) ? left : equal(left, base) ? right : equal(right, base) ? left : undefined;\n if (!source) {\n conflicts.push(...unit.filter((field) => fields.has(field)));\n continue;\n }\n for (const field of unit) {\n const member = source.root.members.get(field);\n if (member) selected.set(field, { document: source, node: member.node });\n }\n }\n if (conflicts.length) return { kind: \"review\", reason: \"field-conflict\", fields: conflicts };\n try {\n return { kind: \"merged\", content: renderSettingsMembers(left, selected) };\n } catch {\n return { kind: \"review\", reason: \"unsupported-format\", fields: [] };\n }\n}\n", "import type { PublicationCapability, RemoteHead } from \"../backends/sync-backend.js\";\nimport type { CommonSyncConfig } from \"../settings/settings-types.js\";\nimport { agentDir } from \"../snapshot/session-paths.js\";\nimport type { Snapshot } from \"../snapshot/snapshot-types.js\";\nimport { inspectRemoteSelection } from \"../sync/sync-policy.js\";\nimport { fileHashMap } from \"../sync/sync-state.js\";\nimport { safeTerminalText, snapshotPathLabel } from \"./terminal-text.js\";\n\nexport function formatDiff(local: Snapshot, remote: Snapshot) {\n const localMap = fileHashMap(local);\n const remoteMap = fileHashMap(remote);\n const allPaths = [...new Set([...Object.keys(localMap), ...Object.keys(remoteMap)])].sort();\n const lines = [`local: ${local.files.length} files`, `remote: ${remote.id} (${remote.files.length} files)`, \"\"];\n let changed = 0;\n for (const filePath of allPaths) {\n if (!Object.hasOwn(localMap, filePath)) {\n lines.push(`Remote only: ${snapshotPathLabel(filePath)}`);\n changed += 1;\n } else if (!Object.hasOwn(remoteMap, filePath)) {\n lines.push(`Local only: ${snapshotPathLabel(filePath)}`);\n changed += 1;\n } else if (localMap[filePath] !== remoteMap[filePath]) {\n lines.push(`Different: ${snapshotPathLabel(filePath)}`);\n changed += 1;\n }\n }\n if (changed === 0) lines.push(\"No file differences.\");\n return lines.join(\"\\n\");\n}\n\nexport function formatSnapshotOnlyDiff(title: string, snapshot: Snapshot) {\n return [`${title}: ${snapshot.id}`, ...snapshot.files.map((file) => `Add: ${snapshotPathLabel(file.path)}`)].join(\n \"\\n\",\n );\n}\n\nexport function formatPushSummary(\n config: CommonSyncConfig,\n destination: string,\n upload: Snapshot,\n head: RemoteHead | undefined,\n preservedRemoteFileCount = 0,\n remote?: Snapshot,\n) {\n return [\n `Sync setup: ${safeTerminalText(config.setupName)}`,\n `Storage location: ${safeTerminalText(destination)}`,\n `Upload ${upload.files.length} files from ${safeTerminalText(agentDir())}.`,\n `Sessions: ${upload.syncSessions ? \"included \u2014 may contain private conversations\" : \"not included\"}`,\n head ? `Remote latest: ${head.snapshotId}` : \"Remote latest: empty\",\n \"Publication effect: the backend's active head will reference the new immutable snapshot.\",\n ...(remote && inspectRemoteSelection(config.include, remote).kind === \"different\"\n ? [\"Included-content policy effect: replace the differing remote selection with this setup's local selection.\"]\n : []),\n formatPublicationPreview(remote, upload),\n preservedRemoteFileCount > 0\n ? `Possible secrets in locally managed files were scanned before this prompt; ${preservedRemoteFileCount} preserved remote file(s) were not rescanned.`\n : \"Possible secrets were scanned before this prompt.\",\n ].join(\"\\n\");\n}\n\nexport function formatApplyPreview(local: Snapshot, remote: Snapshot) {\n return formatDirectionalChanges(local, remote, {\n add: \"Add locally\",\n update: \"Update locally\",\n remove: \"Remove locally\",\n });\n}\n\nexport function formatPullSummary(\n config: CommonSyncConfig,\n destination: string,\n local: Snapshot,\n remote: Snapshot,\n protectedSessionCount: number,\n) {\n return [\n `Sync setup: ${safeTerminalText(config.setupName)}`,\n `Storage location: ${safeTerminalText(destination)}`,\n `Snapshot: ${safeTerminalText(remote.id)}`,\n `Sessions: ${remote.syncSessions ? \"included \u2014 may contain private conversations\" : \"not included\"}`,\n `Protected live sessions: ${protectedSessionCount || \"none\"}`,\n formatApplyPreview(local, remote),\n \"A local backup is created before these writes/deletes. The remote active snapshot is unchanged.\",\n ].join(\"\\n\");\n}\n\nexport function formatRollbackSummary(\n config: CommonSyncConfig,\n destination: string,\n local: Snapshot,\n remote: Snapshot,\n requestedSnapshot: string,\n protectedSessionCount: number,\n) {\n return [\n `Sync setup: ${safeTerminalText(config.setupName)}`,\n `Storage location: ${safeTerminalText(destination)}`,\n `Snapshot: ${safeTerminalText(requestedSnapshot)}`,\n `Sessions: ${remote.syncSessions ? \"included \u2014 may contain private conversations\" : \"not included\"}`,\n `Protected live sessions: ${protectedSessionCount || \"none\"}`,\n formatApplyPreview(local, remote),\n \"A local backup is created before applying; the backend's active head will change.\",\n ].join(\"\\n\");\n}\n\nexport function formatPublicationPreview(remote: Snapshot | undefined, upload: Snapshot) {\n if (!remote) {\n return [\"Remote is empty.\", ...upload.files.map((file) => `Add remotely: ${snapshotPathLabel(file.path)}`)].join(\n \"\\n\",\n );\n }\n return formatDirectionalChanges(remote, upload, {\n add: \"Add remotely\",\n update: \"Update remotely\",\n remove: \"Remove remotely\",\n });\n}\n\nfunction formatDirectionalChanges(\n before: Snapshot,\n after: Snapshot,\n labels: { add: string; update: string; remove: string },\n) {\n const beforeMap = fileHashMap(before);\n const afterMap = fileHashMap(after);\n const paths = [...new Set([...Object.keys(beforeMap), ...Object.keys(afterMap)])].sort();\n const lines: string[] = [];\n for (const filePath of paths) {\n if (!Object.hasOwn(beforeMap, filePath)) lines.push(`${labels.add}: ${snapshotPathLabel(filePath)}`);\n else if (!Object.hasOwn(afterMap, filePath)) lines.push(`${labels.remove}: ${snapshotPathLabel(filePath)}`);\n else if (beforeMap[filePath] !== afterMap[filePath]) lines.push(`${labels.update}: ${snapshotPathLabel(filePath)}`);\n }\n if (lines.length === 0) lines.push(\"No file changes.\");\n return lines.join(\"\\n\");\n}\n\nexport function countPreservedRemoteFiles(local: Snapshot, upload: Snapshot) {\n const localPaths = new Set(local.files.map((file) => file.path));\n return upload.files.filter((file) => !localPaths.has(file.path)).length;\n}\n\nexport function publicationCapabilityDescription(capability: PublicationCapability) {\n switch (capability) {\n case \"lease-protected\":\n return \"lease-protected (exact expected-ref update)\";\n case \"atomic-conditional\":\n return \"atomic-conditional (verified atomic precondition)\";\n case \"conditional-required\":\n return \"conditional-required (read-only until atomic preconditions are verified)\";\n case \"read-check-write-verify\":\n return \"read-check-write-verify (visible races rejected; simultaneous unseen races remain possible)\";\n }\n}\n\nexport function redact(value: string) {\n return value.length <= 8 ? \"configured\" : `${value.slice(0, 4)}\u2026${value.slice(-4)}`;\n}\n", "import { syncConfigReviewIdentity } from \"../settings/config.js\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport type { Snapshot } from \"../snapshot/snapshot-types.js\";\nimport type { SyncState } from \"../state/state-types.js\";\nimport { formatDiff, formatSnapshotOnlyDiff } from \"../ui/sync-format.js\";\nimport { safeTerminalText } from \"../ui/terminal-text.js\";\nimport { SyncDecisionRequiredError } from \"./sync-errors.js\";\nimport { includeFromSelectionConfig } from \"./sync-policy.js\";\nimport { syncPolicyChanged } from \"./sync-state.js\";\n\nexport type SyncDecisionKind =\n | \"remote-or-policy-changed\"\n | \"both-changed\"\n | \"first-sync-settings-diverged\"\n | \"first-sync-sessions-diverged\"\n | \"remote-empty\";\n\nexport type SyncResolutionDirection = \"push\" | \"pull\";\n\nexport interface SyncDecision {\n kind: SyncDecisionKind;\n setupName: string;\n configIdentity: string;\n causes: {\n localChanged: boolean;\n remoteChanged: boolean;\n policyChanged: boolean;\n };\n previousInclude?: readonly string[];\n currentInclude: readonly string[];\n review: string;\n directions: readonly SyncResolutionDirection[];\n directMessage: string;\n}\n\nexport {\n isSyncDecisionRequiredError,\n SyncDecisionRequiredError,\n} from \"./sync-errors.js\";\n\ninterface CreateSyncDecisionOptions {\n kind: SyncDecisionKind;\n config: AnySyncConfig;\n state: SyncState;\n local: Snapshot;\n remote?: Snapshot;\n localChanged: boolean;\n remoteChanged: boolean;\n directMessage: string;\n}\n\nexport function createSyncDecision(options: CreateSyncDecisionOptions) {\n const { config, state, local, remote, kind } = options;\n const policyChanged = Boolean(state.lastAppliedSnapshot) && syncPolicyChanged(state, config);\n const previousInclude = includeFromSelectionConfig(state);\n const currentInclude = [...config.include];\n const causes = {\n localChanged: options.localChanged,\n remoteChanged: options.remoteChanged,\n policyChanged,\n };\n const causeLines =\n kind === \"first-sync-settings-diverged\"\n ? [\"This machine and the remote have different Pi settings on first sync.\"]\n : kind === \"first-sync-sessions-diverged\"\n ? [\"Pi settings match, but local and remote sessions differ on first sync.\"]\n : kind === \"remote-empty\"\n ? [\"The remote storage location is empty.\"]\n : [\n ...(causes.localChanged ? [\"Local content changed since the last sync.\"] : []),\n ...(causes.remoteChanged ? [\"Remote content changed since the last sync.\"] : []),\n ...(causes.policyChanged ? [\"Included content changed since the last sync.\"] : []),\n ];\n const comparison = remote\n ? formatDiff(local, remote)\n : formatSnapshotOnlyDiff(\"Remote is empty. Local push would upload\", local);\n const review = [\n `Sync setup: ${safeTerminalText(config.setupName)}`,\n \"\",\n \"Why a decision is required:\",\n ...causeLines,\n ...(policyChanged\n ? [\"\", `Previously included: ${safeList(previousInclude)}`, `Currently included: ${safeList(currentInclude)}`]\n : []),\n \"\",\n \"Observed differences:\",\n ...comparison.split(\"\\n\").map(safeTerminalText),\n ].join(\"\\n\");\n return new SyncDecisionRequiredError({\n kind,\n setupName: config.setupName,\n configIdentity: syncConfigReviewIdentity(config),\n causes,\n ...(policyChanged ? { previousInclude: [...previousInclude] } : {}),\n currentInclude,\n review,\n directions: kind === \"remote-empty\" ? [\"push\"] : [\"push\", \"pull\"],\n directMessage: options.directMessage,\n });\n}\n\nfunction safeList(values: readonly string[]) {\n return values.length > 0 ? values.map(safeTerminalText).join(\", \") : \"none\";\n}\n", "import type { ExtensionCommandContext, ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { createSyncBackend, type SyncBackendFactory } from \"../backends/backend-factory.js\";\nimport {\n expectedRemoteHead,\n type RemoteHead,\n type SyncBackend,\n SyncBackendConflictError,\n} from \"../backends/sync-backend.js\";\nimport type { CommandOptions } from \"../commands/command-types.js\";\nimport { loadConfig, syncCheckConfigFingerprint } from \"../settings/config.js\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport {\n effectiveSessionRoot,\n requireStableMergeSessionRoot,\n snapshotOptionsForContext,\n} from \"../snapshot/session-paths.js\";\nimport {\n createSnapshot,\n filterSnapshotForConfigPolicy,\n mergeRemotePreservedFiles,\n regenerateSnapshotIdentity,\n scanSnapshot,\n} from \"../snapshot/snapshot.js\";\nimport type { Snapshot } from \"../snapshot/snapshot-types.js\";\nimport { pruneMergeBaselines, readMergeAncestors, stageMergeBaseline } from \"../state/merge-baseline-store.js\";\nimport {\n readStateForConfig,\n statePathForConfig,\n syncStateFingerprint,\n writeStateForConfig,\n} from \"../state/sync-state-store.js\";\nimport { confirmMergeReview } from \"../ui/merge-review.js\";\nimport { mergedSyncSummary } from \"../ui/merged-sync-summary.js\";\nimport { safeTerminalText } from \"../ui/terminal-text.js\";\nimport { releaseConflictArtifacts } from \"./conflict-artifact-ownership.js\";\nimport {\n type CreatedConflictArtifact,\n conflictGroups,\n readConflictArtifact,\n saveConflictArtifact,\n} from \"./conflict-artifacts.js\";\nimport { type ConflictResolution, resolveReviewedGroup } from \"./conflict-resolution.js\";\nimport { pruneCompletedConflicts } from \"./conflict-retention.js\";\nimport { resolveContentConflicts } from \"./content-conflicts.js\";\nimport { planFileMerge } from \"./file-merge-planner.js\";\nimport { overlayLocalFields, portableSnapshot, sameLocalFields } from \"./local-fields.js\";\nimport { applyMergedSnapshot, preflightMergedTargets } from \"./merge-apply.js\";\nimport {\n clearMergeJournal,\n type MergeJournal,\n mergeJournalIdentity,\n readMergeJournal,\n writeMergeJournal,\n} from \"./merge-journal.js\";\nimport { mergeTransferError } from \"./merge-transfer-error.js\";\nimport { acceptedMergeFiles, type PartialProgress, progressState } from \"./partial-progress.js\";\nimport {\n formatRemoteSelectionStatus,\n readSnapshotForHead,\n requireCompatibleRemoteSelection,\n} from \"./remote-snapshot.js\";\nimport { resolveSettingsConflicts } from \"./settings-conflicts.js\";\nimport { createSyncDecision } from \"./sync-decision.js\";\nimport { backupLocal, captureMutationOwner, protectedSessionPaths } from \"./sync-local.js\";\nimport { inspectRemoteSelection } from \"./sync-policy.js\";\nimport { fileHashMap, hasLocalChanges, hasRemoteChanges, sameHashes, syncPolicyChanged } from \"./sync-state.js\";\nimport { TEXT_MERGE_WORK_LIMIT } from \"./text-merge.js\";\n\nconst MAX_ATTEMPTS = 3;\n\n/** Established-baseline sync only. First-source selection remains in the existing command flow. */\nexport async function mergeSync(\n ctx: ExtensionContext | ExtensionCommandContext,\n options: CommandOptions,\n factory: SyncBackendFactory = createSyncBackend,\n resolution?: ConflictResolution,\n) {\n const validateOwner = captureMutationOwner(ctx, options.signal);\n const isCurrent = () => {\n try {\n validateOwner();\n return true;\n } catch {\n return false;\n }\n };\n const config = await loadConfig(options.setup);\n const configToken = syncCheckConfigFingerprint(config);\n const sessionRoot = config.include.includes(\"sessions\") ? await effectiveSessionRoot(ctx) : undefined;\n validateOwner();\n const snapshotOptions = {\n ...snapshotOptionsForContext(ctx, config),\n sessionDir: sessionRoot,\n signal: options.signal,\n };\n const validate = async () => {\n validateOwner();\n const latest = await loadConfig(options.setup);\n validateOwner();\n if (configToken !== syncCheckConfigFingerprint(latest))\n throw new Error(\"Sync setup or settings changed during transfer; reopen sync.\");\n if (sessionRoot !== undefined) {\n const currentRoot = await effectiveSessionRoot(ctx);\n validateOwner();\n if (currentRoot !== sessionRoot)\n throw new Error(\"Session storage root changed during transfer; evidence retained for review.\");\n }\n if (options.auto && (!latest.automaticTransfer || !ctx.isIdle()))\n throw new Error(\"Automatic transfer is no longer authorized at this idle boundary.\");\n };\n await validate();\n const backend = await factory(config);\n await validate();\n if (options.auto && backend.capability === \"read-check-write-verify\") {\n throw new Error(\n \"Automatic transfer requires conditional publication or a lease; this backend supports only read/check/write/verify. Use manual sync.\",\n );\n }\n const pending = await readMergeJournal(config);\n await validate();\n if (pending) {\n const recovered = await completeJournal(ctx, config, backend, pending, validate, options.signal, options.auto);\n if (!recovered) {\n if ((options.auto || !options.silent) && !options.signal?.aborted)\n ctx.ui.notify(\n \"Interrupted candidate is not active; local content and baseline were unchanged. Evidence was reconciled without retrying publication. Run sync again for a fresh plan.\",\n \"warning\",\n );\n return \"cancelled\" as const;\n }\n if ((options.auto || !options.silent) && !options.signal?.aborted)\n ctx.ui.notify(\"Recovered the committed merged transfer. Run sync again to inspect newer changes.\", \"info\");\n return \"applied\" as const;\n }\n const textBudget = { remaining: TEXT_MERGE_WORK_LIMIT };\n const createdArtifacts: CreatedConflictArtifact[] = [];\n const ownedStatePath = statePathForConfig(config);\n try {\n for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {\n await validate();\n const state = await readStateForConfig(config);\n if (state.unresolved?.length && !config.partialSync)\n throw new Error(\n \"Partial progress remains unresolved; re-enable partial sync or review an explicit force direction.\",\n );\n const localRaw = await createSnapshot(config.snapshotIdentity, snapshotOptions);\n const local = portableSnapshot(localRaw, config.localFields);\n if (!sameLocalFields(state.localFields, config.localFields))\n throw new Error(\"Local-field rules changed; review and confirm a directional migration first.\");\n const head = await backend.readHead(options.signal);\n await validate();\n const rawRemote = head ? await readSnapshotForHead(backend, head, options.signal) : undefined;\n await validate();\n if (rawRemote) {\n const files = [...local.files, ...rawRemote.files];\n if (\n files.length > 16_384 ||\n files.reduce((bytes, file) => bytes + file.contentBase64.length * 0.75, 0) > 64 * 1024 * 1024\n ) {\n throw new Error(\n \"Merged transfer exceeds the 64 MiB / 16,384 input-file bound; review an explicit push or pull instead.\",\n );\n }\n }\n const remote = rawRemote\n ? portableSnapshot(filterSnapshotForConfigPolicy(rawRemote, config), rawRemote.localFields)\n : undefined;\n if (rawRemote) {\n requireCompatibleRemoteSelection(config, rawRemote);\n const validation = planFileMerge({\n baseline: state.lastFileHashes,\n local: local.files,\n remote: rawRemote.files,\n selectionCompatible: true,\n });\n const managedPaths = new Set([\n ...Object.keys(state.lastFileHashes),\n ...[...local.files, ...(remote?.files ?? [])].map((file) => file.path),\n ]);\n if (\n validation.kind === \"planned\" &&\n validation.conflicts.some(\n (item) => item.reason === \"path-collision\" && (!config.partialSync || !managedPaths.has(item.path)),\n )\n )\n throw new Error(\"Remote snapshot contains path collisions; review a directional recovery before merging.\");\n }\n const review = (\n message: string,\n kind: \"both-changed\" | \"remote-empty\" | \"remote-or-policy-changed\" = \"both-changed\",\n ) =>\n createSyncDecision({\n kind,\n config,\n state,\n local,\n remote,\n localChanged: hasLocalChanges(local, state, config),\n remoteChanged: remote ? hasRemoteChanges(remote, state, config) : Boolean(state.lastAppliedSnapshot),\n directMessage: message,\n });\n if (!state.lastAppliedSnapshot) throw review(\"Choose the initial source before enabling automatic transfer.\");\n if (syncPolicyChanged(state, config))\n throw review(\"Included content changed; review the selection before merging.\", \"remote-or-policy-changed\");\n if (!head || !remote || !rawRemote)\n throw review(\"The established remote is missing; choose an explicit recovery direction.\", \"remote-empty\");\n const selectionState = inspectRemoteSelection(config.include, rawRemote);\n const selectionCompatible = selectionState.kind === \"same\";\n let plan = planFileMerge({\n baseline: state.lastFileHashes,\n local: local.files,\n remote: remote.files,\n selectionCompatible,\n protectedPaths: protectedSessionPaths(ctx, sessionRoot),\n });\n let resolved = { plan, fields: [] as string[] };\n if (config.mergeSettings) {\n try {\n resolved = await resolveSettingsConflicts(config, state, local, remote, plan);\n } catch (error) {\n if (!config.partialSync) throw error;\n }\n }\n await validate();\n plan = await resolveContentConflicts(\n config,\n state,\n local,\n remote,\n resolved.plan,\n protectedSessionPaths(ctx, sessionRoot),\n { textBudget, signal: options.signal },\n );\n await validate();\n if (resolution) {\n plan = await resolveReviewedGroup(\n config,\n backend,\n state,\n local,\n remote,\n head,\n plan,\n resolution,\n protectedSessionPaths(ctx, sessionRoot),\n );\n await validate();\n }\n if (plan.kind !== \"planned\" || (plan.conflicts.length && (!config.partialSync || options.auto))) {\n const decision = review(\n selectionCompatible\n ? `Conflicting or protected paths require review; no merged transfer was performed. Use /sync diff and an explicit direction.${resolved.fields.length ? ` Settings fields: ${resolved.fields.map(safeTerminalText).join(\", \")}` : \"\"}`\n : \"Remote selection metadata is unavailable; review the included content and choose an explicit direction before merging.\",\n selectionCompatible ? \"both-changed\" : \"remote-or-policy-changed\",\n );\n if (!selectionCompatible)\n decision.decision.review += `\\n\\n${formatRemoteSelectionStatus(selectionState)}\\nAn explicit direction adopts this setup's included-content policy; no automatic merge was performed.`;\n throw decision;\n }\n if (plan.kind !== \"planned\") throw new Error(\"Cannot partition an unverified merge plan.\");\n const groups = conflictGroups(plan, config);\n const withheld = new Set(groups.flatMap((group) => group.paths));\n // Transfer plans defer artifact writes until approved review and freshness guards pass.\n // A no-transfer manual inspection can persist referenced conflict state directly.\n const persistProgress = async (): Promise<PartialProgress | undefined> => {\n if (!groups.length) return;\n let ancestors: import(\"../snapshot/snapshot-types.js\").SnapshotFile[] = [];\n try {\n ancestors = ((await readMergeAncestors(config, state)) ?? []).filter((file) => withheld.has(file.path));\n } catch {\n /* Retain unknown evidence; absence remains explicit. */\n }\n await validate();\n const previousArtifacts = new Map<\n string,\n {\n artifact: Awaited<ReturnType<typeof readConflictArtifact>>;\n local: ReturnType<typeof fileHashMap>;\n remote: ReturnType<typeof fileHashMap>;\n }\n >();\n for (const token of new Set(state.unresolved?.map((group) => group.artifact) ?? [])) {\n try {\n const artifact = await readConflictArtifact(config, backend.identity, token);\n previousArtifacts.set(token, {\n artifact,\n local: fileHashMap(artifact.local),\n remote: fileHashMap(artifact.remote),\n });\n } catch {\n /* Unknown evidence retained, never reused. */\n }\n await validate();\n }\n const localHashes = fileHashMap(local);\n const remoteHashes = fileHashMap(remote);\n const previousGroups = new Map(state.unresolved?.map((item) => [JSON.stringify(item.paths), item]));\n const pending = groups.map((group) => {\n const previous = previousGroups.get(JSON.stringify(group.paths));\n const original = previous ? previousArtifacts.get(previous.artifact) : undefined;\n if (!original || !previous) return { group };\n return group.paths.every(\n (filePath) =>\n localHashes[filePath] === original.local[filePath] &&\n remoteHashes[filePath] === original.remote[filePath] &&\n state.lastFileHashes[filePath] === original.artifact.state.lastFileHashes[filePath],\n )\n ? { group, artifact: previous.artifact }\n : { group };\n });\n let artifact: string | undefined;\n const newGroups = pending.filter((item) => !item.artifact).map((item) => item.group);\n const newPaths = new Set(newGroups.flatMap((group) => group.paths));\n if (newGroups.length)\n artifact = await saveConflictArtifact(\n config,\n backend.identity,\n {\n state,\n local: { ...local, files: local.files.filter((file) => newPaths.has(file.path)) },\n remote: { ...remote, files: remote.files.filter((file) => newPaths.has(file.path)) },\n ancestors: ancestors.filter((file) => newPaths.has(file.path)),\n groups: newGroups,\n observed: { snapshotId: head.snapshotId, revision: head.revision },\n },\n captureMutationOwner(ctx, options.signal),\n (created) => createdArtifacts.push(created),\n );\n await validate();\n return {\n previous: state,\n groups: pending.map((item) => ({ paths: item.group.paths, artifact: item.artifact ?? artifact ?? \"\" })),\n };\n };\n let progress: PartialProgress | undefined;\n const accepted = regenerateSnapshotIdentity({\n ...local,\n files: acceptedMergeFiles(plan.decisions, local.files, withheld),\n });\n const after = overlayLocalFields(accepted, localRaw, config.localFields);\n if (config.include.includes(\"sessions\")) requireStableMergeSessionRoot(localRaw, after);\n const publication = regenerateSnapshotIdentity({\n ...accepted,\n version: config.partialSync ? 3 : accepted.version,\n files: [\n ...accepted.files.filter((file) => !withheld.has(file.path)),\n ...remote.files.filter((file) => withheld.has(file.path)),\n ],\n });\n const upload = mergeRemotePreservedFiles(publication, rawRemote, config);\n const publish =\n !sameHashes(fileHashMap(publication), fileHashMap(remote)) ||\n Boolean(config.partialSync && rawRemote.version !== 3);\n const apply = !sameHashes(fileHashMap(localRaw), fileHashMap(after));\n if (!publish && !apply) {\n const beforeEvidence = await backend.readHead(options.signal);\n await validate();\n if (!beforeEvidence || !backend.sameRevision(beforeEvidence.revision, head.revision))\n throw new Error(\"Remote changed before baseline acceptance; retry from a fresh observation.\");\n progress = await persistProgress();\n await validate();\n const currentLocal = await createSnapshot(config.snapshotIdentity, snapshotOptions);\n await validate();\n if (\n !sameHashes(fileHashMap(currentLocal), fileHashMap(localRaw)) ||\n syncStateFingerprint(await readStateForConfig(config)) !== syncStateFingerprint(state)\n )\n throw new Error(\n \"Local content or baseline changed before baseline acceptance; retry from a fresh observation.\",\n );\n await validate();\n const currentHead = await backend.readHead(options.signal);\n await validate();\n if (!currentHead || !backend.sameRevision(currentHead.revision, head.revision))\n throw new Error(\"Remote changed before baseline acceptance; retry from a fresh observation.\");\n await writeAcceptedState(config, head, accepted, validate, progress);\n await pruneMergeBaselines(\n config,\n acceptedState(config, head, accepted, progress),\n captureMutationOwner(ctx, options.signal),\n );\n await validate();\n await pruneCompletedConflicts(\n config,\n backend.identity,\n acceptedState(config, head, accepted, progress),\n accepted,\n remote,\n captureMutationOwner(ctx, options.signal),\n );\n await validate();\n if (!options.silent)\n ctx.ui.notify(\n progress\n ? `No independent transfer required; ${groups.length} conflict groups remain withheld. Review /sync conflicts.`\n : \"Pi Sync is already up to date.\",\n progress ? \"warning\" : \"info\",\n );\n return \"applied\" as const;\n }\n await preflightMergedTargets(localRaw, after, snapshotOptions, ctx.sessionManager.getSessionFile?.());\n await validate();\n if (!config.skipSecretScan && scanSnapshot(upload).length)\n throw new Error(\"Refusing to merge possible secrets. Review managed content before syncing.\");\n if (!options.yes) {\n const summary = mergedSyncSummary({\n setupName: config.setupName,\n destination: backend.destination,\n localBefore: localRaw,\n localAfter: after,\n remoteBefore: rawRemote,\n remoteAfter: upload,\n publish,\n sessions: config.include.includes(\"sessions\"),\n groups,\n decisions: plan.decisions,\n capability: backend.capability,\n });\n if (\n !(await confirmMergeReview(\n ctx,\n summary.title,\n summary.content,\n options.signal,\n isCurrent,\n summary.confirmationLabel,\n summary.lines,\n ))\n )\n return \"cancelled\" as const;\n }\n await validate();\n const refreshed = await createSnapshot(config.snapshotIdentity, snapshotOptions);\n if (!sameHashes(fileHashMap(refreshed), fileHashMap(localRaw)))\n throw new Error(\"Local content changed during review; no merged transfer was performed.\");\n if (syncStateFingerprint(await readStateForConfig(config)) !== syncStateFingerprint(state))\n throw new Error(\"Sync baseline changed during review; retry from a fresh observation.\");\n await validate();\n const refreshedHead = await backend.readHead(options.signal);\n await validate();\n if (!refreshedHead || !backend.sameRevision(refreshedHead.revision, head.revision))\n throw new Error(\"Remote changed during review; no merged transfer was performed.\");\n progress = await persistProgress();\n await validate();\n const backup = await backupLocal(config.snapshotIdentity, snapshotOptions, options.signal);\n await validate();\n const journal: MergeJournal = {\n version: 1,\n identity: mergeJournalIdentity(config, backend.identity),\n before: localRaw,\n after,\n accepted,\n ...(progress ? { progress } : {}),\n upload: publish ? upload : rawRemote,\n expectedHead: head,\n backup,\n stateIdentity: syncStateFingerprint(state),\n ...(sessionRoot !== undefined ? { sessionRoot } : {}),\n ...(!publish ? { committedHead: head, applyOnly: true } : {}),\n };\n await writeMergeJournal(config, journal);\n // No backend call has begun: a stale candidate can be retired without ambiguous publication.\n const atCommitState = syncStateFingerprint(await readStateForConfig(config));\n await validate();\n const atCommit = await createSnapshot(config.snapshotIdentity, snapshotOptions);\n await validate();\n if (!sameHashes(fileHashMap(atCommit), fileHashMap(localRaw)) || atCommitState !== journal.stateIdentity) {\n await validate();\n await clearMergeJournal(config);\n throw new Error(\n \"Local content or baseline changed before publication; candidate retired without transfer. Review a fresh sync.\",\n );\n }\n // Backup/journal awaits can also change physical identity without changing any bytes.\n try {\n await preflightMergedTargets(atCommit, after, snapshotOptions, ctx.sessionManager.getSessionFile?.());\n await validate();\n } catch (error) {\n await validate();\n await clearMergeJournal(config);\n throw error;\n }\n try {\n if (publish) {\n const result = await backend.publishSnapshot(upload, expectedRemoteHead(head), {\n signal: options.signal,\n onCommit: options.onCommit,\n });\n journal.committedHead = result.head;\n journal.warnings = result.warnings;\n await writeMergeJournal(config, journal);\n } else options.onCommit?.();\n } catch (error) {\n if (\n error instanceof SyncBackendConflictError &&\n error.phase === \"before-commit\" &&\n !error.candidateMayHaveBeenActive\n ) {\n await clearMergeJournal(config);\n if (attempt + 1 < MAX_ATTEMPTS) continue;\n throw new Error(\"Remote changed before commit in all three attempts; retry later.\", { cause: error });\n }\n // Cancellation before publication is safe only if no backend attempt began.\n // Every uncertain/after-commit outcome retains evidence and is never blindly retried.\n throw mergeTransferError(error, config.backend);\n }\n const completed = await completeJournal(ctx, config, backend, journal, validate, options.signal, options.auto);\n if (!completed) {\n if (!options.signal?.aborted && (options.auto || !options.silent))\n ctx.ui.notify(\n \"Remote changed before local apply; candidate retired without transfer. Run sync again.\",\n \"warning\",\n );\n return \"cancelled\" as const;\n }\n if (!options.signal?.aborted && (options.auto || !options.silent))\n ctx.ui.notify(\n [\n `Synced independent changes for \u201C${safeTerminalText(config.setupName)}\u201D. ${apply ? \"Local files changed; reload or restart Pi when ready to use changed resources.\" : \"Remote updated.\"} No automatic reload.`,\n ...(progress\n ? [\n `Partial progress: ${groups.length} dependency groups remain unresolved; neither side's withheld versions or baseline hashes were replaced. Review /sync conflicts.`,\n ]\n : []),\n ...(journal.warnings ?? []).map(safeTerminalText),\n ].join(\"\\n\"),\n progress || journal.warnings?.length ? \"warning\" : \"info\",\n );\n return \"applied\" as const;\n }\n } finally {\n await releaseConflictArtifacts(config, ownedStatePath, createdArtifacts);\n }\n}\n\nasync function completeJournal(\n ctx: ExtensionContext | ExtensionCommandContext,\n config: AnySyncConfig,\n backend: SyncBackend,\n journal: MergeJournal,\n validate: () => Promise<void>,\n signal?: AbortSignal,\n auto = false,\n) {\n if (\n journal.identity !== mergeJournalIdentity(config, backend.identity) ||\n !sameLocalFields(journal.upload.localFields, config.localFields)\n )\n throw new Error(\n \"Merge journal belongs to a different setup, selection or local-field policy; preserve it for reviewed recovery.\",\n );\n await validate();\n const sessionRoot = config.include.includes(\"sessions\") ? await effectiveSessionRoot(ctx) : undefined;\n await validate();\n if (sessionRoot !== undefined && journal.sessionRoot !== sessionRoot) {\n throw new Error(\n \"Merge journal session root is missing or differs from this context; preserve evidence and use reviewed directional recovery.\",\n );\n }\n const snapshotOptions = { ...snapshotOptionsForContext(ctx, config), sessionDir: sessionRoot, signal };\n const head = await backend.readHead(signal);\n if (\n !journal.committedHead &&\n head &&\n (backend.sameRevision(head.revision, journal.expectedHead.revision) ||\n backend.matchesUncommittedRecoveryHead?.(head, journal.expectedHead))\n ) {\n await validate();\n const local = await createSnapshot(config.snapshotIdentity, snapshotOptions);\n if (\n !sameHashes(fileHashMap(local), fileHashMap(journal.before)) ||\n syncStateFingerprint(await readStateForConfig(config)) !== journal.stateIdentity\n ) {\n throw new Error(\n \"Uncertain publication is not active, but local content or baseline changed; keep the journal for reviewed recovery.\",\n );\n }\n await clearMergeJournal(config);\n return false;\n }\n await validate();\n // Baseline publication is the durable completion boundary. A later remote revision\n // cannot undo that acceptance; retire only the journal for the recorded commit.\n if (journal.committedHead && (!head || !backend.sameRevision(head.revision, journal.committedHead.revision))) {\n const state = await readStateForConfig(config);\n await validate();\n if (\n matchesAcceptedState(state, config, journal.committedHead, journal.accepted ?? journal.after, journal.progress)\n ) {\n await clearMergeJournal(config);\n await validate();\n await pruneMergeBaselines(config, state, captureMutationOwner(ctx, signal));\n await validate();\n return true;\n }\n }\n if (journal.applyOnly && (!head || !backend.sameRevision(head.revision, journal.expectedHead.revision))) {\n const local = await createSnapshot(config.snapshotIdentity, snapshotOptions);\n const state = await readStateForConfig(config);\n await validate();\n if (\n sameHashes(fileHashMap(local), fileHashMap(journal.before)) &&\n syncStateFingerprint(state) === journal.stateIdentity\n ) {\n await clearMergeJournal(config);\n return false;\n }\n throw new Error(\"Apply-only remote head advanced after local changes; preserve the journal for reviewed recovery.\");\n }\n if (\n !head ||\n head.snapshotId !== journal.upload.id ||\n (journal.committedHead && !backend.sameRevision(head.revision, journal.committedHead.revision))\n ) {\n throw new Error(\n \"Publication outcome cannot be reconciled with the current remote head. Journal and backup retained; do not retry publication or restore old bytes blindly.\",\n );\n }\n const observed = await readSnapshotForHead(backend, head, signal);\n requireCompatibleRemoteSelection(config, observed);\n if (\n !sameHashes(fileHashMap(observed), fileHashMap(journal.upload)) ||\n JSON.stringify(observed.selection) !== JSON.stringify(journal.upload.selection)\n )\n throw new Error(\"Remote snapshot does not match the recorded merge publication.\");\n const state = await readStateForConfig(config);\n if (matchesAcceptedState(state, config, head, journal.accepted ?? journal.after, journal.progress)) {\n await validate();\n await clearMergeJournal(config);\n await validate();\n await pruneMergeBaselines(config, state, captureMutationOwner(ctx, signal));\n await validate();\n return true;\n }\n if (syncStateFingerprint(state) !== journal.stateIdentity) {\n throw new Error(\"Sync baseline changed after the interrupted merge; preserve its journal and review recovery.\");\n }\n if (inspectRemoteSelection(config.include, observed).kind !== \"same\")\n throw new Error(\n \"Pending merge has unavailable remote selection metadata; preserve its journal and choose a reviewed explicit direction.\",\n );\n if (config.include.includes(\"sessions\")) requireStableMergeSessionRoot(journal.before, journal.after);\n await validate();\n const validateOwner = captureMutationOwner(ctx, signal);\n const validateMutation = () => {\n validateOwner();\n if (auto && !ctx.isIdle()) throw new Error(\"Automatic file apply is no longer idle; evidence retained.\");\n };\n await applyMergedSnapshot(\n journal.before,\n journal.after,\n protectedSessionPaths(ctx, sessionRoot),\n { ...snapshotOptions, validateMutation },\n validate,\n ctx.sessionManager.getSessionFile?.(),\n );\n await validate();\n const headAtAcceptance = await backend.readHead(signal);\n await validate();\n if (!headAtAcceptance || !backend.sameRevision(headAtAcceptance.revision, head.revision))\n throw new Error(\"Remote changed during merged apply; journal and backup retained for review.\");\n await writeAcceptedState(config, head, journal.accepted ?? journal.after, validate, journal.progress);\n await validate();\n await clearMergeJournal(config);\n await validate();\n await pruneMergeBaselines(\n config,\n acceptedState(config, head, journal.accepted ?? journal.after, journal.progress),\n captureMutationOwner(ctx, signal),\n );\n await validate();\n await pruneCompletedConflicts(\n config,\n backend.identity,\n acceptedState(config, head, journal.accepted ?? journal.after, journal.progress),\n journal.accepted ?? journal.after,\n journal.upload,\n captureMutationOwner(ctx, signal),\n );\n await validate();\n return true;\n}\n\n// Older valid journals may have accepted noncanonical JSON before projection normalization.\nfunction matchesAcceptedState(\n state: Awaited<ReturnType<typeof readStateForConfig>>,\n config: AnySyncConfig,\n head: RemoteHead,\n snapshot: Snapshot,\n progress?: PartialProgress,\n) {\n return [true, false].some(\n (canonical) =>\n syncStateFingerprint(state) === syncStateFingerprint(acceptedState(config, head, snapshot, progress, canonical)),\n );\n}\n\nfunction acceptedState(\n config: AnySyncConfig,\n head: RemoteHead,\n snapshot: Snapshot,\n progress?: PartialProgress,\n canonical = true,\n) {\n if (progress) return progressState(config, head, snapshot, progress);\n return {\n version: 1,\n profile: config.snapshotIdentity,\n lastAppliedSnapshot: head.snapshotId,\n lastRemoteRevision: head.revision,\n lastFileHashes: fileHashMap(canonical ? portableSnapshot(snapshot, config.localFields) : snapshot),\n include: [...config.include],\n ...(config.localFields !== undefined ? { localFields: config.localFields } : {}),\n };\n}\n\nasync function writeAcceptedState(\n config: AnySyncConfig,\n head: RemoteHead,\n snapshot: Snapshot,\n validate: () => Promise<void>,\n progress?: PartialProgress,\n) {\n const accepted = portableSnapshot(snapshot, config.localFields);\n const state = acceptedState(config, head, accepted, progress);\n await stageMergeBaseline(config, accepted, state, progress?.previous);\n await validate();\n await writeStateForConfig(config, state);\n await validate();\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,SAAS,mBAAAA,wBAAuB;AAChC,SAAS,YAAY,sBAAsB,mBAAmB,eAAe;;;ACD7E,SAAS,KAAK,YAAY,YAA0C,uBAAuB;AAC3F,SAAS,gBAAgB,0BAA0B,4BAA4B;AAKxE,SAAS,uBAAuB,SAQpC;AACD,QAAM,EAAE,KAAK,OAAO,YAAY,IAAI;AACpC,QAAM,UAAoC,CAAC,UAAU,WAAW,SAAS;AACzE,QAAM,OAAO,IAAI;AAAA,IACf;AAAA,MACE,EAAE,OAAO,UAAU,OAAO,aAAa;AAAA,MACvC,EAAE,OAAO,WAAW,OAAO,QAAQ,qBAAqB,QAAQ,iBAAiB,CAAC,GAAG;AAAA,MACrF,EAAE,OAAO,WAAW,OAAO,eAAe;AAAA,IAC5C;AAAA,IACA;AAAA,IACA;AAAA,MACE,gBAAgB,CAAC,SAAS,MAAM,GAAG,UAAU,IAAI;AAAA,MACjD,cAAc,CAAC,SAAS,MAAM,GAAG,UAAU,IAAI;AAAA,MAC/C,aAAa,CAAC,SAAS,MAAM,GAAG,SAAS,IAAI;AAAA,MAC7C,YAAY,CAAC,SAAS,MAAM,GAAG,OAAO,IAAI;AAAA,MAC1C,SAAS,CAAC,SAAS,MAAM,GAAG,SAAS,IAAI;AAAA,IAC3C;AAAA,EACF;AACA,QAAM,OAAO,IAAI,eAAe,EAAE,WAAW,CAAC,SAAS,MAAM,GAAG,UAAU,IAAI,EAAE,CAAC;AACjF,MAAI,WAAW;AACf,MAAI,SAAS;AACb,MAAI,gBAAgB;AACpB,MAAI,YAAY;AAChB,MAAI,WAAW;AACf,MAAI,OAAO,oBAAI,IAAY;AAC3B,MAAI,UAA6B,CAAC;AAClC,MAAI,WAAW;AACf,MAAI,WAAW;AACf,MAAI,WAAW;AACf,MAAI,eAAe;AACnB,MAAI,aAAa;AACjB,MAAI,eAAe;AACnB,QAAM,SAAS,CAAC,WAAmC;AACjD,QAAI,YAAY,SAAU;AAC1B,eAAW;AACX,YAAQ,SAAS,MAAM;AAAA,EACzB;AACA,QAAM,SAAS,CAAC,UAAkB;AAChC,gBAAY,QAAQ,QAAQ,UAAU,QAAQ;AAC9C,SAAK,iBAAiB,QAAQ;AAAA,EAChC;AACA,OAAK,oBAAoB,CAAC,SAAS;AACjC,eAAW,KAAK,IAAI,GAAG,QAAQ,QAAQ,KAAK,KAA+B,CAAC;AAAA,EAC9E;AACA,OAAK,WAAW,CAAC,SAAS;AACxB,UAAM,SAAS,QAAQ,QAAQ,KAAK;AACpC,QAAI,KAAK,UAAU,WAAW,WAAW,aAAa,UAAW,QAAO,MAAM;AAAA,EAChF;AACA,QAAM,YAAY;AAAA,IAChB,OAAO,OAAe,SAAS,MAAgB;AAC7C,UAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,GAAG;AACzC,mBAAW;AACX,eAAO,CAAC;AAAA,MACV;AACA,YAAM,QAAQ,KAAK,MAAM,KAAK;AAC9B,YAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI,SAAS,IAAI,IAAI,CAAC;AAC1D,UAAI,UAAU,aAAa,SAAS,UAAU;AAG5C,kBAAU,QAAQ,MAAM,QAAQ,CAAC,SAAS,yBAAyB,MAAM,KAAK,CAAC;AAC/E,eAAO,oBAAI,IAAI;AACf,iBAAS;AACT,eAAO,CAAC;AACR,oBAAY;AACZ,mBAAW;AAAA,MACb;AACA,YAAM,SAAS,QAAQ;AACvB,YAAM,UAAU,KAAK,OAAO,KAAK;AACjC,YAAM,WAAW,KAAK,IAAI,GAAG,OAAO,QAAQ,SAAS,KAAK,SAAS,IAAI,EAAE;AACzE,sBAAgB,KAAK,IAAI,GAAG,QAAQ,SAAS,QAAQ;AACrD,eAAS,KAAK,IAAI,QAAQ,aAAa;AACvC,YAAM,UAAU,QAAQ,MAAM,QAAQ,SAAS,QAAQ;AACvD,UAAI,OAAQ,UAAS,QAAQ,QAAQ,QAAQ,SAAS,QAAQ,QAAQ,QAAS,MAAK,IAAI,KAAK;AAC7F,iBAAW,WAAW,KAAK,KAAK,SAAS,QAAQ;AAGjD,YAAM,OAAO,WAAW,sBAAsB;AAC9C,YAAM,OAAO;AAAA,QACX,MAAM,GAAG,UAAU,MAAM,KAAK,yBAAyB,QAAQ,OAAO,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC;AAAA,QACvF,GAAG,QAAQ,IAAI,CAAC,SAAS,MAAM,GAAG,QAAQ,IAAI,CAAC;AAAA,QAC/C,MAAM;AAAA,UACJ;AAAA,UACA,WAAW,QAAQ,SAAS,SAAS,IAAI,CAAC,IAAI,SAAS,QAAQ,MAAM,IAAI,QAAQ,MAAM,GAAG,WAAW,KAAK,2BAAsB;AAAA,QAClI;AAAA,QACA,GAAG;AAAA,QACH,MAAM,GAAG,OAAO,IAAI;AAAA,MACtB;AACA,qBAAe,OAAO,MAAM,IAAI;AAChC,mBAAa,eAAe,QAAQ;AACpC,qBAAe,aAAa;AAC5B,YAAM,QAAQ,SAAS,CAAC,GAAG,KAAK,OAAO,KAAK,GAAG,GAAG,MAAM,GAAG,KAAK,OAAO,KAAK,CAAC,IAAI;AAGjF,aAAO,MAAM,MAAM,GAAG,IAAI,EAAE,IAAI,CAAC,SAAS,gBAAgB,MAAM,OAAO,EAAE,CAAC;AAAA,IAC5E;AAAA,IACA,aAAa;AACX,WAAK,WAAW;AAChB,WAAK,WAAW;AAAA,IAClB;AAAA,IACA,YAAY,MAAc;AACxB,UAAI,YAAY,SAAU;AAC1B,UAAI,WAAW,MAAM,IAAI,KAAK,GAAG,CAAC,KAAK,YAAY,QAAQ,MAAM,mBAAmB,GAAG;AACrF,eAAO,QAAQ;AACf;AAAA,MACF;AAEA,gBAAU,OAAO,IAAI,SAAS,WAAW,WAAW,KAAK;AACzD,UAAI,YAAY,QAAQ,MAAM,eAAe,GAAG;AAC9C,YAAI,CAAC,YAAa,aAAa,KAAK,SAAS,EAAI,UAAS,KAAK,IAAI,GAAG,SAAS,CAAC;AAAA,YAC3E,QAAO,WAAW,CAAC;AAAA,MAC1B,WAAW,YAAY,QAAQ,MAAM,iBAAiB,GAAG;AACvD,YAAI,CAAC,YAAa,aAAa,KAAK,SAAS,cAAgB,UAAS,KAAK,IAAI,eAAe,SAAS,CAAC;AAAA,YACnG,QAAO,WAAW,CAAC;AAAA,MAC1B,WAAW,YAAY,QAAQ,MAAM,oBAAoB,GAAG;AAC1D,cAAM,SAAS,QAAQ,QAAQ,KAAK;AACpC,YAAI,WAAW,aAAa,SAAU,QAAO,MAAM;AAAA,MACrD;AACA,UAAI,cAAc;AAAA,IACpB;AAAA,IACA,YAAY,OAAsB;AAChC,UAAI,YAAY,YAAY,MAAM,UAAU,UAAW,QAAO;AAC9D,gBAAU,OAAO,MAAM,OAAO,KAAK;AACnC,UAAI,MAAM,KAAK,gBAAgB,MAAM,IAAI,cAAc,MAAM,SAAS,WAAW,MAAM,YAAY;AACjG,iBAAS,KAAK,IAAI,GAAG,KAAK,IAAI,eAAe,UAAU,MAAM,aAAa,IAAI,KAAK,EAAE,CAAC;AACtF,eAAO,CAAC;AACR,YAAI,cAAc;AAClB,eAAO,EAAE,SAAS,MAAM,QAAQ,KAAK;AAAA,MACvC;AACA,UAAI,MAAM,IAAI,gBAAgB,MAAM,KAAK,eAAe,QAAQ,UAAU,MAAM,KAAK,SAAU,QAAO;AACtG,aAAO,KAAK,YAAY,EAAE,GAAG,OAAO,GAAG,MAAM,IAAI,cAAc,QAAQ,QAAQ,OAAO,CAAC;AAAA,IACzF;AAAA,IACA,UAAU;AACR,iBAAW;AACX,WAAK,MAAM;AAAA,IACb;AAAA,EACF;AACA,SAAO;AACT;;;AD/IA,eAAsB,mBACpB,KACA,OACA,SACA,QACA,WACA,oBAAoB,iBACpB,cACA;AACA,QAAM,QAAQ,gBAAgB;AAAA,IAC5B,GAAG,QACA,MAAM,IAAI,EACV,MAAM,GAAG,CAAC,EACV,IAAI,CAAC,SAASC,iBAAgB,iBAAiB,IAAI,GAAG,GAAG,CAAC;AAAA,IAC7D;AAAA,EACF;AACA,SAAO,UAAU,KAAK,CAAC,QAAQ,SAAS;AACtC,UAAM,SAAsD,EAAE,OAAO,SAAS;AAC9E,UAAM,OAAO,WAA0D;AAAA,MACrE,OAAO;AAAA,MACP,SAAS;AAAA,QACP,SAAS,OAAO;AAAA,UACd,MAAM;AAAA,UACN;AAAA,UACA;AAAA,UACA,eAAe;AAAA,UACf,OAAO;AAAA,YACL,EAAE,IAAI,UAAU,OAAO,aAAa;AAAA,YACpC,EAAE,IAAI,WAAW,OAAO,QAAQ,iBAAiB,GAAG;AAAA,YACpD,EAAE,IAAI,WAAW,OAAO,eAAe;AAAA,UACzC;AAAA,UACA,QAAQ;AAAA,UACR,MAAM;AAAA,QACR;AAAA,MACF;AAAA,MACA,SAAS;AAAA,QACP,QAAQ,CAAC,EAAE,OAAO,MAAM;AACtB,cAAI,WAAW,aAAa,WAAW,UAAW,QAAO,QAAQ;AACjE,iBAAO,EAAE,MAAM,QAAQ;AAAA,QACzB;AAAA,MACF;AAAA,IACF,CAAC;AACD,UAAM,SACJ,IAAI,SAAS,SAAS,IAAI,QACtB,MAAM,qBAA4D,KAAK;AAAA,MACrE,QAAQ,CAAC,EAAE,KAAK,OAAO,aAAa,SAAS,MAC3C,uBAAuB,EAAE,OAAO,OAAO,mBAAmB,KAAK,OAAO,aAAa,SAAS,CAAC;AAAA,MAC/F;AAAA,MACA;AAAA,MACA,SAAS,MAAM;AAAA,MAAC;AAAA,IAClB,CAAC,IACD,MAAM,QAAQ,KAAK,MAAM,EAAE,UAAU,MAAM,QAAW,QAAQ,WAAW,SAAS,MAAM;AAAA,IAAC,EAAE,CAAC;AAClG,QAAI,CAAC,UAAU,KAAK,QAAQ,QAAS,QAAO;AAC5C,QAAI,OAAO,SAAS,QAAS,OAAM,IAAI,MAAM,iDAAiD;AAC9F,QAAI,OAAO,SAAS;AAClB,YAAM,IAAI,MAAM,kFAAkF;AACpG,QAAI,OAAO,SAAS,YAAa,QAAO,QAAQ,OAAO;AAAA,aAC9C,OAAO,SAAS,SAAU,QAAO;AAE1C,QAAI,OAAO,UAAU,UAAW,QAAO;AACvC,QAAI,OAAO,UAAU,UAAW,QAAO;AACvC,UAAM,SAAS,MAAM,kBAAkB,KAAK;AAAA,MAC1C,OAAO;AAAA,MACP;AAAA,MACA,QAAQ,EAAE,MAAM,OAAO;AAAA,MACvB,cAAc;AAAA,MACd,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,SAAS,MAAM;AAAA,MAAC;AAAA,IAClB,CAAC;AACD,QAAI,CAAC,UAAU,KAAK,QAAQ,QAAS,QAAO;AAC5C,QAAI,OAAO,SAAS,QAAS,OAAM,IAAI,MAAM,iDAAiD;AAC9F,QAAI,OAAO,SAAS,eAAe,OAAO,WAAW,OAAQ,QAAO;AAAA,EAGtE;AACA,SAAO;AACT;;;AEvFA,SAAS,mBAAAC,wBAAuB;AA2BzB,SAAS,kBAAkB,OAA+B;AAC/D,QAAM,QAAQ,QAAQ,MAAM,aAAa,MAAM,UAAU;AACzD,QAAM,SAAS,QAAQ,MAAM,cAAc,MAAM,WAAW;AAC5D,QAAM,MAAM,CAAC,GAAG,OAAO,GAAG,MAAM;AAChC,QAAM,cAAc,IAAI,SAAS,KAAK,IAAI,MAAM,CAAC,WAAW,OAAO,WAAW,QAAQ;AACtF,QAAM,OAAO,cAAc,WAAW;AACtC,QAAM,QACJ,MAAM,UAAU,OAAO,SACnB,oCACA,IAAI,SACF,GAAG,IAAI,IAAI,IAAI,MAAM,IAAI,MAAM,SAAS,UAAU,QAAQ,IAAI,IAAI,WAAW,IAAI,SAAS,OAAO,MACjG,MAAM,UACJ,mCACA;AACV,QAAM,oBACJ,MAAM,UAAU,OAAO,SACnB,mCACA,IAAI,SACF,GAAG,cAAc,WAAW,kBAAkB,IAAI,MAAM,SAAS,UAAU,QAAQ,IAAI,IAAI,WAAW,IAAI,SAAS,OAAO,KAC1H;AACR,QAAM,UAAU,IAAI;AAAA,IAClB,MAAM,UAAU,OAAO,CAAC,SAAS,KAAK,SAAS,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,MAAM,KAAK,MAAM,CAAC;AAAA,EACnG;AACA,QAAM,QAAQ,CAAC,QAAoB,SAA6B;AAC9D,UAAM,SAAS,QAAQ,IAAI,OAAO,IAAI;AACtC,UAAM,SACJ,WAAW,WACP,sBACA,SAAS,WAAW,WAAW,WAC7B,OAAO,WAAW,WAChB,wBACA,iBACF;AACR,WAAO,GAAG,OAAO,MAAM,IAAI,kBAAkB,OAAO,IAAI,CAAC,GAAG,MAAM;AAAA,EACpE;AACA,QAAM,UAAU,CAAC,OAAqB,MAA0B,YAAqB;AACnF,UAAM,UAAU,SAAS,UAAU,kBAAkB;AACrD,QAAI,CAAC,MAAM,OAAQ,QAAO,CAAC,GAAG,OAAO,QAAQ;AAC7C,UAAM,SAAS,CAAC,OAAO,UAAU,QAAQ,EAAE,QAAQ,CAAC,WAAW;AAC7D,YAAM,QAAQ,MAAM,OAAO,CAAC,SAAS,KAAK,WAAW,MAAM,EAAE;AAC7D,aAAO,QAAQ,CAAC,GAAG,KAAK,IAAI,OAAO,YAAY,CAAC,EAAE,IAAI,CAAC;AAAA,IACzD,CAAC;AACD,WAAO;AAAA,MACL,GAAG,OAAO,KAAK,OAAO,KAAK,IAAI,CAAC;AAAA,MAChC,IAAI,UAAU,MAAM,MAAM,GAAG,CAAC,IAAI,OAAO;AAAA,QACvC,CAAC,SAAS,KAAK,UAAUC,iBAAgB,MAAM,MAAM,IAAI,GAAG,EAAE,IAAI,MAAM,MAAM,IAAI,CAAC;AAAA,MACrF;AAAA,MACA,GAAI,WAAW,MAAM,SAAS,IAAI,CAAC,KAAK,MAAM,SAAS,CAAC,iCAA4B,IAAI,CAAC;AAAA,IAC3F;AAAA,EACF;AACA,QAAM,UAAU,CAAC,UAAU,iBAAiB,MAAM,SAAS,CAAC,IAAI,WAAW,iBAAiB,MAAM,WAAW,CAAC,EAAE;AAChH,QAAM,SAAS;AAAA,IACb,gCAAgC,MAAM,UAAU,QAAQ,IAAI;AAAA,IAC5D,aAAa,MAAM,WAAW,sDAAiD,cAAc;AAAA,IAC7F,MAAM,OAAO,SACT,sBAAsB,MAAM,OAAO,MAAM,oDACzC;AAAA,IACJ,GAAI,MAAM,WAAW,MAAM,eAAe,4BACtC,CAAC,mFAAmF,IACpF,CAAC;AAAA,IACL,GAAI,MAAM,WAAW,MAAM,eAAe,yBACtC,CAAC,mGAAmG,IACpG,CAAC;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,OAAO;AAAA,MACL,GAAG,QAAQ,IAAI,CAAC,SAASA,iBAAgB,MAAM,GAAG,CAAC;AAAA,MACnD,GAAG,QAAQ,OAAO,SAAS,IAAI;AAAA,MAC/B,GAAG,QAAQ,QAAQ,UAAU,IAAI;AAAA,MACjC,GAAG;AAAA,IACL;AAAA,IACA,SAAS;AAAA,MACP,GAAG;AAAA,MACH;AAAA,MACA,GAAG,QAAQ,OAAO,SAAS,KAAK;AAAA,MAChC;AAAA,MACA,GAAG,QAAQ,QAAQ,UAAU,KAAK;AAAA,MAClC;AAAA,MACA,GAAG;AAAA,MACH,GAAG,MAAM,OAAO;AAAA,QAAQ,CAAC,UACvB,MAAM,MAAM,IAAI,CAAC,aAAa,2BAA2B,kBAAkB,QAAQ,CAAC,EAAE;AAAA,MACxF;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;AAEA,SAAS,QAAQ,QAAkB,OAA+B;AAChE,QAAM,YAAY,YAAY,MAAM;AACpC,QAAM,WAAW,YAAY,KAAK;AAClC,SAAO,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,SAAS,GAAG,GAAG,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,EACtE,KAAK,EACL,QAAQ,CAAC,aAA2B;AACnC,QAAI,CAAC,OAAO,OAAO,WAAW,QAAQ,EAAG,QAAO,CAAC,EAAE,MAAM,UAAU,QAAQ,MAAM,CAAC;AAClF,QAAI,CAAC,OAAO,OAAO,UAAU,QAAQ,EAAG,QAAO,CAAC,EAAE,MAAM,UAAU,QAAQ,SAAS,CAAC;AACpF,WAAO,UAAU,QAAQ,MAAM,SAAS,QAAQ,IAAI,CAAC,EAAE,MAAM,UAAU,QAAQ,SAAS,CAAC,IAAI,CAAC;AAAA,EAChG,CAAC;AACL;;;AC/HA,OAAO,QAAQ;AACf,OAAO,UAAU;AAajB,eAAsB,yBACpB,QACA,WACA,SACA;AACA,MAAI,CAAC,QAAQ,UAAU,mBAAmB,MAAM,MAAM,UAAW;AACjE,MAAI;AACF,UAAM,QAAQ,MAAM,mBAAmB,MAAM;AAC7C,QAAI,mBAAmB,MAAM,MAAM,UAAW;AAC9C,UAAM,UAAU,MAAM,iBAAiB,MAAM;AAC7C,QAAI,mBAAmB,MAAM,MAAM,UAAW;AAC9C,UAAM,aAAa,oBAAI,IAAI;AAAA,MACzB,IAAI,MAAM,cAAc,CAAC,GAAG,IAAI,CAAC,UAAU,MAAM,QAAQ;AAAA,MACzD,IAAI,SAAS,UAAU,UAAU,CAAC,GAAG,IAAI,CAAC,UAAU,MAAM,QAAQ;AAAA,IACpE,CAAC;AACD,eAAW,SAAS,SAAS;AAC3B,UAAI,WAAW,IAAI,MAAM,KAAK,KAAK,MAAM,WAAW,KAAK,KAAK,kBAAkB,MAAM,GAAG,GAAG,MAAM,KAAK,OAAO;AAC5G;AACF,UAAI;AACF,cAAM,OAAO,MAAM,GAAG,MAAM,MAAM,MAAM;AACxC,YACE,CAAC,KAAK,OAAO,KACb,KAAK,UAAU,KACf,KAAK,QAAQ,MAAM,OACnB,KAAK,QAAQ,MAAM,OACnB,KAAK,SAAS,MAAM;AAEpB;AACF,cAAM,WAAW,KAAK,MAAM,MAAM,GAAG,SAAS,MAAM,QAAQ,MAAM,CAAC;AACnE,YAAI,4BAA4B,QAAQ,MAAM,MAAM,eAAe,mBAAmB,MAAM,MAAM;AAChG;AACF,cAAM,SAAS,MAAM,GAAG,MAAM,MAAM,MAAM;AAC1C,YACE,OAAO,QAAQ,MAAM,OACrB,OAAO,QAAQ,MAAM,OACrB,OAAO,UAAU,KACjB,mBAAmB,MAAM,MAAM;AAE/B;AACF,cAAM,GAAG,OAAO,MAAM,MAAM;AAC5B,cAAM,cAAc,KAAK,QAAQ,MAAM,MAAM,CAAC;AAAA,MAChD,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AACF;;;AC/CA,eAAsB,qBACpB,QACA,SACA,OACA,OACA,QACA,MACA,MACA,YACA,gBACwB;AACxB,QAAM,WAAW,MAAM,qBAAqB,QAAQ,QAAQ,UAAU,WAAW,KAAK;AACtF,QAAM,QAAQ,SAAS,OAAO,WAAW,KAAK;AAC9C,MACE,4BAA4B,QAAQ,MAAM,WAAW,oBACrD,CAAC,SACD,KAAK,SAAS,aACd,CAAC,MAAM,YAAY;AAAA,IACjB,CAAC,SAAS,KAAK,aAAa,WAAW,SAAS,KAAK,UAAU,KAAK,KAAK,MAAM,KAAK,UAAU,MAAM,KAAK;AAAA,EAC3G,KACA,qBAAqB,KAAK,MAAM,WAAW,iBAC3C,MAAM,yBAAyB,KAAK,cACpC,CAAC,MAAM,wBACP,CAAC,QAAQ,aAAa,MAAM,sBAAsB,KAAK,QAAQ;AAE/D,UAAM,IAAI,MAAM,0DAA0D;AAC5E,QAAM,OAAO,YAAY,KAAK;AAC9B,QAAM,SAAS,YAAY,MAAM;AACjC,QAAM,UAAU,YAAY,SAAS,KAAK;AAC1C,QAAM,YAAY,YAAY,SAAS,MAAM;AAC7C,MACE,MAAM,MAAM;AAAA,IACV,CAAC,aACC,KAAK,QAAQ,MAAM,QAAQ,QAAQ,KACnC,OAAO,QAAQ,MAAM,UAAU,QAAQ,KACvC,MAAM,eAAe,QAAQ,MAAM,SAAS,MAAM,eAAe,QAAQ;AAAA,EAC7E;AAEA,UAAM,IAAI,MAAM,uDAAuD;AACzE,MACE,MAAM,MAAM;AAAA,IAAK,CAAC,aAChB,CAAC,GAAG,cAAc,EAAE,KAAK,CAAC,UAAU,kBAAkB,KAAK,MAAM,kBAAkB,QAAQ,CAAC;AAAA,EAC9F;AAEA,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AACF,QAAM,WAAW,WAAW,WAAW,UAAU,QAAQ;AACzD,QAAM,QAAQ,IAAI,IAAI,MAAM,KAAK;AACjC,aAAW,YAAY,CAAC,UAAU,KAAK,GAAG;AACxC,UAAM,SAAS,cAAc;AAAA,MAC3B,UAAU,CAAC;AAAA,MACX,OAAO,SAAS,MAAM,OAAO,CAAC,SAAS,MAAM,IAAI,KAAK,IAAI,CAAC;AAAA,MAC3D,QAAQ,CAAC;AAAA,MACT,qBAAqB;AAAA,IACvB,CAAC;AACD,QAAI,OAAO,SAAS,aAAa,OAAO,UAAU;AAChD,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,EACJ;AACA,QAAM,gBAAgB,IAAI,IAAI,SAAS,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC;AAC7E,QAAM,YAAY,KAAK,UAAU;AAAA,IAAI,CAAC,SACpC,MAAM,IAAI,KAAK,IAAI,IACf;AAAA,MACE,MAAM;AAAA,MACN,MAAM,KAAK;AAAA,MACX,QAAQ,WAAW;AAAA,MACnB,MAAM,cAAc,IAAI,KAAK,IAAI;AAAA,IACnC,IACA;AAAA,EACN;AACA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,WAAW,UAAU,OAAO,CAAC,SAA6D,KAAK,SAAS,UAAU;AAAA,EACpH;AACF;;;AC5FA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAQjB,eAAsB,wBACpB,QACA,SACA,OACA,OACA,QACA,UACA;AACA,WAAS;AACT,QAAM,YAAY,kBAAkB,MAAM;AAC1C,MAAI;AACJ,MAAI;AACF,UAAM,OAAO,MAAMC,IAAG,MAAM,SAAS;AACrC,aAAS;AACT,QAAI,CAAC,KAAK,YAAY,KAAK,KAAK,eAAe,EAAG,OAAM,IAAI,MAAM,sCAAsC;AACxG,YAAQ,MAAMA,IAAG,QAAQ,SAAS;AAClC,aAAS;AAAA,EACX,SAAS,OAAO;AACd,QAAK,MAAgC,SAAS,SAAU;AACxD,UAAM;AAAA,EACR;AACA,QAAM,SAAS,IAAI,IAAI,MAAM,YAAY,IAAI,CAAC,UAAU,MAAM,QAAQ,KAAK,CAAC,CAAC;AAC7E,QAAM,OAAO,YAAY,KAAK;AAC9B,QAAM,SAAS,YAAY,MAAM;AACjC,QAAM,YAAmD,CAAC;AAC1D,aAAW,QAAQ,OAAO;AACxB,aAAS;AACT,UAAM,QAAQ,KAAK,QAAQ,YAAY,EAAE;AACzC,QAAI,CAAC,yBAAyB,KAAK,IAAI,KAAK,OAAO,IAAI,KAAK,EAAG;AAC/D,QAAI;AACF,YAAM,WAAW,MAAM,qBAAqB,QAAQ,SAAS,KAAK;AAClE,eAAS;AACT,YAAM,gBAAgB,YAAY,SAAS,KAAK;AAChD,YAAM,iBAAiB,YAAY,SAAS,MAAM;AAClD,UACE,CAAC,SAAS,OAAO;AAAA,QAAM,CAAC,UACtB,MAAM,MAAM;AAAA,UACV,CAAC,aACC,MAAM,eAAe,QAAQ,MAAM,KAAK,QAAQ,KAChD,KAAK,QAAQ,MAAM,OAAO,QAAQ,MACjC,KAAK,QAAQ,MAAM,cAAc,QAAQ,KAAK,KAAK,QAAQ,MAAM,eAAe,QAAQ;AAAA,QAC7F;AAAA,MACF;AAEA;AACF,YAAM,OAAO,MAAMA,IAAG,MAAMC,MAAK,KAAK,WAAW,IAAI,CAAC;AACtD,eAAS;AACT,UAAI,KAAK,OAAO,EAAG,WAAU,KAAK,EAAE,OAAO,UAAU,KAAK,QAAQ,CAAC;AAAA,IACrE,QAAQ;AACN,eAAS;AAAA,IACX;AAAA,EACF;AACA,YAAU,KAAK,CAAC,MAAM,UAAU,MAAM,WAAW,KAAK,YAAY,KAAK,MAAM,cAAc,MAAM,KAAK,CAAC;AACvG,aAAW,SAAS,UAAU,MAAM,EAAE,GAAG;AACvC,aAAS;AACT,UAAMD,IAAG,GAAGC,MAAK,KAAK,WAAW,GAAG,MAAM,KAAK,OAAO,CAAC;AACvD,aAAS;AAAA,EACX;AACA,MAAI,UAAU,SAAS,IAAI;AACzB,UAAM,cAAc,SAAS;AAC7B,aAAS;AAAA,EACX;AACF;;;ACvEA,SAAS,kBAAkB;AAQpB,SAAS,aAAa,UAAkB,OAA6B;AAC1E,SAAO;AAAA,IACL,MAAM;AAAA,IACN,eAAe,MAAM,SAAS,QAAQ;AAAA,IACtC,QAAQ,WAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AAAA,EACzD;AACF;AACA,eAAsB,wBACpB,QACA,OACA,OACA,QACA,MACA,gBACA,UAAkE,CAAC,GAC3C;AACxB,MAAI,KAAK,SAAS,aAAa,CAAC,OAAO,aAAc,QAAO;AAC5D,UAAQ,QAAQ,eAAe;AAC/B,QAAM,SAAS,QAAQ,cAAc,EAAE,WAAW,sBAAsB;AACxE,QAAM,YAAY,CAAC,GAAG,KAAK,SAAS;AACpC,MAAI,YAA4B,CAAC;AACjC,MAAI;AACF,gBAAa,MAAM,mBAAmB,QAAQ,KAAK,KAAM,CAAC;AAAA,EAC5D,QAAQ;AACN,YAAQ,QAAQ,eAAe;AAC/B,WAAO;AAAA,EACT;AACA,UAAQ,QAAQ,eAAe;AAC/B,QAAM,aAAa,IAAI,IAAI,MAAM,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC;AACvE,QAAM,eAAe,IAAI,IAAI,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC;AAC1E,QAAM,kBAAkB,IAAI,IAAI,UAAU,IAAI,CAAC,SAAS,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC;AAC1E,QAAM,gBAAgB,IAAI,IAAI,UAAU,IAAI,CAAC,UAAU,UAAU,CAAC,SAAS,MAAM,KAAK,CAAC,CAAC;AACxF,QAAM,gBAAgB,IAAI,IAAI,CAAC,GAAG,cAAc,EAAE,IAAI,iBAAiB,CAAC;AACxE,aAAW,YAAY,KAAK,WAAW;AACrC,YAAQ,QAAQ,eAAe;AAC/B,QAAI,SAAS,WAAW,kBAAkB,cAAc,IAAI,kBAAkB,SAAS,IAAI,CAAC,EAAG;AAC/F,UAAM,UAAU,SAAS,KAAK,WAAW,WAAW,KAAK,SAAS,KAAK,SAAS,QAAQ;AACxF,QAAI,CAAC,YAAY,CAAC,gBAAgB,SAAS,IAAI,KAAK,OAAO,cAAc,GAAI;AAC7E,UAAM,OAAO,WAAW,IAAI,SAAS,IAAI;AACzC,UAAM,SAAS,aAAa,IAAI,SAAS,IAAI;AAC7C,QAAI,CAAC,QAAQ,CAAC,OAAQ;AACtB,UAAM,WAAW,gBAAgB,IAAI,SAAS,IAAI;AAClD,UAAM,OAAO,WAAW,OAAO,KAAK,SAAS,eAAe,QAAQ,IAAI;AACxE,QAAI,CAAC,KAAM;AACX,UAAM,aAAa,OAAO,KAAK,KAAK,eAAe,QAAQ;AAC3D,UAAM,cAAc,OAAO,KAAK,OAAO,eAAe,QAAQ;AAC9D,UAAM,QAAQ,UACV,aAAa,MAAM,YAAY,WAAW,IAC1C,UAAU,MAAM,YAAY,aAAa,EAAE,QAAQ,QAAQ,QAAQ,OAAO,CAAC;AAC/E,QAAI,CAAC,MAAO;AACZ,UAAM,QAAQ,cAAc,IAAI,SAAS,IAAI;AAC7C,QAAI,UAAU,OAAW;AACzB,cAAU,KAAK,IAAI;AAAA,MACjB,MAAM;AAAA,MACN,MAAM,SAAS;AAAA,MACf,QAAQ;AAAA,MACR,MAAM,aAAa,SAAS,MAAM,KAAK;AAAA,IACzC;AAAA,EACF;AACA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,WAAW,UAAU,OAAO,CAAC,SAA6D,KAAK,SAAS,UAAU;AAAA,EACpH;AACF;;;ACxEA,SAAS,cAAAC,aAAY,kBAAkB;AACvC,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,SAAS,6BAA6B;;;ACHtC,SAAS,cAAAC,mBAAkB;AAE3B,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAejB,SAAS,OAAO,OAAe;AAC7B,SAAOC,YAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AACxD;AAEA,SAASC,aAAY,UAAoB;AACvC,SAAO,OAAO,YAAY,SAAS,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,MAAM,KAAK,MAAM,CAAC,CAAC;AAClF;AAEA,eAAsB,cACpB,UACA,yBAAyB,oBAAI,IAAY,GACzC,UAUI,CAAC,GACL;AACA,QAAM,OAAO,SAAS;AACtB,QAAM,EAAE,WAAW,IAAI;AACvB,QAAM,qBAAqB;AAAA,IACzB;AAAA,IACA,QAAQ,QAAQ;AAAA,IAChB,kBAAkB,QAAQ;AAAA,IAC1B,kBAAkB,CAAC,GAAG,sBAAsB,EAAE,IAAI,CAAC,aAAa,eAAe,MAAM,UAAU,UAAU,CAAC;AAAA,IAC1G,mBAAmB,IAAI;AAAA,MACrB,OAAO,QAAQ,QAAQ,sBAAsB,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,UAAU,IAAI,MAAM;AAAA,QACzE,eAAe,MAAM,UAAU,UAAU;AAAA,QACzC,SAAS,OAAO,YAAY,QAAQ,IAAI;AAAA,MAC1C,CAAC;AAAA,IACH;AAAA,EACF;AACA,UAAQ,mBAAmB;AAC3B,QAAM,mCAAmC,kBAAkB;AAC3D,QAAM,UAAU,MAAM,eAAe,SAAS,SAAS;AAAA,IACrD,GAAG;AAAA,IACH,GAAI,QAAQ,YAAY,SAAY,EAAE,cAAc,yBAAyB,QAAQ,EAAE,IAAI,CAAC;AAAA,IAC5F;AAAA,EACF,CAAC;AACD,QAAM,OAAO,MAAM;AAAA,IACjB;AAAA,IACA;AAAA,MACE;AAAA,MACA,uBAAuB,MAAM,UAAU,SAAS,EAAE,WAAW,CAAC;AAAA,MAC9D;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACA,QAAM,2BAA2B,MAAM,MAAM,YAAY,OAAO;AAChE,QAAM,yBAAyB,MAAM,kBAAkB;AACvD,SAAO,mBAAmB,UAAU,SAAS,sBAAsB;AACrE;AAEO,SAAS,uBACd,MACA,UACA,SACA,UAAmC,CAAC,GACjB;AACnB,QAAM,YAAY,oBAAI,IAAY;AAClC,QAAM,cAAc,oBAAI,IAAY;AACpC,QAAM,SAAqD,CAAC;AAC5D,QAAM,UAAoB,CAAC;AAE3B,aAAW,QAAQ,SAAS,OAAO;AACjC,UAAM,aAAa,QAAQ,KAAK,IAAI;AACpC,QAAI,CAAC,mBAAmB,KAAK,IAAI,GAAG;AAClC,YAAM,IAAI,MAAM,4BAA4B,KAAK,IAAI,EAAE;AAAA,IACzD;AACA,QAAI,cAAc,UAAU,KAAK,CAAC,kBAAkB,UAAU,GAAG;AAC/D,YAAM,IAAI,MAAM,oCAAoC,KAAK,IAAI,EAAE;AAAA,IACjE;AACA,QAAI,UAAU,IAAI,UAAU,EAAG,OAAM,IAAI,MAAM,+BAA+B,UAAU,EAAE;AAC1F,cAAU,IAAI,UAAU;AACxB,gBAAY,IAAI,UAAU;AAE1B,UAAM,SAAS,eAAe,MAAM,YAAY,QAAQ,UAAU;AAClE,UAAM,UAAU,mBAAmB,KAAK,eAAe,UAAU;AACjE,QAAI,OAAO,OAAO,MAAM,KAAK,OAAQ,OAAM,IAAI,MAAM,uCAAuC,UAAU,EAAE;AACxG,WAAO,KAAK,EAAE,QAAQ,QAAQ,CAAC;AAAA,EACjC;AAEA,QAAM,cAAc,oBAAI,IAAY;AACpC,aAAW,QAAQ,QAAQ,OAAO;AAChC,UAAM,aAAa,QAAQ,KAAK,IAAI;AACpC,QAAI,CAAC,YAAY,IAAI,UAAU,GAAG;AAChC,kBAAY,IAAI,eAAe,MAAM,YAAY,QAAQ,UAAU,CAAC;AAAA,IACtE;AACA,eAAW,cAAc,YAAY,UAAU,GAAG;AAChD,UAAI,YAAY,IAAI,UAAU,GAAG;AAC/B,oBAAY,IAAI,eAAe,MAAM,YAAY,QAAQ,UAAU,CAAC;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AACA,UAAQ,KAAK,GAAG,WAAW;AAE3B,SAAO,EAAE,QAAQ,QAAQ;AAC3B;AAEO,SAAS,yBACd,MACA,MACA,wBACA,YACmB;AACnB,MAAI,uBAAuB,SAAS,EAAG,QAAO;AAC9C,QAAM,mBAAmB,IAAI;AAAA,IAC3B,CAAC,GAAG,sBAAsB,EAAE,IAAI,CAAC,iBAAiB,eAAe,MAAM,cAAc,UAAU,CAAC;AAAA,EAClG;AACA,SAAO;AAAA,IACL,QAAQ,KAAK,OAAO,OAAO,CAAC,SAAS,CAAC,iBAAiB,IAAI,KAAK,MAAM,CAAC;AAAA,IACvE,SAAS,KAAK,QAAQ,OAAO,CAAC,WAAW,CAAC,iBAAiB,IAAI,MAAM,CAAC;AAAA,EACxE;AACF;AAEA,eAAsB,8BACpB,MACA,MACA,UAC4B;AAC5B,QAAM,gBAAgB,oBAAI,IAAoB;AAC9C,aAAW,QAAQ,SAAS,OAAO;AACjC,UAAM,aAAa,QAAQ,KAAK,IAAI;AACpC,QAAI,CAAC,WAAW,SAAS,GAAG,KAAK,mBAAmB,KAAK,IAAI,GAAG;AAC9D,oBAAc,IAAI,WAAW,YAAY,GAAG,UAAU;AAAA,IACxD;AAAA,EACF;AACA,MAAI,cAAc,SAAS,EAAG,QAAO;AAErC,MAAI;AACJ,MAAI;AACF,cAAU,MAAMC,IAAG,QAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;AAAA,EAC1D,SAAS,OAAO;AACd,QAAK,MAAgC,SAAS,SAAU,QAAO;AAC/D,UAAM;AAAA,EACR;AAEA,QAAM,UAAU,IAAI,IAAI,KAAK,OAAO;AACpC,aAAW,SAAS,SAAS;AAC3B,UAAM,gBAAgB,cAAc,IAAI,MAAM,KAAK,YAAY,CAAC;AAChE,QAAI,iBAAiB,MAAM,SAAS,kBAAkB,MAAM,OAAO,KAAK,MAAM,eAAe,IAAI;AAC/F,cAAQ,IAAI,SAAS,MAAM,MAAM,IAAI,CAAC;AAAA,IACxC;AAAA,EACF;AACA,SAAO,EAAE,GAAG,MAAM,SAAS,CAAC,GAAG,OAAO,EAAE;AAC1C;AAEO,SAAS,mBAAmB,UAAoB,SAAmB,wBAAqC;AAC7G,QAAM,SAASD,aAAY,QAAQ;AACnC,MAAI,uBAAuB,SAAS,EAAG,QAAO;AAC9C,QAAM,gBAAgBA,aAAY,OAAO;AACzC,aAAW,gBAAgB,wBAAwB;AACjD,UAAM,aAAa,QAAQ,YAAY;AACvC,QAAI,cAAc,UAAU,GAAG;AAC7B,aAAO,UAAU,IAAI,cAAc,UAAU;AAAA,IAC/C,OAAO;AACL,aAAO,OAAO,UAAU;AAAA,IAC1B;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,cAAsB;AAChD,MAAI,aAAa,SAAS,IAAI,EAAG,QAAO;AACxC,QAAM,aAAa,QAAQ,YAAY;AACvC,SACE,QAAQ,UAAU,KAClB,eAAe,OACf,eAAe,QACf,CAAC,WAAW,WAAW,KAAK,KAC5B,CAACE,MAAK,MAAM,WAAW,UAAU,KACjCA,MAAK,MAAM,UAAU,UAAU,MAAM,cACrC,CAAC,aAAa,UAAU;AAE5B;AAEA,SAAS,mBAAmB,OAAe,UAAkB;AAC3D,MAAI,CAAC,yBAAyB,KAAK,KAAK,KAAK,MAAM,SAAS,MAAM,GAAG;AACnE,UAAM,IAAI,MAAM,4CAA4C,QAAQ,EAAE;AAAA,EACxE;AACA,SAAO,OAAO,KAAK,OAAO,QAAQ;AACpC;AAIA,eAAsB,2BACpB,MACA,MACA,YACA,UAA0B,CAAC,GAC3B;AACA,wBAAsB,OAAO;AAC7B,QAAM,cAAc,IAAI,IAAI,KAAK,OAAO;AACxC,aAAW,UAAU,KAAK,SAAS;AACjC,UAAM,uBAAuB,cAAc,MAAM,QAAQ,UAAU,GAAG,QAAQ,OAAO;AACrF,0BAAsB,OAAO;AAAA,EAC/B;AACA,aAAW,QAAQ,KAAK,QAAQ;AAC9B,UAAM,qBAAqB,cAAc,MAAM,KAAK,QAAQ,UAAU,GAAG,KAAK,QAAQ,aAAa,OAAO;AAC1G,0BAAsB,OAAO;AAAA,EAC/B;AACF;AAEA,SAAS,sBAAsB,SAAyB;AACtD,UAAQ,mBAAmB;AAC3B,UAAQ,QAAQ,eAAe;AACjC;AAEA,eAAe,YAAY,QAAgB,SAAyB;AAClE,wBAAsB,OAAO;AAC7B,MAAI;AACJ,MAAI;AACF,WAAO,MAAMD,IAAG,MAAM,MAAM;AAAA,EAC9B,SAAS,OAAO;AACd,0BAAsB,OAAO;AAC7B,QAAK,MAAgC,SAAS,SAAU,QAAO;AAC/D,UAAM;AAAA,EACR;AACA,wBAAsB,OAAO;AAC7B,SAAO;AACT;AAEA,SAAS,cAAc,MAAc,QAAgB,YAAqB;AACxE,QAAM,cAAc,aAAa,mBAAmB,MAAM,UAAU,IAAI;AACxE,MAAI,eAAe,aAAa,aAAa,MAAM,EAAG,QAAO;AAC7D,SAAO;AACT;AAEA,eAAe,qBAAqB,MAAc,QAAgB,aAA0B,SAAyB;AACnH,QAAM,uBAAuB,MAAM,oBAAoB,MAAMC,MAAK,QAAQ,MAAM,GAAG,aAAa,OAAO;AACvG,wBAAsB,OAAO;AAC7B,MAAI,qBAAsB;AAC1B,QAAM,OAAO,MAAM,YAAY,QAAQ,OAAO;AAC9C,wBAAsB,OAAO;AAC7B,MAAI,MAAM,eAAe,EAAG,OAAM,IAAI,MAAM,wDAAwD,MAAM,EAAE;AAC5G,MAAI,MAAM,YAAY,KAAK,CAAC,YAAY,IAAI,MAAM,GAAG;AACnD,UAAM,IAAI,MAAM,0DAA0D,MAAM,EAAE;AAAA,EACpF;AACF;AAEA,eAAe,oBAAoB,MAAc,WAAmB,aAA0B,SAAyB;AACrH,wBAAsB,OAAO;AAC7B,mBAAiB,MAAM,SAAS;AAChC,QAAM,WAAWA,MAAK,QAAQ,IAAI;AAClC,QAAM,WAAWA,MAAK,SAAS,UAAUA,MAAK,QAAQ,SAAS,CAAC;AAChE,MAAI,UAAU;AACd,aAAW,QAAQ,SAAS,MAAMA,MAAK,GAAG,EAAE,OAAO,OAAO,GAAG;AAC3D,cAAUA,MAAK,KAAK,SAAS,IAAI;AACjC,UAAM,OAAO,MAAM,YAAY,SAAS,OAAO;AAC/C,0BAAsB,OAAO;AAC7B,QAAI,MAAM;AACR,UAAI,KAAK,eAAe,EAAG,OAAM,IAAI,MAAM,qDAAqD,OAAO,EAAE;AACzG,UAAI,CAAC,KAAK,YAAY,GAAG;AACvB,YAAI,YAAY,IAAI,OAAO,EAAG,QAAO;AACrC,cAAM,IAAI,MAAM,4CAA4C,OAAO,EAAE;AAAA,MACvE;AAAA,IACF,OAAO;AACL,YAAMD,IAAG,MAAM,OAAO;AACtB,4BAAsB,OAAO;AAC7B,YAAM,cAAcC,MAAK,QAAQ,OAAO,CAAC;AACzC,4BAAsB,OAAO;AAAA,IAC/B;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,uBAAuB,MAAc,QAAgB,SAAyB;AAC3F,wBAAsB,OAAO;AAC7B,mBAAiB,MAAM,MAAM;AAC7B,QAAM,WAAWA,MAAK,QAAQ,IAAI;AAClC,QAAM,WAAWA,MAAK,SAAS,UAAUA,MAAK,QAAQ,MAAM,CAAC;AAC7D,MAAI,UAAU;AACd,QAAM,QAAQ,SAAS,MAAMA,MAAK,GAAG,EAAE,OAAO,OAAO;AACrD,aAAW,QAAQ,MAAM,MAAM,GAAG,EAAE,GAAG;AACrC,cAAUA,MAAK,KAAK,SAAS,IAAI;AACjC,UAAM,OAAO,MAAM,YAAY,SAAS,OAAO;AAC/C,0BAAsB,OAAO;AAC7B,QAAI,CAAC,KAAM;AACX,QAAI,KAAK,eAAe,EAAG,OAAM,IAAI,MAAM,qDAAqD,OAAO,EAAE;AACzG,QAAI,CAAC,KAAK,YAAY,EAAG,OAAM,IAAI,MAAM,4CAA4C,OAAO,EAAE;AAAA,EAChG;AACF;;;ADlSA,eAAsB,uBACpB,QACA,OACA,SACA,iBACA;AACA,QAAM,OAAO,SAAS;AACtB,QAAM,eAAuC,OAAO,OAAO,uBAAO,OAAO,IAAI,GAAG,YAAY,MAAM,CAAC;AACnG,QAAM,cAAsC,OAAO,OAAO,uBAAO,OAAO,IAAI,GAAG,YAAY,KAAK,CAAC;AACjG,QAAM,QAAQ,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,YAAY,GAAG,GAAG,OAAO,KAAK,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK;AAC7F,QAAM,UAAU,IAAI,IAAI,MAAM,OAAO,CAAC,SAAS,aAAa,IAAI,MAAM,YAAY,IAAI,CAAC,CAAC;AACxF,QAAM,6BAA6B,MAAM,SAAS,OAAO;AACzD,QAAM,4BAA4B,MAAM,OAAO,SAAS,SAAS,iBAAiB,IAAI,IAAI,OAAO,KAAK,WAAW,CAAC,CAAC;AACnH,QAAM,UAAU;AAAA,IACd,IAAI,IAAI,MAAM,OAAO,CAAC,SAAS,QAAQ,IAAI,IAAI,KAAK,CAAC,YAAY,IAAI,CAAC,CAAC;AAAA,IACvE;AAAA,EACF;AACA,QAAM,iBAAiB,IAAI,IAAI,CAAC,GAAG,OAAO,EAAE,IAAI,CAAC,SAAS,eAAe,MAAM,MAAM,QAAQ,UAAU,CAAC,CAAC;AACzG,aAAW,YAAY,OAAO;AAC5B,QAAI,QAAQ,IAAI,QAAQ,EAAG,OAAM,uBAAuB,MAAM,UAAU,SAAS,gBAAgB,YAAY;AAAA,EAC/G;AACF;AAEA,SAAS,iBAAiB,SAAsB,aAA+C;AAC7F,aAAW,YAAY,CAAC,GAAG,OAAO,GAAG;AACnC,QAAI,SAASC,MAAK,MAAM,QAAQ,QAAQ;AACxC,WAAO,WAAW,KAAK;AACrB,UAAI,YAAY,MAAM,GAAG;AACvB,iBACM,YAAYA,MAAK,MAAM,QAAQ,QAAQ,GAC3C,cAAc,QACd,YAAYA,MAAK,MAAM,QAAQ,SAAS;AAExC,kBAAQ,IAAI,SAAS;AACvB,gBAAQ,IAAI,MAAM;AAClB;AAAA,MACF;AACA,eAASA,MAAK,MAAM,QAAQ,MAAM;AAAA,IACpC;AAAA,EACF;AACA,SAAO;AACT;AAGA,eAAe,6BAA6B,MAAc,SAA2B,SAA0B;AAC7G,QAAM,WAAW,IAAI;AAAA,IACnB,CAAC,GAAG,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,SAAS,SAAS,GAAG,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,SAAS,YAAY,GAAG,QAAQ,CAAC;AAAA,EACjH;AACA,MAAI,SAAS,SAAS,EAAG;AACzB,UAAQ,QAAQ,eAAe;AAC/B,UAAQ,mBAAmB;AAC3B,MAAI;AACJ,MAAI;AACF,YAAQ,MAAMC,IAAG,QAAQ,IAAI;AAAA,EAC/B,SAAS,OAAO;AACd,YAAQ,QAAQ,eAAe;AAC/B,YAAQ,mBAAmB;AAC3B,QAAK,MAAgC,SAAS,SAAU,OAAM;AAC9D;AAAA,EACF;AACA,UAAQ,QAAQ,eAAe;AAC/B,UAAQ,mBAAmB;AAC3B,aAAW,QAAQ,OAAO;AACxB,UAAM,YAAY,SAAS,IAAI,KAAK,YAAY,CAAC;AACjD,QAAI,cAAc,UAAa,SAAS;AACtC,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,EACJ;AACF;AAGA,eAAe,4BACb,MACA,OACA,SACA,SACA,iBACA,aAAkC,IAAI,IAAI,KAAK,GAC/C;AACA,QAAM,eAAe,kBACjB,kBAAkB,MAAM,uBAAuBD,MAAK,QAAQ,eAAe,GAAG,OAAO,CAAC,IACtF;AACJ,UAAQ,QAAQ,eAAe;AAC/B,UAAQ,mBAAmB;AAC3B,QAAM,OAAO,oBAAI,IAAoB;AACrC,aAAW,YAAY,OAAO;AAC5B,YAAQ,QAAQ,eAAe;AAC/B,UAAM,SAAS,eAAe,MAAM,UAAU,QAAQ,UAAU;AAChE,UAAM,MAAM,kBAAkB,MAAM,uBAAuB,QAAQ,OAAO,CAAC;AAC3E,YAAQ,QAAQ,eAAe;AAC/B,YAAQ,mBAAmB;AAC3B,UAAM,WAAW,KAAK,IAAI,GAAG;AAC7B,QACE,aACC,kBAAkB,QAAQ,MAAM,kBAAkB,QAAQ,KACxD,WAAW,IAAI,QAAQ,KAAK,WAAW,IAAI,QAAQ;AAEtD,YAAM,IAAI,MAAM,mFAAmF;AACrG,QAAI,QAAQ,gBAAgB,QAAQ,IAAI,QAAQ;AAC9C,YAAM,IAAI,MAAM,oEAAoE;AACtF,SAAK,IAAI,KAAK,QAAQ;AAAA,EACxB;AACF;AAEA,eAAe,mBAAmB,WAAmB,UAAkB,cAAgD;AACrH,aAAW,QAAQ,MAAMC,IAAG,QAAQ,SAAS,GAAG;AAC9C,UAAM,QAAQD,MAAK,KAAK,WAAW,IAAI;AACvC,UAAM,gBAAgB,GAAG,QAAQ,IAAI,IAAI;AACzC,UAAM,OAAO,MAAMC,IAAG,MAAM,KAAK;AACjC,QAAI,KAAK,YAAY,GAAG;AACtB,YAAM,mBAAmB,OAAO,eAAe,YAAY;AAAA,IAC7D,WACE,KAAK,OAAO,KACZ,KAAK,UAAU,KACf,aAAa,aAAa,MACxBC,YAAW,QAAQ,EAChB,OAAO,MAAMD,IAAG,SAAS,KAAK,CAAC,EAC/B,OAAO,KAAK,GACjB;AACA;AAAA,IACF,OAAO;AACL,YAAM,IAAI,MAAM,4EAA4E;AAAA,IAC9F;AAAA,EACF;AACF;AAEA,SAAS,wBAAwB,QAAgB,OAA4B;AAC3E,WAAS,SAASD,MAAK,QAAQ,MAAM,GAAG,WAAWA,MAAK,QAAQ,MAAM,GAAG,SAASA,MAAK,QAAQ,MAAM;AACnG,QAAI,MAAM,IAAI,MAAM,EAAG,QAAO;AAChC,SAAO;AACT;AAEA,eAAe,uBAAuB,QAAgB,SAA0B;AAE9E,MAAI,WAAW;AACf,SAAO,MAAM;AACX,YAAQ,QAAQ,eAAe;AAC/B,QAAI;AACF,YAAM,WAAW,MAAMC,IAAG,SAAS,QAAQ;AAC3C,aAAOD,MAAK,QAAQ,UAAUA,MAAK,SAAS,UAAU,MAAM,CAAC;AAAA,IAC/D,SAAS,OAAO;AACd,YAAM,OAAQ,MAAgC;AAC9C,UAAI,SAAS,YAAY,SAAS,UAAW,OAAM;AACnD,YAAM,SAASA,MAAK,QAAQ,QAAQ;AACpC,UAAI,WAAW,SAAU,QAAO;AAChC,iBAAW;AAAA,IACb;AAAA,EACF;AACF;AAEA,eAAe,uBACb,MACA,UACA,SACA,iBAAsC,oBAAI,IAAI,GAC9C,cACA;AACA,QAAM,SAAS,eAAe,MAAM,UAAU,QAAQ,UAAU;AAChE,QAAM,WACJ,SAAS,WAAW,WAAW,KAAK,QAAQ,aACxCA,MAAK,QAAQ,mBAAmB,MAAM,QAAQ,UAAU,CAAC,IACzDA,MAAK,QAAQ,IAAI;AACvB,WACM,SAASA,MAAK,QAAQ,MAAM,GAChC,kBAAkB,MAAM,MAAM,kBAAkB,QAAQ,GACxD,SAASA,MAAK,QAAQ,MAAM,GAC5B;AACA,YAAQ,QAAQ,eAAe;AAC/B,QAAIA,MAAK,QAAQ,MAAM,MAAM,OAAQ,OAAM,IAAI,MAAM,wBAAwB;AAC7E,QAAI;AACF,YAAM,OAAO,MAAMC,IAAG,MAAM,MAAM;AAClC,WACG,CAAC,KAAK,YAAY,KAAK,KAAK,eAAe,MAC5C,EAAE,KAAK,OAAO,KAAK,KAAK,UAAU,KAAK,eAAe,IAAI,MAAM;AAEhE,cAAM,IAAI,MAAM,4EAA4E;AAAA,IAChG,SAAS,OAAO;AACd,YAAM,OAAQ,MAAgC;AAC9C,UAAI,SAAS,SAAU,OAAM;AAAA,IAC/B;AAAA,EACF;AACA,UAAQ,QAAQ,eAAe;AAC/B,MAAI;AACF,UAAM,OAAO,MAAMA,IAAG,MAAM,MAAM;AAClC,QAAK,CAAC,KAAK,OAAO,KAAK,CAAC,eAAe,IAAI,MAAM,KAAO,KAAK,OAAO,KAAK,KAAK,QAAQ;AACpF,YAAM,IAAI,MAAM,6FAA6F;AAC/G,QAAI,KAAK,YAAY,KAAK,aAAc,OAAM,mBAAmB,QAAQ,UAAU,YAAY;AAAA,EACjG,SAAS,OAAO;AACd,UAAM,OAAQ,MAAgC;AAC9C,QAAI,SAAS,YAAY,EAAE,SAAS,aAAa,eAAe,OAAO,GAAI,OAAM;AAAA,EACnF;AACF;AAGA,eAAsB,oBACpB,QACA,OACA,gBACA,SACA,UACA,iBACA;AACA,QAAM,OAAO,SAAS;AACtB,QAAM,eAAuC,OAAO,OAAO,uBAAO,OAAO,IAAI,GAAG,YAAY,MAAM,CAAC;AACnG,QAAM,cAAsC,OAAO,OAAO,uBAAO,OAAO,IAAI,GAAG,YAAY,KAAK,CAAC;AACjG,QAAM,QAAQ,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,YAAY,GAAG,GAAG,OAAO,KAAK,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK;AAC7F,QAAM,eAAe;AAAA,IACnB,IAAI,IAAI,MAAM,OAAO,CAAC,SAAS,aAAa,IAAI,KAAK,CAAC,YAAY,IAAI,CAAC,CAAC;AAAA,IACxE;AAAA,EACF;AACA,QAAM,0BAA0B,CAAC,GAAG,YAAY,EAAE,OAAO,CAAC,SAAS,CAAC,aAAa,IAAI,KAAK,CAAC,YAAY,IAAI,CAAC;AAC5G,QAAM,UAAU;AAAA,IACd,GAAG,oBAAI,IAAI,CAAC,GAAG,MAAM,OAAO,CAAC,SAAS,aAAa,IAAI,MAAM,YAAY,IAAI,CAAC,GAAG,GAAG,uBAAuB,CAAC;AAAA,EAC9G,EAAE,KAAK;AACP,QAAM,gBAAgB,IAAI,IAAI,CAAC,GAAG,cAAc,EAAE,IAAI,iBAAiB,CAAC;AACxE,MAAI,QAAQ,KAAK,CAAC,SAAS,cAAc,IAAI,kBAAkB,IAAI,CAAC,CAAC,GAAG;AACtE,UAAM,IAAI,MAAM,oEAAoE;AAAA,EACtF;AAEA,QAAM,UAAU,QAAQ,IAAI,CAAC,SAAS,eAAe,MAAM,MAAM,QAAQ,UAAU,CAAC;AACpF,QAAM,mBAAmB,IAAI,IAAI,QAAQ,IAAI,CAAC,QAAQ,UAAU,CAAC,QAAQ,QAAQ,KAAK,CAAC,CAAC,CAAC;AACzF,QAAM,YAAY,IAAI,IAAI,OAAO;AACjC,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,IAAI,IAAI,OAAO;AAAA,IACf;AAAA,IACA;AAAA,IACA,IAAI,IAAI,OAAO,KAAK,WAAW,CAAC;AAAA,EAClC;AAGA,QAAM,iBAAiB,oBAAI,IAAsB;AACjD,QAAM,eAAyB,CAAC;AAChC,QAAM,kBAA4B,CAAC;AACnC,aAAW,UAAU,SAAS;AAC5B,QAAI,MAAMD,MAAK,QAAQ,MAAM;AAC7B,QAAI;AACF,YAAM,MAAMC,IAAG,SAAS,MAAM;AAAA,IAChC,SAAS,OAAO;AACd,YAAM,OAAQ,MAAgC;AAC9C,UAAI,SAAS,YAAY,SAAS,UAAW,OAAM;AAAA,IACrD;AACA,YAAQ,QAAQ,eAAe;AAC/B,YAAQ,mBAAmB;AAC3B,UAAM,UAAU,eAAe,IAAI,GAAG,KAAK,CAAC;AAC5C,YAAQ,KAAK,MAAM;AACnB,mBAAe,IAAI,KAAK,OAAO;AAAA,EACjC;AACA,aAAW,CAAC,KAAK,OAAO,KAAK,gBAAgB;AAC3C,iBAAa,KAAK,GAAG;AACrB,QAAI,QAAQ,SAAS,EAAG,iBAAgB,KAAK,GAAG,QAAQ,OAAO,CAAC,WAAWD,MAAK,QAAQ,MAAM,MAAM,GAAG,CAAC;AAAA,EAC1G;AACA,iBAAe,QAAQ,OAA8B;AACnD,UAAM,SAAS,aAAa,KAAK;AACjC,QAAI,OAAQ,QAAO,sBAAsB,QAAQ,MAAM,QAAQ,QAAQ,CAAC,CAAC;AACzE,UAAM,SAAS;AACf,UAAM,6BAA6B,MAAM,SAAS,OAAO;AACzD,UAAM,SAAS;AACf,UAAM,UAAU,MAAM,eAAe,OAAO,SAAS,OAAO;AAC5D,UAAM,gBAAwC,OAAO,OAAO,uBAAO,OAAO,IAAI,GAAG,YAAY,OAAO,CAAC;AACrG,UAAM,gBAAgB,IAAI;AAAA,MACxB,MACG;AAAA,QACC,CAAC,aACE,aAAa,QAAQ,KAAK,CAAC,YAAY,QAAQ,KAC/C,YAAY,QAAQ,KAAK,cAAc,QAAQ,MAAM,YAAY,QAAQ;AAAA,MAC9E,EACC,IAAI,CAAC,aAAa,eAAe,MAAM,UAAU,QAAQ,UAAU,CAAC;AAAA,IACzE;AACA,eAAW,QAAQ,SAAS;AAC1B,UAAI,cAAc,IAAI,MAAM,aAAa,IAAI,KAAK,cAAc,IAAI,MAAM,YAAY,IAAI,GAAG;AAC3F,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,YAAMG,UAAS,eAAe,MAAM,MAAM,QAAQ,UAAU;AAC5D,UAAI;AACF,cAAM,OAAO,MAAMF,IAAG,MAAME,OAAM;AAClC,YAAK,CAAC,KAAK,OAAO,KAAK,CAAC,KAAK,YAAY,KAAO,KAAK,OAAO,KAAK,KAAK,QAAQ;AAC5E,gBAAM,IAAI,MAAM,kEAAkE;AAAA,MACtF,SAAS,OAAO;AACd,cAAM,OAAQ,MAAgC;AAC9C,YAAI,SAAS,YAAY,EAAE,SAAS,aAAa,wBAAwBA,SAAQ,aAAa,GAAI,OAAM;AAAA,MAC1G;AAAA,IACF;AACA,UAAM,OAAO,uBAAuB,MAAM,OAAO,SAAS,OAAO;AACjE,SAAK,SAAS,KAAK,OAAO,OAAO,CAAC,SAAS,UAAU,IAAI,KAAK,MAAM,CAAC;AACrE,SAAK,UAAU,KAAK,QAAQ,OAAO,CAACA,YAAW,UAAU,IAAIA,OAAM,CAAC;AACpE,UAAM,2BAA2B,MAAM,MAAM,QAAQ,YAAY,OAAO;AACxE,UAAM,iBAAiB,IAAI,IAAI,KAAK,OAAO;AAC3C,eAAW,YAAY,yBAAyB;AAC9C,eAAS,SAASH,MAAK,MAAM,QAAQ,QAAQ,GAAG,WAAW,KAAK,SAASA,MAAK,MAAM,QAAQ,MAAM,GAAG;AACnG,YAAI,YAAY,MAAM,KAAK,eAAe,IAAI,eAAe,MAAM,QAAQ,QAAQ,UAAU,CAAC,GAAG;AAC/F,eAAK,QAAQ,KAAK,eAAe,MAAM,UAAU,QAAQ,UAAU,CAAC;AACpE;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,SAAK,QAAQ;AAAA,MACX,CAAC,MAAM,UAAU,MAAM,MAAMA,MAAK,GAAG,EAAE,SAAS,KAAK,MAAMA,MAAK,GAAG,EAAE,UAAU,KAAK,cAAc,KAAK;AAAA,IACzG;AACA,UAAM,UAAU;AAAA,MACd,IAAI,IAAI,MAAM,OAAO,CAAC,aAAa,eAAe,IAAI,eAAe,MAAM,UAAU,QAAQ,UAAU,CAAC,CAAC,CAAC;AAAA,MAC1G;AAAA,IACF;AACA,UAAM,iBAAiB,IAAI,IAAI,CAAC,GAAG,OAAO,EAAE,IAAI,CAAC,SAAS,eAAe,MAAM,MAAM,QAAQ,UAAU,CAAC,CAAC;AACzG,UAAM,6BAA6B,MAAM,SAAS,OAAO;AACzD,UAAM,SAAS;AACf,UAAM,mBAAmB,OAAOG,YAAmB;AACjD,YAAM,SAAS;AACf,YAAM,WAAW,iBAAiB,IAAIA,OAAM;AAC5C,UAAI,CAAC,SAAU,OAAM,IAAI,MAAM,uBAAuB;AACtD,YAAM,uBAAuB,MAAM,UAAU,SAAS,gBAAgB,aAAa;AACnF,YAAM,SAAS;AACf,UAAI;AACJ,UAAI;AACF,cAAM,OAAO,MAAMF,IAAG,MAAME,OAAM;AAClC,YAAI,KAAK,YAAY,KAAK,QAAQ,IAAI,QAAQ,GAAG;AAC/C,eAAK,MAAMF,IAAG,QAAQE,OAAM,GAAG;AAC7B,kBAAM,IAAI,MAAM,yEAAyE;AAAA,QAC7F,OAAO;AACL,cAAI,CAAC,KAAK,OAAO,KAAK,KAAK,QAAQ;AACjC,kBAAM,IAAI,MAAM,kEAAkE;AACpF,iBAAOD,YAAW,QAAQ,EACvB,OAAO,MAAMD,IAAG,SAASE,OAAM,CAAC,EAChC,OAAO,KAAK;AAAA,QACjB;AAAA,MACF,SAAS,OAAO;AACd,YAAK,MAAgC,SAAS,SAAU,OAAM;AAAA,MAChE;AACA,cAAQ,QAAQ,eAAe;AAC/B,cAAQ,mBAAmB;AAC3B,UAAI,SAAS,aAAa,QAAQ,KAAK,SAAS,YAAY,QAAQ;AAClE,cAAM,IAAI,MAAM,uFAAuF;AAAA,IAC3G;AACA,eAAWA,WAAU,KAAK,SAAS;AACjC,YAAM,iBAAiBA,OAAM;AAC7B,UAAI;AACF,cAAM,OAAO,MAAMF,IAAG,MAAME,OAAM;AAClC,cAAM,SAAS;AACf,YAAI,KAAK,YAAY;AACnB,gBAAMF,IAAG,MAAME,OAAM;AAAA,YAClB,OAAMF,IAAG,GAAGE,SAAQ,EAAE,OAAO,KAAK,CAAC;AAAA,MAC1C,SAAS,OAAO;AACd,YAAK,MAAgC,SAAS,SAAU,OAAM;AAAA,MAChE;AACA,YAAM,cAAcH,MAAK,QAAQG,OAAM,CAAC;AAAA,IAC1C;AACA,UAAM,4BAA4B,YAAY;AAC5C,YAAM,SAAS;AACf,iBAAWA,WAAU,iBAAiB;AACpC,YAAI;AACF,gBAAMF,IAAG,MAAME,OAAM;AAAA,QACvB,SAAS,OAAO;AACd,cAAK,MAAgC,SAAS,SAAU,OAAM;AAC9D;AAAA,QACF;AACA,cAAM,IAAI,MAAM,6FAA6F;AAAA,MAC/G;AACA,YAAM,SAAS;AAAA,IACjB;AACA,mBAAe,oBAAoBC,QAA8B;AAC/D,YAAMD,UAAS,gBAAgBC,MAAK;AACpC,UAAID,QAAQ,QAAO,sBAAsBA,SAAQ,MAAM,oBAAoBC,SAAQ,CAAC,CAAC;AAGrF,YAAM,0BAA0B;AAChC,YAAM,aAAa;AAAA,IACrB;AACA,UAAM,0BAA0B;AAChC,UAAM,oBAAoB,CAAC;AAC3B,mBAAe,eAAe;AAC5B,iBAAW,QAAQ,KAAK,QAAQ;AAC9B,cAAM,SAAS;AACf,cAAM,WAAW,iBAAiB,IAAI,KAAK,MAAM;AACjD,YAAI,CAAC,SAAU,OAAM,IAAI,MAAM,6BAA6B;AAC5D,cAAM,uBAAuB,MAAM,UAAU,SAAS,oBAAI,IAAI,CAAC;AAC/D,cAAMH,IAAG,MAAMD,MAAK,QAAQ,KAAK,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;AAC7D,cAAM,YAAYA,MAAK,KAAKA,MAAK,QAAQ,KAAK,MAAM,GAAG,iBAAiB,WAAW,CAAC,QAAQ;AAC5F,YAAI,OAAO;AACX,YAAI;AACF,kBAAQ,MAAMC,IAAG,KAAK,KAAK,MAAM,GAAG,OAAO;AAAA,QAC7C,SAAS,OAAO;AACd,cAAK,MAAgC,SAAS,SAAU,OAAM;AAAA,QAChE;AACA,YAAI;AACF,gBAAM,SAAS,MAAMA,IAAG,KAAK,WAAW,MAAM,IAAI;AAClD,cAAI;AACF,kBAAM,OAAO,UAAU,KAAK,OAAO;AACnC,kBAAM,OAAO,KAAK;AAAA,UACpB,UAAE;AACA,kBAAM,OAAO,MAAM;AAAA,UACrB;AACA,gBAAM,iBAAiB,KAAK,MAAM;AAClC,gBAAMA,IAAG,OAAO,WAAW,KAAK,MAAM;AACtC,gBAAM,cAAcD,MAAK,QAAQ,KAAK,MAAM,CAAC;AAAA,QAC/C,UAAE;AACA,gBAAMC,IAAG,GAAG,WAAW,EAAE,OAAO,KAAK,CAAC;AAAA,QACxC;AAAA,MACF;AACA,YAAM;AAAA,QACJ;AAAA,QACA,CAAC,MAAM,GAAI,QAAQ,aAAa,CAAC,mBAAmB,MAAM,QAAQ,UAAU,CAAC,IAAI,CAAC,CAAE;AAAA,QACpF;AAAA,MACF;AACA,YAAM,SAAS;AAAA,IACjB;AAAA,EACF;AACA,QAAM,QAAQ,CAAC;AACjB;;;AExaA,IAAM,aAAa;AACnB,IAAM,oBAAoB;AAGnB,SAAS,mBAAmB,OAAgB,SAAqC;AACtF,QAAM,WAAqB,CAAC;AAC5B,QAAM,OAAO,oBAAI,IAAW;AAC5B,MAAI,UAAU;AACd,SAAO,mBAAmB,SAAS,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,OAAO,YAAY;AAC/E,SAAK,IAAI,OAAO;AAChB,UAAM,OAAQ,QAAkC;AAChD,UAAM,SAAU,QAAyC;AACzD,UAAM,WAAW;AAAA,MACf,OAAO,SAAS,YAAY,0BAA0B,KAAK,IAAI,IAAI,OAAO;AAAA,MAC1E,OAAO,WAAW,YAAY,OAAO,UAAU,MAAM,KAAK,UAAU,OAAO,UAAU,MACjF,QAAQ,MAAM,KACd;AAAA,IACN,EAAE,OAAO,OAAO;AAChB,UAAM,UAAU,GAAG,QAAQ,OAAO,GAAG,SAAS,SAAS,KAAK,SAAS,KAAK,IAAI,CAAC,MAAM,EAAE;AACvF,QAAI,WAAW,CAAC,SAAS,SAAS,OAAO,EAAG,UAAS,KAAK,OAAO;AACjE,cAAU,QAAQ;AAAA,EACpB;AACA,MAAI,SAAS,SAAS,KAAK,UAAK,KAAK;AAErC,aAAW,UAAU,mBAAmB,OAAO,EAAG,UAAS,OAAO,WAAW,QAAQ,YAAY;AACjG,WAAS,OAAO,QAAQ,oCAAoC,eAAe;AAC3E,WAAS,iBAAiB,MAAM;AAChC,MAAI,OAAO,SAAS,kBAAmB,UAAS,GAAG,OAAO,MAAM,GAAG,iBAAiB,CAAC;AACrF,SAAO,IAAI;AAAA,IACT,qIAAqI,MAAM;AAAA,IAC3I,EAAE,OAAO,MAAM;AAAA,EACjB;AACF;AAEA,SAAS,mBAAmB,SAAwC;AAClE,QAAM,UAAoB,CAAC;AAC3B,MAAI;AACJ,UAAQ,QAAQ,MAAM;AAAA,IACpB,KAAK;AACH,cAAQ,KAAK,QAAQ,QAAQ,aAAa,QAAQ,QAAQ,iBAAiB,QAAQ,QAAQ,gBAAgB,EAAE;AAC7G,gBAAU,QAAQ,QAAQ;AAC1B;AAAA,IACF,KAAK;AACH,cAAQ;AAAA,QACN,QAAQ,QAAQ;AAAA,QAChB,QAAQ,QAAQ;AAAA,QAChB,OAAO,KAAK,GAAG,QAAQ,QAAQ,QAAQ,IAAI,QAAQ,QAAQ,QAAQ,EAAE,EAAE,SAAS,QAAQ;AAAA,MAC1F;AACA,gBAAU,QAAQ,QAAQ;AAC1B;AAAA,IACF,KAAK;AACH,gBAAU,QAAQ,QAAQ;AAC1B;AAAA,EACJ;AACA,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,OAAO;AAC3B,YAAQ,KAAK,IAAI,UAAU,IAAI,UAAU,GAAG,IAAI,aAAa,OAAO,CAAC;AACrE,eAAW,SAAS,CAAC,IAAI,UAAU,IAAI,QAAQ,EAAG,SAAQ,KAAK,mBAAmB,KAAK,CAAC;AAAA,EAC1F,QAAQ;AAAA,EAER;AACA,SAAO;AAAA,IACL,GAAG,IAAI;AAAA,MACL,QACG,OAAO,OAAO,EACd,QAAQ,CAAC,UAAU,CAAC,OAAO,mBAAmB,KAAK,GAAG,KAAK,UAAU,KAAK,EAAE,MAAM,GAAG,EAAE,CAAC,CAAC;AAAA,IAC9F;AAAA,EACF,EAAE,KAAK,CAAC,MAAM,UAAU,MAAM,SAAS,KAAK,MAAM;AACpD;;;AChEO,SAAS,mBACd,WACA,YACA,UACA;AACA,QAAM,cAAc,IAAI,IAAI,WAAW,IAAI,CAAC,SAAS,CAAC,KAAK,MAAM,IAAI,CAAC,CAAC;AACvE,SAAO,UAAU,QAAQ,CAAC,aAAa;AACrC,UAAM,OAAO,SAAS,IAAI,SAAS,IAAI,IACnC,YAAY,IAAI,SAAS,IAAI,IAC7B,SAAS,SAAS,aAChB,SAAS,OACT;AACN,WAAO,OAAO,CAAC,IAAI,IAAI,CAAC;AAAA,EAC1B,CAAC;AACH;AAMO,SAAS,cACd,QACA,MACA,UACA,UACW;AACX,QAAM,WAAW,IAAI,IAAI,SAAS,OAAO,QAAQ,CAAC,UAAU,MAAM,KAAK,CAAC;AACxE,QAAM,UAAU,YAAY,QAAQ;AACpC,QAAM,SAAS,OAAO,OAAO,uBAAO,OAAO,IAAI,GAA6B,SAAS,SAAS,cAAc;AAC5G,aAAW,OAAO,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,MAAM,GAAG,GAAG,OAAO,KAAK,OAAO,CAAC,CAAC,GAAG;AAC5E,QAAI,SAAS,IAAI,GAAG,EAAG;AACvB,UAAM,QAAQ,QAAQ,GAAG;AACzB,QAAI,UAAU,OAAW,QAAO,OAAO,GAAG;AAAA,QACrC,QAAO,GAAG,IAAI;AAAA,EACrB;AACA,SAAO;AAAA,IACL,GAAG,SAAS;AAAA,IACZ,SAAS;AAAA,IACT,SAAS,OAAO;AAAA,IAChB,gBAAgB;AAAA,IAChB,SAAS,CAAC,GAAG,OAAO,OAAO;AAAA,IAC3B,aAAa,OAAO;AAAA,IACpB,sBAAsB,KAAK;AAAA,IAC3B,sBAAsB,KAAK;AAAA,IAC3B,YAAY,SAAS;AAAA,EACvB;AACF;;;ACrDA,SAAS,cAAAI,mBAAkB;;;ACY3B,IAAM,iBAAiB;AAAA,EACrB,CAAC,mBAAmB,cAAc;AAAA,EAClC,CAAC,aAAa,cAAc;AAAA,EAC5B,CAAC,cAAc,WAAW;AAAA,EAC1B,CAAC,UAAU,qBAAqB;AAAA,EAChC,CAAC,mBAAmB,YAAY;AAClC;AAGO,SAAS,kBAAkB,UAAkB,OAAe,QAAqC;AACtG,MAAI;AACJ,MAAI;AACF,gBAAY,CAAC,UAAU,OAAO,MAAM,EAAE,IAAI,qBAAqB;AAAA,EACjE,QAAQ;AACN,WAAO,EAAE,MAAM,UAAU,QAAQ,sBAAsB,QAAQ,CAAC,EAAE;AAAA,EACpE;AACA,QAAM,CAAC,MAAM,MAAM,KAAK,IAAI;AAC5B,QAAM,WAAW,oBAAI,IAAwD;AAC7E,QAAM,SAAS,IAAI,IAAI,UAAU,QAAQ,CAAC,aAAa,CAAC,GAAG,SAAS,KAAK,QAAQ,KAAK,CAAC,CAAC,CAAC;AACzF,QAAM,QAAoB,eAAe,IAAI,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC;AAClE,QAAM,UAAU,IAAI,IAAI,MAAM,KAAK,CAAC;AACpC,QAAM,KAAK,GAAG,CAAC,GAAG,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,QAAQ,IAAI,KAAK,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AACxF,QAAM,YAAsB,CAAC;AAC7B,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,CAAC,OAAqB,WAClC,KAAK;AAAA,MAAM,CAAC,UACV,UAAU,MAAM,KAAK,QAAQ,IAAI,KAAK,GAAG,KAAK,OAAO,OAAO,KAAK,QAAQ,IAAI,KAAK,GAAG,KAAK,KAAK;AAAA,IACjG;AACF,UAAM,SAAS,MAAM,MAAM,KAAK,IAAI,OAAO,MAAM,MAAM,IAAI,IAAI,QAAQ,MAAM,OAAO,IAAI,IAAI,OAAO;AACnG,QAAI,CAAC,QAAQ;AACX,gBAAU,KAAK,GAAG,KAAK,OAAO,CAAC,UAAU,OAAO,IAAI,KAAK,CAAC,CAAC;AAC3D;AAAA,IACF;AACA,eAAW,SAAS,MAAM;AACxB,YAAM,SAAS,OAAO,KAAK,QAAQ,IAAI,KAAK;AAC5C,UAAI,OAAQ,UAAS,IAAI,OAAO,EAAE,UAAU,QAAQ,MAAM,OAAO,KAAK,CAAC;AAAA,IACzE;AAAA,EACF;AACA,MAAI,UAAU,OAAQ,QAAO,EAAE,MAAM,UAAU,QAAQ,kBAAkB,QAAQ,UAAU;AAC3F,MAAI;AACF,WAAO,EAAE,MAAM,UAAU,SAAS,sBAAsB,MAAM,QAAQ,EAAE;AAAA,EAC1E,QAAQ;AACN,WAAO,EAAE,MAAM,UAAU,QAAQ,sBAAsB,QAAQ,CAAC,EAAE;AAAA,EACpE;AACF;;;ADhDA,eAAsB,yBACpB,QACA,OACA,OACA,QACA,MACoD;AACpD,MAAI,KAAK,SAAS,UAAW,QAAO,EAAE,MAAM,QAAQ,CAAC,EAAE;AACvD,QAAM,SAAmB,CAAC;AAC1B,QAAM,YAAY,CAAC,GAAG,KAAK,SAAS;AACpC,WAAS,QAAQ,GAAG,QAAQ,UAAU,QAAQ,SAAS;AACrD,UAAM,WAAW,UAAU,KAAK;AAChC,QAAI,UAAU,SAAS,cAAc,SAAS,WAAW,kBAAkB,SAAS,SAAS;AAC3F;AACF,UAAM,OAAO,MAAM,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,SAAS,IAAI;AACnE,UAAM,QAAQ,OAAO,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,SAAS,IAAI;AACrE,QAAI,CAAC,QAAQ,CAAC,MAAO;AACrB,UAAM,WAAW,MAAM,kBAAkB,QAAQ,OAAO,SAAS,IAAI;AACrE,QAAI,CAAC,SAAU;AACf,UAAM,SAAS;AAAA,MACb;AAAA,MACA,OAAO,KAAK,KAAK,eAAe,QAAQ;AAAA,MACxC,OAAO,KAAK,MAAM,eAAe,QAAQ;AAAA,IAC3C;AACA,QAAI,OAAO,SAAS,UAAU;AAC5B,aAAO,KAAK,GAAG,OAAO,MAAM;AAC5B;AAAA,IACF;AACA,cAAU,KAAK,IAAI;AAAA,MACjB,MAAM;AAAA,MACN,MAAM,SAAS;AAAA,MACf,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ,MAAM,SAAS;AAAA,QACf,eAAe,OAAO,QAAQ,SAAS,QAAQ;AAAA,QAC/C,QAAQC,YAAW,QAAQ,EAAE,OAAO,OAAO,OAAO,EAAE,OAAO,KAAK;AAAA,MAClE;AAAA,IACF;AAAA,EACF;AACA,SAAO;AAAA,IACL,MAAM,EAAE,MAAM,WAAW,WAAW,WAAW,UAAU,OAAO,CAAC,aAAa,SAAS,SAAS,UAAU,EAAE;AAAA,IAC5G;AAAA,EACF;AACF;;;AE3CO,SAAS,WAAW,OAAiB,QAAkB;AAC5D,QAAM,WAAW,YAAY,KAAK;AAClC,QAAM,YAAY,YAAY,MAAM;AACpC,QAAM,WAAW,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,QAAQ,GAAG,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK;AAC1F,QAAM,QAAQ,CAAC,UAAU,MAAM,MAAM,MAAM,UAAU,WAAW,OAAO,EAAE,KAAK,OAAO,MAAM,MAAM,WAAW,EAAE;AAC9G,MAAI,UAAU;AACd,aAAW,YAAY,UAAU;AAC/B,QAAI,CAAC,OAAO,OAAO,UAAU,QAAQ,GAAG;AACtC,YAAM,KAAK,gBAAgB,kBAAkB,QAAQ,CAAC,EAAE;AACxD,iBAAW;AAAA,IACb,WAAW,CAAC,OAAO,OAAO,WAAW,QAAQ,GAAG;AAC9C,YAAM,KAAK,eAAe,kBAAkB,QAAQ,CAAC,EAAE;AACvD,iBAAW;AAAA,IACb,WAAW,SAAS,QAAQ,MAAM,UAAU,QAAQ,GAAG;AACrD,YAAM,KAAK,cAAc,kBAAkB,QAAQ,CAAC,EAAE;AACtD,iBAAW;AAAA,IACb;AAAA,EACF;AACA,MAAI,YAAY,EAAG,OAAM,KAAK,sBAAsB;AACpD,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,uBAAuB,OAAe,UAAoB;AACxE,SAAO,CAAC,GAAG,KAAK,KAAK,SAAS,EAAE,IAAI,GAAG,SAAS,MAAM,IAAI,CAAC,SAAS,QAAQ,kBAAkB,KAAK,IAAI,CAAC,EAAE,CAAC,EAAE;AAAA,IAC3G;AAAA,EACF;AACF;AAEO,SAAS,kBACd,QACA,aACA,QACA,MACA,2BAA2B,GAC3B,QACA;AACA,SAAO;AAAA,IACL,eAAe,iBAAiB,OAAO,SAAS,CAAC;AAAA,IACjD,qBAAqB,iBAAiB,WAAW,CAAC;AAAA,IAClD,UAAU,OAAO,MAAM,MAAM,eAAe,iBAAiB,SAAS,CAAC,CAAC;AAAA,IACxE,aAAa,OAAO,eAAe,sDAAiD,cAAc;AAAA,IAClG,OAAO,kBAAkB,KAAK,UAAU,KAAK;AAAA,IAC7C;AAAA,IACA,GAAI,UAAU,uBAAuB,OAAO,SAAS,MAAM,EAAE,SAAS,cAClE,CAAC,2GAA2G,IAC5G,CAAC;AAAA,IACL,yBAAyB,QAAQ,MAAM;AAAA,IACvC,2BAA2B,IACvB,8EAA8E,wBAAwB,kDACtG;AAAA,EACN,EAAE,KAAK,IAAI;AACb;AAEO,SAAS,mBAAmB,OAAiB,QAAkB;AACpE,SAAO,yBAAyB,OAAO,QAAQ;AAAA,IAC7C,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV,CAAC;AACH;AAEO,SAAS,kBACd,QACA,aACA,OACA,QACA,uBACA;AACA,SAAO;AAAA,IACL,eAAe,iBAAiB,OAAO,SAAS,CAAC;AAAA,IACjD,qBAAqB,iBAAiB,WAAW,CAAC;AAAA,IAClD,aAAa,iBAAiB,OAAO,EAAE,CAAC;AAAA,IACxC,aAAa,OAAO,eAAe,sDAAiD,cAAc;AAAA,IAClG,4BAA4B,yBAAyB,MAAM;AAAA,IAC3D,mBAAmB,OAAO,MAAM;AAAA,IAChC;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEO,SAAS,sBACd,QACA,aACA,OACA,QACA,mBACA,uBACA;AACA,SAAO;AAAA,IACL,eAAe,iBAAiB,OAAO,SAAS,CAAC;AAAA,IACjD,qBAAqB,iBAAiB,WAAW,CAAC;AAAA,IAClD,aAAa,iBAAiB,iBAAiB,CAAC;AAAA,IAChD,aAAa,OAAO,eAAe,sDAAiD,cAAc;AAAA,IAClG,4BAA4B,yBAAyB,MAAM;AAAA,IAC3D,mBAAmB,OAAO,MAAM;AAAA,IAChC;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEO,SAAS,yBAAyB,QAA8B,QAAkB;AACvF,MAAI,CAAC,QAAQ;AACX,WAAO,CAAC,oBAAoB,GAAG,OAAO,MAAM,IAAI,CAAC,SAAS,iBAAiB,kBAAkB,KAAK,IAAI,CAAC,EAAE,CAAC,EAAE;AAAA,MAC1G;AAAA,IACF;AAAA,EACF;AACA,SAAO,yBAAyB,QAAQ,QAAQ;AAAA,IAC9C,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV,CAAC;AACH;AAEA,SAAS,yBACP,QACA,OACA,QACA;AACA,QAAM,YAAY,YAAY,MAAM;AACpC,QAAM,WAAW,YAAY,KAAK;AAClC,QAAM,QAAQ,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,SAAS,GAAG,GAAG,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK;AACvF,QAAM,QAAkB,CAAC;AACzB,aAAW,YAAY,OAAO;AAC5B,QAAI,CAAC,OAAO,OAAO,WAAW,QAAQ,EAAG,OAAM,KAAK,GAAG,OAAO,GAAG,KAAK,kBAAkB,QAAQ,CAAC,EAAE;AAAA,aAC1F,CAAC,OAAO,OAAO,UAAU,QAAQ,EAAG,OAAM,KAAK,GAAG,OAAO,MAAM,KAAK,kBAAkB,QAAQ,CAAC,EAAE;AAAA,aACjG,UAAU,QAAQ,MAAM,SAAS,QAAQ,EAAG,OAAM,KAAK,GAAG,OAAO,MAAM,KAAK,kBAAkB,QAAQ,CAAC,EAAE;AAAA,EACpH;AACA,MAAI,MAAM,WAAW,EAAG,OAAM,KAAK,kBAAkB;AACrD,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,0BAA0B,OAAiB,QAAkB;AAC3E,QAAM,aAAa,IAAI,IAAI,MAAM,MAAM,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC;AAC/D,SAAO,OAAO,MAAM,OAAO,CAAC,SAAS,CAAC,WAAW,IAAI,KAAK,IAAI,CAAC,EAAE;AACnE;AAEO,SAAS,iCAAiC,YAAmC;AAClF,UAAQ,YAAY;AAAA,IAClB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;;;ACtGO,SAAS,mBAAmB,SAAoC;AACrE,QAAM,EAAE,QAAQ,OAAO,OAAO,QAAQ,KAAK,IAAI;AAC/C,QAAM,gBAAgB,QAAQ,MAAM,mBAAmB,KAAK,kBAAkB,OAAO,MAAM;AAC3F,QAAM,kBAAkB,2BAA2B,KAAK;AACxD,QAAM,iBAAiB,CAAC,GAAG,OAAO,OAAO;AACzC,QAAM,SAAS;AAAA,IACb,cAAc,QAAQ;AAAA,IACtB,eAAe,QAAQ;AAAA,IACvB;AAAA,EACF;AACA,QAAM,aACJ,SAAS,iCACL,CAAC,uEAAuE,IACxE,SAAS,iCACP,CAAC,wEAAwE,IACzE,SAAS,iBACP,CAAC,uCAAuC,IACxC;AAAA,IACE,GAAI,OAAO,eAAe,CAAC,4CAA4C,IAAI,CAAC;AAAA,IAC5E,GAAI,OAAO,gBAAgB,CAAC,6CAA6C,IAAI,CAAC;AAAA,IAC9E,GAAI,OAAO,gBAAgB,CAAC,+CAA+C,IAAI,CAAC;AAAA,EAClF;AACV,QAAM,aAAa,SACf,WAAW,OAAO,MAAM,IACxB,uBAAuB,4CAA4C,KAAK;AAC5E,QAAM,SAAS;AAAA,IACb,eAAe,iBAAiB,OAAO,SAAS,CAAC;AAAA,IACjD;AAAA,IACA;AAAA,IACA,GAAG;AAAA,IACH,GAAI,gBACA,CAAC,IAAI,wBAAwB,SAAS,eAAe,CAAC,IAAI,uBAAuB,SAAS,cAAc,CAAC,EAAE,IAC3G,CAAC;AAAA,IACL;AAAA,IACA;AAAA,IACA,GAAG,WAAW,MAAM,IAAI,EAAE,IAAI,gBAAgB;AAAA,EAChD,EAAE,KAAK,IAAI;AACX,SAAO,IAAI,0BAA0B;AAAA,IACnC;AAAA,IACA,WAAW,OAAO;AAAA,IAClB,gBAAgB,yBAAyB,MAAM;AAAA,IAC/C;AAAA,IACA,GAAI,gBAAgB,EAAE,iBAAiB,CAAC,GAAG,eAAe,EAAE,IAAI,CAAC;AAAA,IACjE;AAAA,IACA;AAAA,IACA,YAAY,SAAS,iBAAiB,CAAC,MAAM,IAAI,CAAC,QAAQ,MAAM;AAAA,IAChE,eAAe,QAAQ;AAAA,EACzB,CAAC;AACH;AAEA,SAAS,SAAS,QAA2B;AAC3C,SAAO,OAAO,SAAS,IAAI,OAAO,IAAI,gBAAgB,EAAE,KAAK,IAAI,IAAI;AACvE;;;ACnCA,IAAM,eAAe;AAGrB,eAAsB,UACpB,KACA,SACA,UAA8B,mBAC9B,YACA;AACA,QAAM,gBAAgB,qBAAqB,KAAK,QAAQ,MAAM;AAC9D,QAAM,YAAY,MAAM;AACtB,QAAI;AACF,oBAAc;AACd,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,QAAM,SAAS,MAAM,WAAW,QAAQ,KAAK;AAC7C,QAAM,cAAc,2BAA2B,MAAM;AACrD,QAAM,cAAc,OAAO,QAAQ,SAAS,UAAU,IAAI,MAAM,qBAAqB,GAAG,IAAI;AAC5F,gBAAc;AACd,QAAM,kBAAkB;AAAA,IACtB,GAAG,0BAA0B,KAAK,MAAM;AAAA,IACxC,YAAY;AAAA,IACZ,QAAQ,QAAQ;AAAA,EAClB;AACA,QAAM,WAAW,YAAY;AAC3B,kBAAc;AACd,UAAM,SAAS,MAAM,WAAW,QAAQ,KAAK;AAC7C,kBAAc;AACd,QAAI,gBAAgB,2BAA2B,MAAM;AACnD,YAAM,IAAI,MAAM,8DAA8D;AAChF,QAAI,gBAAgB,QAAW;AAC7B,YAAM,cAAc,MAAM,qBAAqB,GAAG;AAClD,oBAAc;AACd,UAAI,gBAAgB;AAClB,cAAM,IAAI,MAAM,6EAA6E;AAAA,IACjG;AACA,QAAI,QAAQ,SAAS,CAAC,OAAO,qBAAqB,CAAC,IAAI,OAAO;AAC5D,YAAM,IAAI,MAAM,mEAAmE;AAAA,EACvF;AACA,QAAM,SAAS;AACf,QAAM,UAAU,MAAM,QAAQ,MAAM;AACpC,QAAM,SAAS;AACf,MAAI,QAAQ,QAAQ,QAAQ,eAAe,2BAA2B;AACpE,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,UAAU,MAAM,iBAAiB,MAAM;AAC7C,QAAM,SAAS;AACf,MAAI,SAAS;AACX,UAAM,YAAY,MAAM,gBAAgB,KAAK,QAAQ,SAAS,SAAS,UAAU,QAAQ,QAAQ,QAAQ,IAAI;AAC7G,QAAI,CAAC,WAAW;AACd,WAAK,QAAQ,QAAQ,CAAC,QAAQ,WAAW,CAAC,QAAQ,QAAQ;AACxD,YAAI,GAAG;AAAA,UACL;AAAA,UACA;AAAA,QACF;AACF,aAAO;AAAA,IACT;AACA,SAAK,QAAQ,QAAQ,CAAC,QAAQ,WAAW,CAAC,QAAQ,QAAQ;AACxD,UAAI,GAAG,OAAO,qFAAqF,MAAM;AAC3G,WAAO;AAAA,EACT;AACA,QAAM,aAAa,EAAE,WAAW,sBAAsB;AACtD,QAAM,mBAA8C,CAAC;AACrD,QAAM,iBAAiB,mBAAmB,MAAM;AAChD,MAAI;AACF,aAAS,UAAU,GAAG,UAAU,cAAc,WAAW;AACvD,YAAM,SAAS;AACf,YAAM,QAAQ,MAAM,mBAAmB,MAAM;AAC7C,UAAI,MAAM,YAAY,UAAU,CAAC,OAAO;AACtC,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AACF,YAAM,WAAW,MAAM,eAAe,OAAO,kBAAkB,eAAe;AAC9E,YAAM,QAAQ,iBAAiB,UAAU,OAAO,WAAW;AAC3D,UAAI,CAAC,gBAAgB,MAAM,aAAa,OAAO,WAAW;AACxD,cAAM,IAAI,MAAM,8EAA8E;AAChG,YAAM,OAAO,MAAM,QAAQ,SAAS,QAAQ,MAAM;AAClD,YAAM,SAAS;AACf,YAAM,YAAY,OAAO,MAAM,oBAAoB,SAAS,MAAM,QAAQ,MAAM,IAAI;AACpF,YAAM,SAAS;AACf,UAAI,WAAW;AACb,cAAM,QAAQ,CAAC,GAAG,MAAM,OAAO,GAAG,UAAU,KAAK;AACjD,YACE,MAAM,SAAS,SACf,MAAM,OAAO,CAAC,OAAO,SAAS,QAAQ,KAAK,cAAc,SAAS,MAAM,CAAC,IAAI,KAAK,OAAO,MACzF;AACA,gBAAM,IAAI;AAAA,YACR;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,YAAM,SAAS,YACX,iBAAiB,8BAA8B,WAAW,MAAM,GAAG,UAAU,WAAW,IACxF;AACJ,UAAI,WAAW;AACb,yCAAiC,QAAQ,SAAS;AAClD,cAAM,aAAa,cAAc;AAAA,UAC/B,UAAU,MAAM;AAAA,UAChB,OAAO,MAAM;AAAA,UACb,QAAQ,UAAU;AAAA,UAClB,qBAAqB;AAAA,QACvB,CAAC;AACD,cAAM,eAAe,oBAAI,IAAI;AAAA,UAC3B,GAAG,OAAO,KAAK,MAAM,cAAc;AAAA,UACnC,GAAG,CAAC,GAAG,MAAM,OAAO,GAAI,QAAQ,SAAS,CAAC,CAAE,EAAE,IAAI,CAAC,SAAS,KAAK,IAAI;AAAA,QACvE,CAAC;AACD,YACE,WAAW,SAAS,aACpB,WAAW,UAAU;AAAA,UACnB,CAAC,SAAS,KAAK,WAAW,qBAAqB,CAAC,OAAO,eAAe,CAAC,aAAa,IAAI,KAAK,IAAI;AAAA,QACnG;AAEA,gBAAM,IAAI,MAAM,yFAAyF;AAAA,MAC7G;AACA,YAAM,SAAS,CACb,SACA,OAAqE,mBAErE,mBAAmB;AAAA,QACjB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,cAAc,gBAAgB,OAAO,OAAO,MAAM;AAAA,QAClD,eAAe,SAAS,iBAAiB,QAAQ,OAAO,MAAM,IAAI,QAAQ,MAAM,mBAAmB;AAAA,QACnG,eAAe;AAAA,MACjB,CAAC;AACH,UAAI,CAAC,MAAM,oBAAqB,OAAM,OAAO,+DAA+D;AAC5G,UAAI,kBAAkB,OAAO,MAAM;AACjC,cAAM,OAAO,kEAAkE,0BAA0B;AAC3G,UAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;AACvB,cAAM,OAAO,6EAA6E,cAAc;AAC1G,YAAM,iBAAiB,uBAAuB,OAAO,SAAS,SAAS;AACvE,YAAM,sBAAsB,eAAe,SAAS;AACpD,UAAI,OAAO,cAAc;AAAA,QACvB,UAAU,MAAM;AAAA,QAChB,OAAO,MAAM;AAAA,QACb,QAAQ,OAAO;AAAA,QACf;AAAA,QACA,gBAAgB,sBAAsB,KAAK,WAAW;AAAA,MACxD,CAAC;AACD,UAAI,WAAW,EAAE,MAAM,QAAQ,CAAC,EAAc;AAC9C,UAAI,OAAO,eAAe;AACxB,YAAI;AACF,qBAAW,MAAM,yBAAyB,QAAQ,OAAO,OAAO,QAAQ,IAAI;AAAA,QAC9E,SAAS,OAAO;AACd,cAAI,CAAC,OAAO,YAAa,OAAM;AAAA,QACjC;AAAA,MACF;AACA,YAAM,SAAS;AACf,aAAO,MAAM;AAAA,QACX;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,SAAS;AAAA,QACT,sBAAsB,KAAK,WAAW;AAAA,QACtC,EAAE,YAAY,QAAQ,QAAQ,OAAO;AAAA,MACvC;AACA,YAAM,SAAS;AACf,UAAI,YAAY;AACd,eAAO,MAAM;AAAA,UACX;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,sBAAsB,KAAK,WAAW;AAAA,QACxC;AACA,cAAM,SAAS;AAAA,MACjB;AACA,UAAI,KAAK,SAAS,aAAc,KAAK,UAAU,WAAW,CAAC,OAAO,eAAe,QAAQ,OAAQ;AAC/F,cAAM,WAAW;AAAA,UACf,sBACI,6HAA6H,SAAS,OAAO,SAAS,qBAAqB,SAAS,OAAO,IAAI,gBAAgB,EAAE,KAAK,IAAI,CAAC,KAAK,EAAE,KAClO;AAAA,UACJ,sBAAsB,iBAAiB;AAAA,QACzC;AACA,YAAI,CAAC;AACH,mBAAS,SAAS,UAAU;AAAA;AAAA,EAAO,4BAA4B,cAAc,CAAC;AAAA;AAChF,cAAM;AAAA,MACR;AACA,UAAI,KAAK,SAAS,UAAW,OAAM,IAAI,MAAM,4CAA4C;AACzF,YAAM,SAAS,eAAe,MAAM,MAAM;AAC1C,YAAM,WAAW,IAAI,IAAI,OAAO,QAAQ,CAAC,UAAU,MAAM,KAAK,CAAC;AAG/D,YAAM,kBAAkB,YAAkD;AACxE,YAAI,CAAC,OAAO,OAAQ;AACpB,YAAI,YAAoE,CAAC;AACzE,YAAI;AACF,uBAAc,MAAM,mBAAmB,QAAQ,KAAK,KAAM,CAAC,GAAG,OAAO,CAAC,SAAS,SAAS,IAAI,KAAK,IAAI,CAAC;AAAA,QACxG,QAAQ;AAAA,QAER;AACA,cAAM,SAAS;AACf,cAAM,oBAAoB,oBAAI,IAO5B;AACF,mBAAW,SAAS,IAAI,IAAI,MAAM,YAAY,IAAI,CAAC,UAAU,MAAM,QAAQ,KAAK,CAAC,CAAC,GAAG;AACnF,cAAI;AACF,kBAAMC,YAAW,MAAM,qBAAqB,QAAQ,QAAQ,UAAU,KAAK;AAC3E,8BAAkB,IAAI,OAAO;AAAA,cAC3B,UAAAA;AAAA,cACA,OAAO,YAAYA,UAAS,KAAK;AAAA,cACjC,QAAQ,YAAYA,UAAS,MAAM;AAAA,YACrC,CAAC;AAAA,UACH,QAAQ;AAAA,UAER;AACA,gBAAM,SAAS;AAAA,QACjB;AACA,cAAM,cAAc,YAAY,KAAK;AACrC,cAAM,eAAe,YAAY,MAAM;AACvC,cAAM,iBAAiB,IAAI,IAAI,MAAM,YAAY,IAAI,CAAC,SAAS,CAAC,KAAK,UAAU,KAAK,KAAK,GAAG,IAAI,CAAC,CAAC;AAClG,cAAMC,WAAU,OAAO,IAAI,CAAC,UAAU;AACpC,gBAAM,WAAW,eAAe,IAAI,KAAK,UAAU,MAAM,KAAK,CAAC;AAC/D,gBAAM,WAAW,WAAW,kBAAkB,IAAI,SAAS,QAAQ,IAAI;AACvE,cAAI,CAAC,YAAY,CAAC,SAAU,QAAO,EAAE,MAAM;AAC3C,iBAAO,MAAM,MAAM;AAAA,YACjB,CAAC,aACC,YAAY,QAAQ,MAAM,SAAS,MAAM,QAAQ,KACjD,aAAa,QAAQ,MAAM,SAAS,OAAO,QAAQ,KACnD,MAAM,eAAe,QAAQ,MAAM,SAAS,SAAS,MAAM,eAAe,QAAQ;AAAA,UACtF,IACI,EAAE,OAAO,UAAU,SAAS,SAAS,IACrC,EAAE,MAAM;AAAA,QACd,CAAC;AACD,YAAI;AACJ,cAAM,YAAYA,SAAQ,OAAO,CAAC,SAAS,CAAC,KAAK,QAAQ,EAAE,IAAI,CAAC,SAAS,KAAK,KAAK;AACnF,cAAM,WAAW,IAAI,IAAI,UAAU,QAAQ,CAAC,UAAU,MAAM,KAAK,CAAC;AAClE,YAAI,UAAU;AACZ,qBAAW,MAAM;AAAA,YACf;AAAA,YACA,QAAQ;AAAA,YACR;AAAA,cACE;AAAA,cACA,OAAO,EAAE,GAAG,OAAO,OAAO,MAAM,MAAM,OAAO,CAAC,SAAS,SAAS,IAAI,KAAK,IAAI,CAAC,EAAE;AAAA,cAChF,QAAQ,EAAE,GAAG,QAAQ,OAAO,OAAO,MAAM,OAAO,CAAC,SAAS,SAAS,IAAI,KAAK,IAAI,CAAC,EAAE;AAAA,cACnF,WAAW,UAAU,OAAO,CAAC,SAAS,SAAS,IAAI,KAAK,IAAI,CAAC;AAAA,cAC7D,QAAQ;AAAA,cACR,UAAU,EAAE,YAAY,KAAK,YAAY,UAAU,KAAK,SAAS;AAAA,YACnE;AAAA,YACA,qBAAqB,KAAK,QAAQ,MAAM;AAAA,YACxC,CAAC,YAAY,iBAAiB,KAAK,OAAO;AAAA,UAC5C;AACF,cAAM,SAAS;AACf,eAAO;AAAA,UACL,UAAU;AAAA,UACV,QAAQA,SAAQ,IAAI,CAAC,UAAU,EAAE,OAAO,KAAK,MAAM,OAAO,UAAU,KAAK,YAAY,YAAY,GAAG,EAAE;AAAA,QACxG;AAAA,MACF;AACA,UAAI;AACJ,YAAM,WAAW,2BAA2B;AAAA,QAC1C,GAAG;AAAA,QACH,OAAO,mBAAmB,KAAK,WAAW,MAAM,OAAO,QAAQ;AAAA,MACjE,CAAC;AACD,YAAM,QAAQ,mBAAmB,UAAU,UAAU,OAAO,WAAW;AACvE,UAAI,OAAO,QAAQ,SAAS,UAAU,EAAG,+BAA8B,UAAU,KAAK;AACtF,YAAM,cAAc,2BAA2B;AAAA,QAC7C,GAAG;AAAA,QACH,SAAS,OAAO,cAAc,IAAI,SAAS;AAAA,QAC3C,OAAO;AAAA,UACL,GAAG,SAAS,MAAM,OAAO,CAAC,SAAS,CAAC,SAAS,IAAI,KAAK,IAAI,CAAC;AAAA,UAC3D,GAAG,OAAO,MAAM,OAAO,CAAC,SAAS,SAAS,IAAI,KAAK,IAAI,CAAC;AAAA,QAC1D;AAAA,MACF,CAAC;AACD,YAAM,SAAS,0BAA0B,aAAa,WAAW,MAAM;AACvE,YAAM,UACJ,CAAC,WAAW,YAAY,WAAW,GAAG,YAAY,MAAM,CAAC,KACzD,QAAQ,OAAO,eAAe,UAAU,YAAY,CAAC;AACvD,YAAM,QAAQ,CAAC,WAAW,YAAY,QAAQ,GAAG,YAAY,KAAK,CAAC;AACnE,UAAI,CAAC,WAAW,CAAC,OAAO;AACtB,cAAM,iBAAiB,MAAM,QAAQ,SAAS,QAAQ,MAAM;AAC5D,cAAM,SAAS;AACf,YAAI,CAAC,kBAAkB,CAAC,QAAQ,aAAa,eAAe,UAAU,KAAK,QAAQ;AACjF,gBAAM,IAAI,MAAM,4EAA4E;AAC9F,mBAAW,MAAM,gBAAgB;AACjC,cAAM,SAAS;AACf,cAAM,eAAe,MAAM,eAAe,OAAO,kBAAkB,eAAe;AAClF,cAAM,SAAS;AACf,YACE,CAAC,WAAW,YAAY,YAAY,GAAG,YAAY,QAAQ,CAAC,KAC5D,qBAAqB,MAAM,mBAAmB,MAAM,CAAC,MAAM,qBAAqB,KAAK;AAErF,gBAAM,IAAI;AAAA,YACR;AAAA,UACF;AACF,cAAM,SAAS;AACf,cAAM,cAAc,MAAM,QAAQ,SAAS,QAAQ,MAAM;AACzD,cAAM,SAAS;AACf,YAAI,CAAC,eAAe,CAAC,QAAQ,aAAa,YAAY,UAAU,KAAK,QAAQ;AAC3E,gBAAM,IAAI,MAAM,4EAA4E;AAC9F,cAAM,mBAAmB,QAAQ,MAAM,UAAU,UAAU,QAAQ;AACnE,cAAM;AAAA,UACJ;AAAA,UACA,cAAc,QAAQ,MAAM,UAAU,QAAQ;AAAA,UAC9C,qBAAqB,KAAK,QAAQ,MAAM;AAAA,QAC1C;AACA,cAAM,SAAS;AACf,cAAM;AAAA,UACJ;AAAA,UACA,QAAQ;AAAA,UACR,cAAc,QAAQ,MAAM,UAAU,QAAQ;AAAA,UAC9C;AAAA,UACA;AAAA,UACA,qBAAqB,KAAK,QAAQ,MAAM;AAAA,QAC1C;AACA,cAAM,SAAS;AACf,YAAI,CAAC,QAAQ;AACX,cAAI,GAAG;AAAA,YACL,WACI,qCAAqC,OAAO,MAAM,8DAClD;AAAA,YACJ,WAAW,YAAY;AAAA,UACzB;AACF,eAAO;AAAA,MACT;AACA,YAAM,uBAAuB,UAAU,OAAO,iBAAiB,IAAI,eAAe,iBAAiB,CAAC;AACpG,YAAM,SAAS;AACf,UAAI,CAAC,OAAO,kBAAkB,aAAa,MAAM,EAAE;AACjD,cAAM,IAAI,MAAM,4EAA4E;AAC9F,UAAI,CAAC,QAAQ,KAAK;AAChB,cAAM,UAAU,kBAAkB;AAAA,UAChC,WAAW,OAAO;AAAA,UAClB,aAAa,QAAQ;AAAA,UACrB,aAAa;AAAA,UACb,YAAY;AAAA,UACZ,cAAc;AAAA,UACd,aAAa;AAAA,UACb;AAAA,UACA,UAAU,OAAO,QAAQ,SAAS,UAAU;AAAA,UAC5C;AAAA,UACA,WAAW,KAAK;AAAA,UAChB,YAAY,QAAQ;AAAA,QACtB,CAAC;AACD,YACE,CAAE,MAAM;AAAA,UACN;AAAA,UACA,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR;AAAA,UACA,QAAQ;AAAA,UACR,QAAQ;AAAA,QACV;AAEA,iBAAO;AAAA,MACX;AACA,YAAM,SAAS;AACf,YAAM,YAAY,MAAM,eAAe,OAAO,kBAAkB,eAAe;AAC/E,UAAI,CAAC,WAAW,YAAY,SAAS,GAAG,YAAY,QAAQ,CAAC;AAC3D,cAAM,IAAI,MAAM,wEAAwE;AAC1F,UAAI,qBAAqB,MAAM,mBAAmB,MAAM,CAAC,MAAM,qBAAqB,KAAK;AACvF,cAAM,IAAI,MAAM,sEAAsE;AACxF,YAAM,SAAS;AACf,YAAM,gBAAgB,MAAM,QAAQ,SAAS,QAAQ,MAAM;AAC3D,YAAM,SAAS;AACf,UAAI,CAAC,iBAAiB,CAAC,QAAQ,aAAa,cAAc,UAAU,KAAK,QAAQ;AAC/E,cAAM,IAAI,MAAM,iEAAiE;AACnF,iBAAW,MAAM,gBAAgB;AACjC,YAAM,SAAS;AACf,YAAM,SAAS,MAAM,YAAY,OAAO,kBAAkB,iBAAiB,QAAQ,MAAM;AACzF,YAAM,SAAS;AACf,YAAM,UAAwB;AAAA,QAC5B,SAAS;AAAA,QACT,UAAU,qBAAqB,QAAQ,QAAQ,QAAQ;AAAA,QACvD,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACA,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;AAAA,QAC/B,QAAQ,UAAU,SAAS;AAAA,QAC3B,cAAc;AAAA,QACd;AAAA,QACA,eAAe,qBAAqB,KAAK;AAAA,QACzC,GAAI,gBAAgB,SAAY,EAAE,YAAY,IAAI,CAAC;AAAA,QACnD,GAAI,CAAC,UAAU,EAAE,eAAe,MAAM,WAAW,KAAK,IAAI,CAAC;AAAA,MAC7D;AACA,YAAM,kBAAkB,QAAQ,OAAO;AAEvC,YAAM,gBAAgB,qBAAqB,MAAM,mBAAmB,MAAM,CAAC;AAC3E,YAAM,SAAS;AACf,YAAM,WAAW,MAAM,eAAe,OAAO,kBAAkB,eAAe;AAC9E,YAAM,SAAS;AACf,UAAI,CAAC,WAAW,YAAY,QAAQ,GAAG,YAAY,QAAQ,CAAC,KAAK,kBAAkB,QAAQ,eAAe;AACxG,cAAM,SAAS;AACf,cAAM,kBAAkB,MAAM;AAC9B,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAEA,UAAI;AACF,cAAM,uBAAuB,UAAU,OAAO,iBAAiB,IAAI,eAAe,iBAAiB,CAAC;AACpG,cAAM,SAAS;AAAA,MACjB,SAAS,OAAO;AACd,cAAM,SAAS;AACf,cAAM,kBAAkB,MAAM;AAC9B,cAAM;AAAA,MACR;AACA,UAAI;AACF,YAAI,SAAS;AACX,gBAAM,SAAS,MAAM,QAAQ,gBAAgB,QAAQ,mBAAmB,IAAI,GAAG;AAAA,YAC7E,QAAQ,QAAQ;AAAA,YAChB,UAAU,QAAQ;AAAA,UACpB,CAAC;AACD,kBAAQ,gBAAgB,OAAO;AAC/B,kBAAQ,WAAW,OAAO;AAC1B,gBAAM,kBAAkB,QAAQ,OAAO;AAAA,QACzC,MAAO,SAAQ,WAAW;AAAA,MAC5B,SAAS,OAAO;AACd,YACE,iBAAiB,4BACjB,MAAM,UAAU,mBAChB,CAAC,MAAM,4BACP;AACA,gBAAM,kBAAkB,MAAM;AAC9B,cAAI,UAAU,IAAI,aAAc;AAChC,gBAAM,IAAI,MAAM,oEAAoE,EAAE,OAAO,MAAM,CAAC;AAAA,QACtG;AAGA,cAAM,mBAAmB,OAAO,OAAO,OAAO;AAAA,MAChD;AACA,YAAM,YAAY,MAAM,gBAAgB,KAAK,QAAQ,SAAS,SAAS,UAAU,QAAQ,QAAQ,QAAQ,IAAI;AAC7G,UAAI,CAAC,WAAW;AACd,YAAI,CAAC,QAAQ,QAAQ,YAAY,QAAQ,QAAQ,CAAC,QAAQ;AACxD,cAAI,GAAG;AAAA,YACL;AAAA,YACA;AAAA,UACF;AACF,eAAO;AAAA,MACT;AACA,UAAI,CAAC,QAAQ,QAAQ,YAAY,QAAQ,QAAQ,CAAC,QAAQ;AACxD,YAAI,GAAG;AAAA,UACL;AAAA,YACE,wCAAmC,iBAAiB,OAAO,SAAS,CAAC,WAAM,QAAQ,mFAAmF,iBAAiB;AAAA,YACvL,GAAI,WACA;AAAA,cACE,qBAAqB,OAAO,MAAM;AAAA,YACpC,IACA,CAAC;AAAA,YACL,IAAI,QAAQ,YAAY,CAAC,GAAG,IAAI,gBAAgB;AAAA,UAClD,EAAE,KAAK,IAAI;AAAA,UACX,YAAY,QAAQ,UAAU,SAAS,YAAY;AAAA,QACrD;AACF,aAAO;AAAA,IACT;AAAA,EACF,UAAE;AACA,UAAM,yBAAyB,QAAQ,gBAAgB,gBAAgB;AAAA,EACzE;AACF;AAEA,eAAe,gBACb,KACA,QACA,SACA,SACA,UACA,QACA,OAAO,OACP;AACA,MACE,QAAQ,aAAa,qBAAqB,QAAQ,QAAQ,QAAQ,KAClE,CAAC,gBAAgB,QAAQ,OAAO,aAAa,OAAO,WAAW;AAE/D,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AACF,QAAM,SAAS;AACf,QAAM,cAAc,OAAO,QAAQ,SAAS,UAAU,IAAI,MAAM,qBAAqB,GAAG,IAAI;AAC5F,QAAM,SAAS;AACf,MAAI,gBAAgB,UAAa,QAAQ,gBAAgB,aAAa;AACpE,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,kBAAkB,EAAE,GAAG,0BAA0B,KAAK,MAAM,GAAG,YAAY,aAAa,OAAO;AACrG,QAAM,OAAO,MAAM,QAAQ,SAAS,MAAM;AAC1C,MACE,CAAC,QAAQ,iBACT,SACC,QAAQ,aAAa,KAAK,UAAU,QAAQ,aAAa,QAAQ,KAChE,QAAQ,iCAAiC,MAAM,QAAQ,YAAY,IACrE;AACA,UAAM,SAAS;AACf,UAAM,QAAQ,MAAM,eAAe,OAAO,kBAAkB,eAAe;AAC3E,QACE,CAAC,WAAW,YAAY,KAAK,GAAG,YAAY,QAAQ,MAAM,CAAC,KAC3D,qBAAqB,MAAM,mBAAmB,MAAM,CAAC,MAAM,QAAQ,eACnE;AACA,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,UAAM,kBAAkB,MAAM;AAC9B,WAAO;AAAA,EACT;AACA,QAAM,SAAS;AAGf,MAAI,QAAQ,kBAAkB,CAAC,QAAQ,CAAC,QAAQ,aAAa,KAAK,UAAU,QAAQ,cAAc,QAAQ,IAAI;AAC5G,UAAMC,SAAQ,MAAM,mBAAmB,MAAM;AAC7C,UAAM,SAAS;AACf,QACE,qBAAqBA,QAAO,QAAQ,QAAQ,eAAe,QAAQ,YAAY,QAAQ,OAAO,QAAQ,QAAQ,GAC9G;AACA,YAAM,kBAAkB,MAAM;AAC9B,YAAM,SAAS;AACf,YAAM,oBAAoB,QAAQA,QAAO,qBAAqB,KAAK,MAAM,CAAC;AAC1E,YAAM,SAAS;AACf,aAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI,QAAQ,cAAc,CAAC,QAAQ,CAAC,QAAQ,aAAa,KAAK,UAAU,QAAQ,aAAa,QAAQ,IAAI;AACvG,UAAM,QAAQ,MAAM,eAAe,OAAO,kBAAkB,eAAe;AAC3E,UAAMA,SAAQ,MAAM,mBAAmB,MAAM;AAC7C,UAAM,SAAS;AACf,QACE,WAAW,YAAY,KAAK,GAAG,YAAY,QAAQ,MAAM,CAAC,KAC1D,qBAAqBA,MAAK,MAAM,QAAQ,eACxC;AACA,YAAM,kBAAkB,MAAM;AAC9B,aAAO;AAAA,IACT;AACA,UAAM,IAAI,MAAM,kGAAkG;AAAA,EACpH;AACA,MACE,CAAC,QACD,KAAK,eAAe,QAAQ,OAAO,MAClC,QAAQ,iBAAiB,CAAC,QAAQ,aAAa,KAAK,UAAU,QAAQ,cAAc,QAAQ,GAC7F;AACA,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,QAAM,WAAW,MAAM,oBAAoB,SAAS,MAAM,MAAM;AAChE,mCAAiC,QAAQ,QAAQ;AACjD,MACE,CAAC,WAAW,YAAY,QAAQ,GAAG,YAAY,QAAQ,MAAM,CAAC,KAC9D,KAAK,UAAU,SAAS,SAAS,MAAM,KAAK,UAAU,QAAQ,OAAO,SAAS;AAE9E,UAAM,IAAI,MAAM,gEAAgE;AAClF,QAAM,QAAQ,MAAM,mBAAmB,MAAM;AAC7C,MAAI,qBAAqB,OAAO,QAAQ,MAAM,QAAQ,YAAY,QAAQ,OAAO,QAAQ,QAAQ,GAAG;AAClG,UAAM,SAAS;AACf,UAAM,kBAAkB,MAAM;AAC9B,UAAM,SAAS;AACf,UAAM,oBAAoB,QAAQ,OAAO,qBAAqB,KAAK,MAAM,CAAC;AAC1E,UAAM,SAAS;AACf,WAAO;AAAA,EACT;AACA,MAAI,qBAAqB,KAAK,MAAM,QAAQ,eAAe;AACzD,UAAM,IAAI,MAAM,8FAA8F;AAAA,EAChH;AACA,MAAI,uBAAuB,OAAO,SAAS,QAAQ,EAAE,SAAS;AAC5D,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AACF,MAAI,OAAO,QAAQ,SAAS,UAAU,EAAG,+BAA8B,QAAQ,QAAQ,QAAQ,KAAK;AACpG,QAAM,SAAS;AACf,QAAM,gBAAgB,qBAAqB,KAAK,MAAM;AACtD,QAAM,mBAAmB,MAAM;AAC7B,kBAAc;AACd,QAAI,QAAQ,CAAC,IAAI,OAAO,EAAG,OAAM,IAAI,MAAM,4DAA4D;AAAA,EACzG;AACA,QAAM;AAAA,IACJ,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,sBAAsB,KAAK,WAAW;AAAA,IACtC,EAAE,GAAG,iBAAiB,iBAAiB;AAAA,IACvC;AAAA,IACA,IAAI,eAAe,iBAAiB;AAAA,EACtC;AACA,QAAM,SAAS;AACf,QAAM,mBAAmB,MAAM,QAAQ,SAAS,MAAM;AACtD,QAAM,SAAS;AACf,MAAI,CAAC,oBAAoB,CAAC,QAAQ,aAAa,iBAAiB,UAAU,KAAK,QAAQ;AACrF,UAAM,IAAI,MAAM,6EAA6E;AAC/F,QAAM,mBAAmB,QAAQ,MAAM,QAAQ,YAAY,QAAQ,OAAO,UAAU,QAAQ,QAAQ;AACpG,QAAM,SAAS;AACf,QAAM,kBAAkB,MAAM;AAC9B,QAAM,SAAS;AACf,QAAM;AAAA,IACJ;AAAA,IACA,cAAc,QAAQ,MAAM,QAAQ,YAAY,QAAQ,OAAO,QAAQ,QAAQ;AAAA,IAC/E,qBAAqB,KAAK,MAAM;AAAA,EAClC;AACA,QAAM,SAAS;AACf,QAAM;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,IACR,cAAc,QAAQ,MAAM,QAAQ,YAAY,QAAQ,OAAO,QAAQ,QAAQ;AAAA,IAC/E,QAAQ,YAAY,QAAQ;AAAA,IAC5B,QAAQ;AAAA,IACR,qBAAqB,KAAK,MAAM;AAAA,EAClC;AACA,QAAM,SAAS;AACf,SAAO;AACT;AAGA,SAAS,qBACP,OACA,QACA,MACA,UACA,UACA;AACA,SAAO,CAAC,MAAM,KAAK,EAAE;AAAA,IACnB,CAAC,cACC,qBAAqB,KAAK,MAAM,qBAAqB,cAAc,QAAQ,MAAM,UAAU,UAAU,SAAS,CAAC;AAAA,EACnH;AACF;AAEA,SAAS,cACP,QACA,MACA,UACA,UACA,YAAY,MACZ;AACA,MAAI,SAAU,QAAO,cAAc,QAAQ,MAAM,UAAU,QAAQ;AACnE,SAAO;AAAA,IACL,SAAS;AAAA,IACT,SAAS,OAAO;AAAA,IAChB,qBAAqB,KAAK;AAAA,IAC1B,oBAAoB,KAAK;AAAA,IACzB,gBAAgB,YAAY,YAAY,iBAAiB,UAAU,OAAO,WAAW,IAAI,QAAQ;AAAA,IACjG,SAAS,CAAC,GAAG,OAAO,OAAO;AAAA,IAC3B,GAAI,OAAO,gBAAgB,SAAY,EAAE,aAAa,OAAO,YAAY,IAAI,CAAC;AAAA,EAChF;AACF;AAEA,eAAe,mBACb,QACA,MACA,UACA,UACA,UACA;AACA,QAAM,WAAW,iBAAiB,UAAU,OAAO,WAAW;AAC9D,QAAM,QAAQ,cAAc,QAAQ,MAAM,UAAU,QAAQ;AAC5D,QAAM,mBAAmB,QAAQ,UAAU,OAAO,UAAU,QAAQ;AACpE,QAAM,SAAS;AACf,QAAM,oBAAoB,QAAQ,KAAK;AACvC,QAAM,SAAS;AACjB;",
6
+ "names": ["truncateToWidth", "truncateToWidth", "truncateToWidth", "truncateToWidth", "fs", "path", "fs", "path", "createHash", "fs", "path", "createHash", "fs", "path", "createHash", "fileHashMap", "fs", "path", "path", "fs", "createHash", "target", "index", "createHash", "createHash", "artifact", "pending", "state"]
7
+ }
@@ -3,7 +3,7 @@
3
3
  import {
4
4
  confirmMergeReview,
5
5
  mergeSync
6
- } from "./chunk-QDPED3XJ.ts";
6
+ } from "./chunk-HUTYAPFP.ts";
7
7
  import {
8
8
  conflictArtifactFingerprint,
9
9
  readConflictArtifact
@@ -172,4 +172,4 @@ async function showConflicts(ctx, options, factory = createSyncBackend) {
172
172
  export {
173
173
  showConflicts
174
174
  };
175
- //# sourceMappingURL=conflict-review-JANNPKKS.ts.map
175
+ //# sourceMappingURL=conflict-review-JRFJIBEN.ts.map
@@ -14,7 +14,7 @@ import {
14
14
  formatSnapshotOnlyDiff,
15
15
  mergeSync,
16
16
  publicationCapabilityDescription
17
- } from "./chunk-QDPED3XJ.ts";
17
+ } from "./chunk-HUTYAPFP.ts";
18
18
  import {
19
19
  readMergeJournal,
20
20
  requireNoMergeJournal,
@@ -882,4 +882,4 @@ export {
882
882
  status,
883
883
  syncBoth
884
884
  };
885
- //# sourceMappingURL=sync-operations-OWTE3ZL2.ts.map
885
+ //# sourceMappingURL=sync-operations-QQ2GXKVC.ts.map
package/dist/index.ts CHANGED
@@ -200,7 +200,7 @@ async function executeCommand(rawArgs, ctx, signal, loaders, onCommit, setup, on
200
200
  return { kind: "completed" };
201
201
  }
202
202
  case "conflicts": {
203
- const { showConflicts } = await import("./chunks/conflict-review-JANNPKKS.ts");
203
+ const { showConflicts } = await import("./chunks/conflict-review-JRFJIBEN.ts");
204
204
  throwIfAborted(options.signal);
205
205
  await withLock("sync", () => showConflicts(ctx, options));
206
206
  return { kind: "completed" };
@@ -784,7 +784,7 @@ function createSyncLoaders(dependencies) {
784
784
  setupSwitch: cachedModuleLoader(dependencies.loadSetupSwitch ?? (() => import("./chunks/setup-switch-KTUWL6DE.ts"))),
785
785
  snapshot: cachedModuleLoader(dependencies.loadSnapshot ?? (() => import("./chunks/snapshot-THS5EY2L.ts"))),
786
786
  syncState: cachedModuleLoader(dependencies.loadSyncState ?? (() => import("./chunks/sync-state-CFL4RRRB.ts"))),
787
- operations: cachedModuleLoader(dependencies.loadSyncOperations ?? (() => import("./chunks/sync-operations-OWTE3ZL2.ts")))
787
+ operations: cachedModuleLoader(dependencies.loadSyncOperations ?? (() => import("./chunks/sync-operations-QQ2GXKVC.ts")))
788
788
  };
789
789
  return loaders;
790
790
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@narumitw/pi-sync",
3
- "version": "0.54.0",
3
+ "version": "0.54.1",
4
4
  "description": "Pi extension that syncs Pi configuration through Git, WebDAV, Cloudflare R2, or S3-compatible storage.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -30,7 +30,7 @@ import {
30
30
  writeStateForConfig,
31
31
  } from "../state/sync-state-store.js";
32
32
  import { confirmMergeReview } from "../ui/merge-review.js";
33
- import { formatApplyPreview, formatPublicationPreview } from "../ui/sync-format.js";
33
+ import { mergedSyncSummary } from "../ui/merged-sync-summary.js";
34
34
  import { safeTerminalText } from "../ui/terminal-text.js";
35
35
  import { releaseConflictArtifacts } from "./conflict-artifact-ownership.js";
36
36
  import {
@@ -402,29 +402,33 @@ export async function mergeSync(
402
402
  await validate();
403
403
  if (!config.skipSecretScan && scanSnapshot(upload).length)
404
404
  throw new Error("Refusing to merge possible secrets. Review managed content before syncing.");
405
- if (
406
- !options.yes &&
407
- !(await confirmMergeReview(
408
- ctx,
409
- "Merge independent Pi changes?",
410
- [
411
- `Sync setup: ${safeTerminalText(config.setupName)}`,
412
- `Storage location: ${safeTerminalText(backend.destination)}`,
413
- `Sessions: ${config.include.includes("sessions") ? "included — may contain private conversations" : "not included"}`,
414
- `Local writes/deletions: ${plan.decisions.filter((item) => item.kind === "accepted" && (item.source === "remote" || item.source === "merged")).length}`,
415
- formatApplyPreview(localRaw, after).split("\n").map(safeTerminalText).join("\n"),
416
- `Unresolved dependency groups: ${groups.length} (withheld versions stay on each side; baselines do not advance)`,
417
- ...groups.flatMap((group) => group.paths.map((filePath) => `Withheld: ${safeTerminalText(filePath)}`)),
418
- `Remote publication: ${publish ? "yes" : "no"}`,
419
- formatPublicationPreview(rawRemote, upload).split("\n").map(safeTerminalText).join("\n"),
420
- `Backend publication: ${backend.capability}`,
421
- "The current session is protected. A backup and recovery journal are retained. Resources are not reloaded.",
422
- ].join("\n"),
423
- options.signal,
424
- isCurrent,
425
- ))
426
- )
427
- return "cancelled" as const;
405
+ if (!options.yes) {
406
+ const summary = mergedSyncSummary({
407
+ setupName: config.setupName,
408
+ destination: backend.destination,
409
+ localBefore: localRaw,
410
+ localAfter: after,
411
+ remoteBefore: rawRemote,
412
+ remoteAfter: upload,
413
+ publish,
414
+ sessions: config.include.includes("sessions"),
415
+ groups,
416
+ decisions: plan.decisions,
417
+ capability: backend.capability,
418
+ });
419
+ if (
420
+ !(await confirmMergeReview(
421
+ ctx,
422
+ summary.title,
423
+ summary.content,
424
+ options.signal,
425
+ isCurrent,
426
+ summary.confirmationLabel,
427
+ summary.lines,
428
+ ))
429
+ )
430
+ return "cancelled" as const;
431
+ }
428
432
  await validate();
429
433
  const refreshed = await createSnapshot(config.snapshotIdentity, snapshotOptions);
430
434
  if (!sameHashes(fileHashMap(refreshed), fileHashMap(localRaw)))