codesesh 0.19.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +2 -1
  2. package/dist/{chunk-G2BTNW3C.js → chunk-BEF6LLRG.js} +1230 -182
  3. package/dist/chunk-BEF6LLRG.js.map +1 -0
  4. package/dist/{chunk-KD3DGWZY.js → chunk-TIHF4T3K.js} +2 -2
  5. package/dist/{dist-ALXOBKV2.js → dist-3F467V44.js} +4 -2
  6. package/dist/index.js +53 -12
  7. package/dist/index.js.map +1 -1
  8. package/dist/scan-refresh-worker.js +2 -2
  9. package/dist/search-index-worker.js +9 -11
  10. package/dist/search-index-worker.js.map +1 -1
  11. package/dist/smart-tag-worker.js +2 -2
  12. package/dist/web/assets/ErrorBoundary-BY-N1QzJ.js +1 -0
  13. package/dist/web/assets/InteractiveReceipt-DYGyHeZd.js +1 -0
  14. package/dist/web/assets/OverviewScreen-_ZaVjhxN.js +1 -0
  15. package/dist/web/assets/PrismHighlighter-BZkkX0AU.js +6 -0
  16. package/dist/web/assets/Projects-q6cEm2dc.js +1 -0
  17. package/dist/web/assets/SearchFilterBar-CrVBpo40.js +1 -0
  18. package/dist/web/assets/SearchResultsPanel-Cg5V8Ia6.js +1 -0
  19. package/dist/web/assets/SessionDetail-BSSuddsZ.js +54 -0
  20. package/dist/web/assets/{session-title-CNhapdPJ.js → SmartTagChips-ux6idUGJ.js} +1 -1
  21. package/dist/web/assets/chunk-62JRHF6Z-BWRsEBnL.js +4 -0
  22. package/dist/web/assets/code-metrics-UYFsCC7E.js +1 -0
  23. package/dist/web/assets/ibm-plex-sans-cyrillic-ext-wght-normal-d45eAU9y.woff2 +0 -0
  24. package/dist/web/assets/ibm-plex-sans-cyrillic-wght-normal-BAAhND-U.woff2 +0 -0
  25. package/dist/web/assets/ibm-plex-sans-greek-wght-normal-CmyJS8uq.woff2 +0 -0
  26. package/dist/web/assets/ibm-plex-sans-latin-ext-wght-normal-CIII54If.woff2 +0 -0
  27. package/dist/web/assets/ibm-plex-sans-latin-wght-normal-IvpUvPa2.woff2 +0 -0
  28. package/dist/web/assets/ibm-plex-sans-vietnamese-wght-normal-Dg1JeJN0.woff2 +0 -0
  29. package/dist/web/assets/index-C3KgxGwE.js +1410 -0
  30. package/dist/web/assets/index-DQX42cFQ.css +1 -0
  31. package/dist/web/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  32. package/dist/web/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  33. package/dist/web/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  34. package/dist/web/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  35. package/dist/web/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  36. package/dist/web/assets/jsx-runtime-B-hcVAMW.js +1 -0
  37. package/dist/web/assets/panel-B7kuE60V.js +1 -0
  38. package/dist/web/assets/session-indexes-DmnjZ_JL.js +1 -0
  39. package/dist/web/assets/session-title-DdtlxtlR.js +1 -0
  40. package/dist/web/assets/space-grotesk-latin-ext-wght-normal-D9tNdqV9.woff2 +0 -0
  41. package/dist/web/assets/space-grotesk-latin-wght-normal-BhU9QXUp.woff2 +0 -0
  42. package/dist/web/assets/space-grotesk-vietnamese-wght-normal-D0rl6rjA.woff2 +0 -0
  43. package/dist/web/assets/utils-t2u9IbNT.js +1 -0
  44. package/dist/web/icon/agent/grok.svg +1 -0
  45. package/dist/web/index.html +43 -30
  46. package/package.json +8 -8
  47. package/dist/chunk-G2BTNW3C.js.map +0 -1
  48. package/dist/web/assets/AgentIcon-CEj7HO1m.js +0 -1
  49. package/dist/web/assets/BookmarkButton-DLEnIyeE.js +0 -1
  50. package/dist/web/assets/Dashboard-DUG0IFcy.js +0 -39
  51. package/dist/web/assets/DialogTitle-Dv6DQPIb.js +0 -1
  52. package/dist/web/assets/InteractiveReceipt-xnRqJvfd.js +0 -1
  53. package/dist/web/assets/PrismHighlighter-C7OfXHq2.js +0 -6
  54. package/dist/web/assets/Projects-BMaZc6J5.js +0 -1
  55. package/dist/web/assets/SearchFilterBar-iP6pzlZo.js +0 -1
  56. package/dist/web/assets/SearchResultsPanel-RuiLPkbP.js +0 -1
  57. package/dist/web/assets/SessionDetail-De1Wl3mu.js +0 -54
  58. package/dist/web/assets/index-B-CV7pFu.css +0 -2
  59. package/dist/web/assets/index-CQI8F_8X.js +0 -1930
  60. package/dist/web/assets/index.dom-CCLJ9_FR.js +0 -1
  61. package/dist/web/assets/jsx-runtime-n5LQ9ujS.js +0 -1
  62. package/dist/web/assets/session-indexes-BuxBafvh.js +0 -4
  63. package/dist/web/assets/useTheme-CwDcVdGz.js +0 -1
  64. package/dist/web/assets/utils-B6KiDbIe.js +0 -1
  65. /package/dist/{chunk-KD3DGWZY.js.map → chunk-TIHF4T3K.js.map} +0 -0
  66. /package/dist/{dist-ALXOBKV2.js.map → dist-3F467V44.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../core/src/contract/message-part.ts","../../core/src/contract/events.ts","../../core/src/contract/calendar-day.ts","../../core/src/contract/project-identity.ts","../../core/src/contract/session-reference.ts","../../core/src/contract/session-index.ts","../../core/src/contract/session-tree.ts","../../core/src/contract/fixtures.ts","../../core/src/agents/registry.ts","../../core/src/agents/claudecode.ts","../../core/src/agents/base.ts","../../core/src/utils/diagnostics.ts","../../core/src/discovery/paths.ts","../../core/src/utils/jsonl.ts","../../core/src/utils/title-fallback.ts","../../core/src/utils/parse-cleanup.ts","../../core/src/utils/session-normalization.ts","../../core/src/pricing/data/aliases.json","../../core/src/pricing/fetcher.ts","../../core/src/utils/private-storage.ts","../../core/src/pricing/data/snapshot.json","../../core/src/pricing/resolver.ts","../../core/src/pricing/cost.ts","../../core/src/utils/cost.ts","../../core/src/utils/narrow.ts","../../core/src/agents/transcript-builder.ts","../../core/src/agents/opencode.ts","../../core/src/utils/sqlite.ts","../../core/src/agents/opencode-sqlite.ts","../../core/src/agents/kimi.ts","../../core/src/agents/kimi-code.ts","../../core/src/agents/codex.ts","../../core/src/agents/codex-exec-decode.ts","../../core/src/agents/cursor.ts","../../core/src/utils/perf.ts","../../core/src/agents/pi.ts","../../core/src/agents/zcode.ts","../../core/src/agents/register.ts","../../core/src/discovery/scanner.ts","../../core/src/projects/display-name.ts","../../core/src/projects/fs.ts","../../core/src/projects/identity.ts","../../core/src/projects/groups.ts","../../core/src/projects/scope.ts","../../core/src/utils/smart-tags.ts","../../core/src/utils/file-activity.ts","../../core/src/discovery/cache/sessions.ts","../../core/src/discovery/cache/db.ts","../../core/src/discovery/cache/messages.ts","../../core/src/discovery/cache/schema.ts","../../core/src/discovery/cache/search-query-parser.ts","../../core/src/discovery/cache/search-index-writer.ts","../../core/src/discovery/cache/search.ts","../../core/src/discovery/cache/file-activity.ts","../../core/src/discovery/orchestrate.ts","../../core/src/discovery/session-detail.ts","../../core/src/discovery/cache/project-groups.ts","../../core/src/state/database.ts","../../core/src/state/bookmarks.ts","../../core/src/state/session-aliases.ts","../../core/src/analytics/dashboard.ts","../../core/src/analytics/projects.ts","../../core/src/search/session-search.ts"],"sourcesContent":["import type {\n ImagePart,\n MessagePart,\n PlanPart,\n ToolPart,\n ToolPartState,\n ToolPartStatus,\n} from \"./session.js\";\n\nfunction toRecord(value: unknown): Record<string, unknown> | null {\n return value !== null && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null;\n}\n\nfunction optionalString(value: unknown): string | undefined {\n return typeof value === \"string\" && value ? value : undefined;\n}\n\nfunction optionalTime(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\nfunction timeField(time_created: number | undefined) {\n return time_created === undefined ? {} : { time_created };\n}\n\nfunction firstDefined(...values: unknown[]): unknown {\n return values.find((value) => value !== undefined);\n}\n\nfunction normalizeStatus(\n state: Record<string, unknown>,\n output: unknown,\n error: unknown,\n): ToolPartStatus {\n const status = state.status;\n if (status === \"running\" || status === \"completed\" || status === \"error\") return status;\n if (status === \"success\") return \"completed\";\n if (error != null) return \"error\";\n if (output !== undefined) return \"completed\";\n return \"running\";\n}\n\nfunction normalizeMetadata(state: Record<string, unknown>): unknown {\n const rawMetadata = state.metadata ?? state.meta;\n const extras = Object.fromEntries(\n Object.entries(state).filter(\n ([key]) =>\n ![\"status\", \"input\", \"arguments\", \"output\", \"result\", \"error\", \"metadata\", \"meta\"].includes(\n key,\n ),\n ),\n );\n if (Object.keys(extras).length === 0) return rawMetadata;\n\n const metadata = toRecord(rawMetadata);\n return metadata ? { ...metadata, ...extras } : extras;\n}\n\nfunction normalizeToolState(value: unknown, legacyPart: Record<string, unknown>): ToolPartState {\n const state = toRecord(value) ?? {};\n const input = firstDefined(state.input, state.arguments, legacyPart.input);\n const output = firstDefined(state.output, state.result, legacyPart.output);\n const error = state.error;\n const metadata = normalizeMetadata(state);\n\n return {\n status: normalizeStatus(state, output, error),\n ...(input !== undefined ? { input } : {}),\n ...(output !== undefined ? { output } : {}),\n ...(error !== undefined ? { error } : {}),\n ...(metadata !== undefined ? { metadata } : {}),\n };\n}\n\nfunction planText(value: unknown): string {\n if (typeof value === \"string\") return value;\n const record = toRecord(value);\n if (!record) return \"\";\n return planText(record.text ?? record.plan ?? record.content);\n}\n\nfunction normalizePlanPart(\n value: Record<string, unknown>,\n time_created: number | undefined,\n): PlanPart | null {\n const approval_status = value.approval_status === \"fail\" ? \"fail\" : \"success\";\n const text = planText(value.text ?? (approval_status === \"fail\" ? value.output : value.input));\n return text ? { type: \"plan\", text, approval_status, ...timeField(time_created) } : null;\n}\n\nfunction normalizeImagePart(\n value: Record<string, unknown>,\n time_created: number | undefined,\n): ImagePart | null {\n const data = optionalString(value.data);\n const url = optionalString(value.url);\n const mime_type = optionalString(value.mime_type);\n\n if (data && mime_type) {\n return {\n type: \"image\",\n data,\n mime_type,\n ...(url ? { url } : {}),\n ...timeField(time_created),\n };\n }\n if (url) {\n return {\n type: \"image\",\n url,\n ...(data ? { data } : {}),\n ...(mime_type ? { mime_type } : {}),\n ...timeField(time_created),\n };\n }\n return null;\n}\n\nfunction normalizeToolPart(\n value: Record<string, unknown>,\n time_created: number | undefined,\n): ToolPart | null {\n const title = optionalString(value.title);\n const callID = optionalString(value.callID);\n const tool = optionalString(value.tool)?.trim() || title?.replace(/^tool:\\s*/i, \"\").trim();\n if (!tool) return null;\n\n return {\n type: \"tool\",\n tool,\n ...(title ? { title } : {}),\n ...(callID ? { callID } : {}),\n state: normalizeToolState(value.state, value),\n ...timeField(time_created),\n };\n}\n\nfunction normalizeMessagePart(value: unknown): MessagePart | null {\n const part = toRecord(value);\n if (!part) return null;\n const time_created = optionalTime(part.time_created);\n\n if (part.type === \"text\" || part.type === \"reasoning\") {\n if (typeof part.text !== \"string\") return null;\n return { type: part.type, text: part.text, ...timeField(time_created) };\n }\n if (part.type === \"plan\") return normalizePlanPart(part, time_created);\n if (part.type === \"image\") return normalizeImagePart(part, time_created);\n if (part.type === \"tool\") return normalizeToolPart(part, time_created);\n return null;\n}\n\nexport function normalizeMessageParts(value: unknown): MessagePart[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap((part) => {\n const normalized = normalizeMessagePart(part);\n return normalized ? [normalized] : [];\n });\n}\n","import type { ReferencedSessionHead } from \"./session.js\";\nimport type { SessionReference } from \"./session-reference.js\";\n\nexport interface SessionsUpdatedEvent {\n type: \"sessions-updated\";\n changedAgents: string[];\n newSessions: number;\n updatedSessions: number;\n removedSessions: number;\n totalSessions: number;\n timestamp: number;\n changedSessionHeads: ReferencedSessionHead[];\n removedSessionRefs: SessionReference[];\n}\n\nexport function mergeSessionsUpdatedEvents(\n previous: SessionsUpdatedEvent,\n next: SessionsUpdatedEvent,\n): SessionsUpdatedEvent {\n const changedSessionHeads = new Map<string, ReferencedSessionHead>();\n const removedSessionRefs = new Map<string, SessionReference>();\n const sessionKey = (agentName: string, sessionId: string) => `${agentName}\\0${sessionId}`;\n const addChanged = (item: ReferencedSessionHead) => {\n const key = sessionKey(item.reference.agentName, item.reference.sessionId);\n removedSessionRefs.delete(key);\n changedSessionHeads.set(key, item);\n };\n const addRemoved = (item: SessionReference) => {\n const key = sessionKey(item.agentName, item.sessionId);\n changedSessionHeads.delete(key);\n removedSessionRefs.set(key, item);\n };\n\n for (const item of previous.changedSessionHeads) addChanged(item);\n for (const item of previous.removedSessionRefs) addRemoved(item);\n for (const item of next.changedSessionHeads) addChanged(item);\n for (const item of next.removedSessionRefs) addRemoved(item);\n\n return {\n type: \"sessions-updated\",\n changedAgents: Array.from(new Set([...previous.changedAgents, ...next.changedAgents])),\n newSessions: previous.newSessions + next.newSessions,\n updatedSessions: previous.updatedSessions + next.updatedSessions,\n removedSessions: previous.removedSessions + next.removedSessions,\n totalSessions: next.totalSessions,\n timestamp: next.timestamp,\n changedSessionHeads: [...changedSessionHeads.values()],\n removedSessionRefs: [...removedSessionRefs.values()],\n };\n}\n\nexport interface AgentScanStatus {\n agentName: string;\n status: \"pending\" | \"scanning\" | \"finalizing\" | \"indexing\" | \"complete\";\n total?: number;\n processed?: number;\n sessions?: number;\n startedAt?: number;\n updatedAt: number;\n completedAt?: number;\n}\n\n/**\n * Full-history reconciliation runs independently of the main scan phase:\n * startup only syncs the display window, so a low-priority background pass\n * (capped at one agent at a time) periodically re-checks the rest of history.\n */\nexport interface BackfillProgress {\n phase?: \"scanning\" | \"finalizing\" | \"indexing\";\n total?: number;\n processed?: number;\n sessions?: number;\n}\n\nexport interface BackfillStatus {\n active: boolean;\n pendingAgents: string[];\n currentAgent?: string;\n progress?: BackfillProgress;\n completedAgents: string[];\n failedAgents: string[];\n}\n\nexport interface ScanStatusEvent {\n type: \"scan-status\";\n active: boolean;\n phase: \"idle\" | \"indexing\" | \"initializing\" | \"scanning\";\n pendingAgents: string[];\n scanningAgents: string[];\n completedAgents: string[];\n agentStatuses: Record<string, AgentScanStatus>;\n totalAgents: number;\n startedAt?: number;\n updatedAt: number;\n completedAt?: number;\n backfill: BackfillStatus;\n}\n","/**\n * Local calendar days, the unit the dashboard and its time windows are defined\n * in. A calendar day is not a fixed duration: across a DST transition adjacent\n * local midnights are 23 or 25 hours apart, so stepping by a constant number of\n * milliseconds skips or repeats a day. Every helper here advances date fields\n * instead.\n */\n\n/** Local midnight of the calendar day containing `timestamp`. */\nexport function startOfCalendarDay(timestamp: number): number {\n const date = new Date(timestamp);\n return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();\n}\n\n/** Local midnight `days` calendar days from the day containing `timestamp`. */\nexport function addCalendarDays(timestamp: number, days: number): number {\n const date = new Date(timestamp);\n return new Date(date.getFullYear(), date.getMonth(), date.getDate() + days).getTime();\n}\n\n/** Days since the epoch for a local calendar date, counted on a fixed-length UTC grid. */\nfunction toCalendarDayNumber(timestamp: number): number {\n const date = new Date(timestamp);\n return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) / 86_400_000;\n}\n\n/** Calendar days in the inclusive local range, at least 1. */\nexport function countCalendarDays(from: number, to: number): number {\n return Math.max(1, toCalendarDayNumber(to) - toCalendarDayNumber(from) + 1);\n}\n\n/** `YYYY-MM-DD` key for the local calendar day; the dashboard wire format. */\nexport function toCalendarDayKey(timestamp: number): string {\n const date = new Date(timestamp);\n return `${String(date.getFullYear()).padStart(4, \"0\")}-${String(date.getMonth() + 1).padStart(\n 2,\n \"0\",\n )}-${String(date.getDate()).padStart(2, \"0\")}`;\n}\n","/**\n * What a project identity is, independent of how it is discovered or displayed.\n *\n * The same facts used to be restated in five places: the kind union here, a kind\n * Set and `kind:key` encoding in the Node resolver, another `getProjectIdentityKey`\n * in the session index, a private group key in analytics, and a third copy in the\n * web adapter. Adding a kind meant editing all of them, and nothing failed if one\n * was missed.\n *\n * This module owns the closed set, the identity key, and identity comparison.\n * Discovering identities from the filesystem lives in `projects/identity.ts`;\n * encoding them into URLs lives in the web adapter. Both sit outside this one.\n */\n\n/**\n * Every kind of project identity, most specific first. The order is documentation,\n * not behavior. These values appear in SQLite rows and API responses, so they\n * cannot be renamed without a migration.\n */\nexport const PROJECT_IDENTITY_KINDS = [\n \"git_remote\",\n \"git_common_dir\",\n \"manifest_path\",\n \"synthetic\",\n \"path\",\n \"loose\",\n] as const;\n\nexport type ProjectIdentityKind = (typeof PROJECT_IDENTITY_KINDS)[number];\n\nexport interface ProjectIdentityRef {\n kind: ProjectIdentityKind;\n key: string;\n}\n\nconst KIND_LOOKUP = new Set<string>(PROJECT_IDENTITY_KINDS);\n\nexport function isProjectIdentityKind(value: string): value is ProjectIdentityKind {\n return KIND_LOOKUP.has(value);\n}\n\n/**\n * Stable key for grouping and lookup. This is not a URL: route encoding is a\n * separate adapter, and conflating the two would put an escaped key in storage.\n */\nexport function getProjectIdentityKey(identity: ProjectIdentityRef): string {\n return `${identity.kind}:${identity.key}`;\n}\n\nexport function matchesProjectIdentity(\n identity: ProjectIdentityRef | null | undefined,\n expected: ProjectIdentityRef,\n): boolean {\n return identity?.kind === expected.kind && identity.key === expected.key;\n}\n\n/** Key for one agent's slice of a project. */\nexport function getProjectAgentKey(projectIdentityKey: string, agentName: string): string {\n return `${projectIdentityKey}\\0${agentName.toLowerCase()}`;\n}\n","export interface SessionReference {\n agentName: string;\n sessionId: string;\n}\n\nexport const UNKNOWN_AGENT_NAME = \"unknown\";\n\nexport function normalizeSessionReference(reference: SessionReference): SessionReference {\n return {\n agentName: reference.agentName.trim().toLowerCase(),\n sessionId: reference.sessionId,\n };\n}\n\nexport function parseSessionReference(value: string): SessionReference | null {\n const separatorIndex = value.indexOf(\"/\");\n if (separatorIndex <= 0 || separatorIndex === value.length - 1) return null;\n\n const agentName = value.slice(0, separatorIndex).trim().toLowerCase();\n if (!agentName) return null;\n return {\n agentName,\n sessionId: value.slice(separatorIndex + 1),\n };\n}\n\nexport function formatSessionReference(reference: SessionReference): string {\n const normalized = normalizeSessionReference(reference);\n return `${normalized.agentName}/${normalized.sessionId}`;\n}\n\nexport function getSessionAgentKey(session: { slug: string }): string {\n return parseSessionReference(session.slug)?.agentName ?? UNKNOWN_AGENT_NAME;\n}\n\n/**\n * Canonical URL path for an agent. Callers must never concatenate the name\n * themselves: both routers match on the raw path, so an unencoded segment can\n * split, truncate, or turn into a query or fragment.\n */\nexport function agentRoutePath(agentName: string): string {\n return `/${encodeURIComponent(agentName.trim().toLowerCase())}`;\n}\n\n/**\n * Canonical URL path for a session reference, shared by web routes and HTTP\n * endpoints. Each segment is encoded independently, so an opaque id keeps `/`,\n * `?`, `#` and `%` intact through React Router and Hono alike.\n */\nexport function sessionRoutePath(reference: SessionReference): string {\n const normalized = normalizeSessionReference(reference);\n return `${agentRoutePath(normalized.agentName)}/${encodeURIComponent(normalized.sessionId)}`;\n}\n\n/** Same as {@link sessionRoutePath}, for callers holding a session head. */\nexport function getSessionRoutePath(session: { slug: string; id: string }): string {\n return sessionRoutePath({ agentName: getSessionAgentKey(session), sessionId: session.id });\n}\n","import type { ReferencedSessionHead, SessionHead } from \"./session.js\";\nimport { getProjectAgentKey, getProjectIdentityKey } from \"./project-identity.js\";\nimport {\n formatSessionReference,\n getSessionAgentKey,\n type SessionReference,\n} from \"./session-reference.js\";\n\nexport type SessionHeadChange = ReferencedSessionHead;\n\nexport type SessionHeadRemoval = SessionReference;\n\nexport interface CanonicalSessionIndex {\n sourceSessions: SessionHead[];\n sessionsByActivity: SessionHead[];\n byRouteKey: Map<string, SessionHead>;\n byAgent: Map<string, SessionHead[]>;\n byProjectIdentityKey: Map<string, SessionHead[]>;\n byProjectAgentKey: Map<string, SessionHead[]>;\n}\n\nexport function compareSessionActivityDesc(a: SessionHead, b: SessionHead): number {\n return (b.time_updated ?? b.time_created) - (a.time_updated ?? a.time_created);\n}\n\nexport function sortSessionsByActivity(sessions: SessionHead[]): SessionHead[] {\n for (let index = 1; index < sessions.length; index += 1) {\n if (compareSessionActivityDesc(sessions[index - 1]!, sessions[index]!) > 0) {\n return [...sessions].sort(compareSessionActivityDesc);\n }\n }\n return [...sessions];\n}\n\n/**\n * Merges shards that are each already sorted by activity, newest first.\n *\n * Callers must uphold that precondition — this does not re-sort. Ties resolve to\n * the earlier shard, which is what a stable `Array.sort` over the concatenation\n * would produce, so the result is element-for-element identical to\n * `sortSessionsByActivity(shards.flat())` at O(n·k) instead of O(n log n).\n */\nexport function mergeSortedSessions(shards: SessionHead[][]): SessionHead[] {\n const active = shards.filter((shard) => shard.length > 0);\n if (active.length === 0) return [];\n if (active.length === 1) return [...active[0]!];\n\n const total = active.reduce((sum, shard) => sum + shard.length, 0);\n const merged: SessionHead[] = [];\n const cursors = Array.from({ length: active.length }, () => 0);\n\n for (let position = 0; position < total; position += 1) {\n let pick = -1;\n for (let shard = 0; shard < active.length; shard += 1) {\n const cursor = cursors[shard]!;\n if (cursor >= active[shard]!.length) continue;\n if (\n pick === -1 ||\n compareSessionActivityDesc(active[shard]![cursor]!, active[pick]![cursors[pick]!]!) < 0\n ) {\n pick = shard;\n }\n }\n merged.push(active[pick]![cursors[pick]!]!);\n cursors[pick]! += 1;\n }\n\n return merged;\n}\n\nexport function getSessionRouteKey(agentName: string, sessionId: string): string {\n return formatSessionReference({ agentName, sessionId });\n}\n\nfunction pushMapValue<K, V>(map: Map<K, V[]>, key: K, value: V): void {\n const current = map.get(key);\n if (current) {\n current.push(value);\n } else {\n map.set(key, [value]);\n }\n}\n\nexport function createSessionIndex(sourceSessions: SessionHead[]): CanonicalSessionIndex {\n const byRouteKey = new Map<string, SessionHead>();\n const byAgent = new Map<string, SessionHead[]>();\n const byProjectIdentityKey = new Map<string, SessionHead[]>();\n const byProjectAgentKey = new Map<string, SessionHead[]>();\n\n for (const session of sourceSessions) {\n const agentName = getSessionAgentKey(session);\n const routeKey = getSessionRouteKey(agentName, session.id);\n if (!byRouteKey.has(routeKey)) byRouteKey.set(routeKey, session);\n }\n\n const sessionsByActivity = sortSessionsByActivity(sourceSessions);\n for (const session of sessionsByActivity) {\n const agentName = getSessionAgentKey(session);\n pushMapValue(byAgent, agentName, session);\n\n const identity = session.project_identity;\n if (!identity?.key) continue;\n\n const projectIdentityKey = getProjectIdentityKey(identity);\n pushMapValue(byProjectIdentityKey, projectIdentityKey, session);\n pushMapValue(byProjectAgentKey, getProjectAgentKey(projectIdentityKey, agentName), session);\n }\n\n return {\n sourceSessions,\n sessionsByActivity,\n byRouteKey,\n byAgent,\n byProjectIdentityKey,\n byProjectAgentKey,\n };\n}\n\nexport function applySessionChanges(\n sessions: SessionHead[],\n changes: SessionHeadChange[],\n removals: SessionHeadRemoval[],\n): SessionHead[] {\n const byRouteKey = new Map<string, SessionHead>();\n for (const session of sessions) {\n byRouteKey.set(getSessionRouteKey(getSessionAgentKey(session), session.id), session);\n }\n\n for (const removal of removals) {\n byRouteKey.delete(getSessionRouteKey(removal.agentName, removal.sessionId));\n }\n for (const change of changes) {\n byRouteKey.set(\n getSessionRouteKey(change.reference.agentName, change.reference.sessionId),\n change.session,\n );\n }\n\n return sortSessionsByActivity([...byRouteKey.values()]);\n}\n\nexport function updateSessionIndex(\n index: CanonicalSessionIndex,\n changes: SessionHeadChange[],\n removals: SessionHeadRemoval[],\n): CanonicalSessionIndex {\n return createSessionIndex(applySessionChanges(index.sourceSessions, changes, removals));\n}\n","import type { SessionHead } from \"./session.js\";\nimport { getSessionAgentKey } from \"./session-reference.js\";\n\nfunction referenceKey(reference: { agentName: string; sessionId: string }): string {\n return `${reference.agentName.trim().toLowerCase()}\\0${reference.sessionId}`;\n}\n\nfunction sessionKey(session: SessionHead): string {\n return `${getSessionAgentKey(session)}\\0${session.id}`;\n}\n\nfunction hasActivityInWindow(session: SessionHead, from?: number, to?: number): boolean {\n const activity = session.time_updated ?? session.time_created;\n return (from == null || activity >= from) && (to == null || activity <= to);\n}\n\nexport function isChildSession(session: SessionHead): boolean {\n return session.parent_reference != null;\n}\n\nexport function getRootSessions(sessions: SessionHead[]): SessionHead[] {\n return sessions.filter((session) => !session.parent_reference);\n}\n\n/**\n * Filters roots by activity and keeps every descendant of a matching root.\n * The input order is preserved so callers keep their existing sort behavior.\n */\nexport function filterSessionTreeByActivityWindow(\n sessions: SessionHead[],\n from?: number,\n to?: number,\n): SessionHead[] {\n if (from == null && to == null) return sessions;\n\n const available = new Set(sessions.map(sessionKey));\n const childrenByParent = new Map<string, string[]>();\n\n for (const session of sessions) {\n const parent = session.parent_reference;\n if (!parent || !available.has(referenceKey(parent))) continue;\n const parentKey = referenceKey(parent);\n const children = childrenByParent.get(parentKey);\n if (children) children.push(sessionKey(session));\n else childrenByParent.set(parentKey, [sessionKey(session)]);\n }\n\n const visible = new Set<string>();\n const pending = getRootSessions(sessions)\n .filter((session) => hasActivityInWindow(session, from, to))\n .map(sessionKey);\n\n while (pending.length > 0) {\n const key = pending.pop()!;\n if (visible.has(key)) continue;\n visible.add(key);\n for (const childKey of childrenByParent.get(key) ?? []) pending.push(childKey);\n }\n\n return sessions.filter((session) => visible.has(sessionKey(session)));\n}\n","import type { DashboardData } from \"./dashboard.js\";\nimport type { AgentScanStatus, ScanStatusEvent, SessionsUpdatedEvent } from \"./events.js\";\nimport type { SessionHead } from \"./session.js\";\n\nexport const SAMPLE_SESSION_HEAD = {\n id: \"session-1\",\n slug: \"claudecode/session-1\",\n title: \"Fix flaky search index test\",\n directory: \"/Users/dev/project\",\n project_identity: {\n kind: \"git_remote\",\n key: \"github.com/example/project\",\n displayName: \"example/project\",\n },\n time_created: 1_700_000_000_000,\n time_updated: 1_700_003_600_000,\n stats: {\n message_count: 12,\n total_input_tokens: 4200,\n total_output_tokens: 1800,\n total_cost: 0.042,\n cost_source: \"recorded\",\n total_tokens: 6000,\n total_cache_read_tokens: 3000,\n total_cache_create_tokens: 500,\n },\n model_usage: { \"claude-5-sonnet\": 6000 },\n smart_tags: [\"bugfix\"],\n smart_tags_source_updated_at: 1_700_003_600_000,\n} satisfies SessionHead;\n\nconst SAMPLE_AGENT_SCAN_STATUS = {\n agentName: \"claudecode\",\n status: \"complete\",\n total: 42,\n processed: 42,\n sessions: 42,\n startedAt: 1_700_000_000_000,\n updatedAt: 1_700_000_010_000,\n completedAt: 1_700_000_010_000,\n} satisfies AgentScanStatus;\n\nexport const SAMPLE_SCAN_STATUS_EVENT = {\n type: \"scan-status\",\n active: false,\n phase: \"idle\",\n pendingAgents: [],\n scanningAgents: [],\n completedAgents: [\"claudecode\"],\n agentStatuses: { claudecode: SAMPLE_AGENT_SCAN_STATUS },\n totalAgents: 1,\n startedAt: 1_700_000_000_000,\n updatedAt: 1_700_000_010_000,\n completedAt: 1_700_000_010_000,\n backfill: {\n active: false,\n pendingAgents: [],\n completedAgents: [\"claudecode\"],\n failedAgents: [],\n },\n} satisfies ScanStatusEvent;\n\nexport const SAMPLE_SESSIONS_UPDATED_EVENT = {\n type: \"sessions-updated\",\n changedAgents: [\"claudecode\"],\n newSessions: 1,\n updatedSessions: 0,\n removedSessions: 0,\n totalSessions: 43,\n timestamp: 1_700_000_020_000,\n changedSessionHeads: [\n {\n reference: { agentName: \"claudecode\", sessionId: SAMPLE_SESSION_HEAD.id },\n session: SAMPLE_SESSION_HEAD,\n },\n ],\n removedSessionRefs: [],\n} satisfies SessionsUpdatedEvent;\n\nexport const SAMPLE_DASHBOARD_DATA = {\n totals: {\n sessions: 1,\n messages: 12,\n tokens: 6000,\n cost: 0.042,\n cost_source: \"recorded\",\n latestActivity: 1_700_003_600_000,\n },\n perAgent: [\n {\n name: \"claudecode\",\n displayName: \"Claude Code\",\n icon: \"claude\",\n sessions: 1,\n messages: 12,\n tokens: 6000,\n },\n ],\n dailyActivity: [{ date: \"2023-11-14\", sessions: 1, messages: 12 }],\n dailyTokenActivity: [\n { date: \"2023-11-14\", input: 700, output: 1800, cache_read: 3000, cache_create: 500 },\n ],\n modelDistribution: [{ model: \"claude-5-sonnet\", tokens: 6000, sessions: 1 }],\n recentSessions: [\n {\n reference: { agentName: \"claudecode\", sessionId: SAMPLE_SESSION_HEAD.id },\n session: SAMPLE_SESSION_HEAD,\n },\n ],\n recentFileActivities: [],\n window: { from: 1_699_900_000_000, to: 1_700_003_600_000, days: 1 },\n} satisfies DashboardData;\n","import type { BaseAgent } from \"./base.js\";\nimport type { AgentInfo } from \"../types/index.js\";\n\nexport type AgentToolStrategy = \"custom\" | \"default\";\n\nexport interface AgentRegistration {\n create: () => BaseAgent;\n icon: string;\n /** Icon uses brand colors that work on both themes; render it as-is instead of tinting with currentColor. */\n iconColored?: boolean;\n resolveDataRoot: () => string | null;\n resumeCommandPrefix: string | null;\n toolStrategy: AgentToolStrategy;\n}\n\nexport type AgentRoots = Readonly<Record<string, string | null>>;\n\nlet registrations: AgentRegistration[] = [];\n\nexport function registerAgent(reg: AgentRegistration): void {\n registrations.push(reg);\n}\n\nexport function createRegisteredAgents(): BaseAgent[] {\n return registrations.map((r) => r.create());\n}\n\nexport function getRegisteredAgents(): readonly AgentRegistration[] {\n return registrations;\n}\n\nexport function resolveAgentRoots(): AgentRoots {\n return Object.fromEntries(\n registrations.map((registration) => [\n registration.create().name,\n registration.resolveDataRoot(),\n ]),\n );\n}\n\nexport function getAgentInfoMap(sessionsByAgent: Record<string, number>): AgentInfo[] {\n return registrations.map((registration) => {\n const agent = registration.create();\n return {\n name: agent.name,\n displayName: agent.displayName,\n icon: registration.icon,\n iconColored: registration.iconColored,\n resumeCommandPrefix: registration.resumeCommandPrefix,\n count: sessionsByAgent[agent.name] ?? 0,\n };\n });\n}\n","import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join, basename, dirname } from \"node:path\";\nimport {\n SingleFileSessionSource,\n filteredSession,\n getParsedSession,\n parsedSession,\n skippedSession,\n} from \"./base.js\";\nimport type { ParseSessionResult } from \"./base.js\";\nimport type {\n SessionHead,\n SessionDetail,\n Message,\n MessagePart,\n ToolPart,\n ToolPartState,\n} from \"../types/index.js\";\nimport { firstExisting, resolveHomePath } from \"../discovery/paths.js\";\nimport { readJsonlFile, readJsonlFileLines } from \"../utils/jsonl.js\";\nimport { basenameTitle, normalizeTitleText, resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport { isInternalEventType } from \"../utils/parse-cleanup.js\";\nimport { cleanInternalText } from \"../utils/session-normalization.js\";\nimport { estimateTokenCost } from \"../utils/cost.js\";\nimport { asArray, asNumber, asRecord, asString, reportFieldMismatch } from \"../utils/narrow.js\";\nimport {\n matchesScanWindow,\n type AgentScanOptions,\n type FileSessionMeta,\n type SessionCacheMeta,\n type SessionSourceFile,\n type SessionSourceRef,\n} from \"./base.js\";\nimport { TranscriptBuilder, type TranscriptMessageInput } from \"./transcript-builder.js\";\n\nconst HEAD_INDEX_VERSION = \"claudecode-head-v4\";\n\nexport function resolveClaudeCodeDataRoot(): string {\n return resolveHomePath(\"CLAUDE_CONFIG_DIR\", \".claude\");\n}\n\ninterface ClaudeUsage {\n key: string;\n input: number;\n output: number;\n cacheRead: number;\n cacheCreate: number;\n}\n\ninterface SessionMeta extends FileSessionMeta {\n indexPath: string | null;\n indexMtimeMs: number | null;\n headIndexVersion: string;\n model: string | null | undefined;\n parentSessionId: string | null;\n}\n\ninterface ClaudeChildContext {\n sessionId: string;\n projectDir: string;\n parentSessionId: string | null;\n explicitTitle: string | null;\n metaMtimeMs: number | null;\n toolUseId: string | null;\n}\n\ninterface ClaudeChildContextCacheEntry {\n metaMtimeMs: number | null;\n context: ClaudeChildContext;\n}\n\nfunction parseTimestampMs(data: Record<string, unknown>): number {\n const raw = data[\"timestamp\"];\n const value = asString(raw);\n if (value === undefined) {\n if (raw !== undefined && raw !== null) reportFieldMismatch(\"claudecode\", \"timestamp\");\n return 0;\n }\n const trimmed = value.trim();\n if (!trimmed) return 0;\n try {\n return new Date(trimmed.includes(\"Z\") ? trimmed : trimmed + \"Z\").getTime();\n } catch {\n return 0;\n }\n}\n\n/** Reads a numeric usage field; a present-but-wrong-typed field is a schema drift signal. */\nfunction readUsageNumber(usage: Record<string, unknown>, field: string): number {\n const raw = usage[field];\n if (raw === undefined) return 0;\n const value = asNumber(raw);\n if (value === undefined) {\n reportFieldMismatch(\"claudecode\", `message.usage.${field}`);\n return 0;\n }\n return value;\n}\n\nfunction extractClaudeUsage(\n data: Record<string, unknown>,\n msg: Record<string, unknown>,\n): ClaudeUsage | null {\n const rawUsage = msg[\"usage\"];\n if (rawUsage === undefined || rawUsage === null) return null;\n\n const usage = asRecord(rawUsage);\n if (!usage) {\n reportFieldMismatch(\"claudecode\", \"message.usage\");\n return null;\n }\n\n const requestId = typeof data[\"requestId\"] === \"string\" ? data[\"requestId\"].trim() : \"\";\n const uuid = typeof data[\"uuid\"] === \"string\" ? data[\"uuid\"].trim() : \"\";\n const key = requestId || uuid;\n if (!key) return null;\n\n return {\n key,\n input: readUsageNumber(usage, \"input_tokens\"),\n output: readUsageNumber(usage, \"output_tokens\"),\n cacheRead: readUsageNumber(usage, \"cache_read_input_tokens\"),\n cacheCreate: readUsageNumber(usage, \"cache_creation_input_tokens\"),\n };\n}\n\nexport class ClaudeCodeAgent extends SingleFileSessionSource<SessionMeta> {\n readonly name = \"claudecode\";\n readonly displayName = \"Claude Code\";\n\n private basePath: string | null = null;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private sessionsIndexCache: Record<string, any> = {};\n private sessionsIndexMtime: Record<string, number | null> = {};\n private childContextsBySource = new Map<string, ClaudeChildContext>();\n private childContextCache = new Map<string, ClaudeChildContextCacheEntry>();\n private childSessionIdByToolUseId = new Map<string, string>();\n private childIndexReady = false;\n\n private findBasePath(): string | null {\n return firstExisting(join(resolveClaudeCodeDataRoot(), \"projects\"), \"data/claudecode\");\n }\n\n getSessionWatchPlan() {\n const dataRoot = resolveClaudeCodeDataRoot();\n return {\n status: \"supported\" as const,\n targets: [{ root: dataRoot, path: join(dataRoot, \"projects\") }, { path: \"data/claudecode\" }],\n };\n }\n\n isAvailable(): boolean {\n this.basePath = this.findBasePath();\n if (!this.basePath) return false;\n try {\n for (const entry of readdirSync(this.basePath)) {\n const dir = join(this.basePath, entry);\n if (existsSync(dir) && readdirSync(dir).some((f) => f.endsWith(\".jsonl\"))) {\n return true;\n }\n }\n } catch {\n // ignore\n }\n return false;\n }\n\n listSessionSources(options?: AgentScanOptions): SessionSourceRef[] {\n if (!this.basePath) return [];\n const projectDirs = this.listProjectDirs();\n const indexMtimes = new Map<string, number | null>();\n for (const projectDir of projectDirs) {\n const indexPath = this.getSessionsIndexPath(projectDir);\n indexMtimes.set(projectDir, this.readFileMtimeMs(indexPath));\n }\n\n const projectDirSet = new Set(projectDirs);\n const allSources = this.walkFiles(projectDirs, (entry) => entry.name.endsWith(\".jsonl\"), {\n recursive: true,\n });\n this.indexChildContexts(allSources, projectDirs);\n const indexedSources = allSources.flatMap((source) => {\n const child = this.childContextsBySource.get(source.file);\n if (!child && !projectDirSet.has(dirname(source.file))) return [];\n return [\n {\n source,\n sessionId: child?.sessionId ?? basename(source.file, \".jsonl\"),\n child,\n },\n ];\n });\n let selectedSources = indexedSources.filter(({ source }) =>\n matchesScanWindow(source.stat.mtimeMs, options),\n );\n\n if (options?.from != null || options?.to != null) {\n type IndexedSource = (typeof indexedSources)[number];\n const childrenByParent = new Map<string, IndexedSource[]>();\n for (const indexed of indexedSources) {\n const parentId = indexed.child?.parentSessionId;\n if (!parentId) continue;\n const children = childrenByParent.get(parentId);\n if (children) children.push(indexed);\n else childrenByParent.set(parentId, [indexed]);\n }\n\n const windowSelectedById = new Map(\n selectedSources.map((indexed) => [indexed.sessionId, indexed]),\n );\n const connectedSelected = new Map<string, IndexedSource>();\n const acceptedIds = new Set<string>();\n const visitingIds = new Set<string>();\n const hasSelectedParent = (sessionId: string): boolean => {\n if (acceptedIds.has(sessionId)) return true;\n if (visitingIds.has(sessionId)) return false;\n\n const indexed = windowSelectedById.get(sessionId);\n if (!indexed) return false;\n const parentId = indexed.child?.parentSessionId;\n if (!parentId) {\n acceptedIds.add(sessionId);\n return true;\n }\n\n visitingIds.add(sessionId);\n const connected = hasSelectedParent(parentId);\n visitingIds.delete(sessionId);\n if (connected) acceptedIds.add(sessionId);\n return connected;\n };\n\n for (const indexed of selectedSources) {\n if (hasSelectedParent(indexed.sessionId)) {\n connectedSelected.set(indexed.sessionId, indexed);\n }\n }\n\n if (options?.includeRelatedSessions !== false) {\n const pending = [...connectedSelected.values()]\n .filter(({ child }) => !child?.parentSessionId)\n .map(({ sessionId }) => sessionId);\n while (pending.length > 0) {\n const parentId = pending.pop()!;\n for (const child of childrenByParent.get(parentId) ?? []) {\n if (connectedSelected.has(child.sessionId)) continue;\n connectedSelected.set(child.sessionId, child);\n pending.push(child.sessionId);\n }\n }\n }\n\n selectedSources = [...connectedSelected.values()];\n }\n\n return selectedSources.map(({ source: { file, stat }, sessionId, child }) => {\n const projectDir = child?.projectDir ?? dirname(file);\n return {\n sessionId,\n sourcePath: file,\n fingerprint: this.sourceFingerprint(\n stat,\n indexMtimes.get(projectDir) ?? null,\n child?.metaMtimeMs,\n ),\n };\n });\n }\n\n setSessionMetaMap(meta: Map<string, SessionCacheMeta>): void {\n super.setSessionMetaMap(meta);\n this.childContextsBySource.clear();\n this.childSessionIdByToolUseId.clear();\n this.childIndexReady = false;\n }\n\n protected parseFileSessionHead(sourcePath: string): SessionHead | null {\n const child = this.getChildContext(sourcePath);\n const projectDir = child?.projectDir ?? dirname(sourcePath);\n return getParsedSession(this.parseSessionHeadResult(sourcePath, projectDir, child));\n }\n\n getSessionData(sessionId: string): SessionDetail {\n const meta = this.sessionMetaMap.get(sessionId);\n if (!meta) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n if (!existsSync(meta.sourcePath)) {\n throw new Error(`Session file missing: ${meta.sourcePath}`);\n }\n\n this.ensureChildIndex();\n const builder = new TranscriptBuilder();\n const assistantUuidToToolCalls = new Map<string, string[]>();\n const countedUsageKeys = new Set<string>();\n for (const record of readJsonlFile(meta.sourcePath)) {\n try {\n this.convertRecord(\n record,\n builder,\n assistantUuidToToolCalls,\n countedUsageKeys,\n this.childSessionIdByToolUseId,\n );\n } catch {\n // skip malformed records\n }\n }\n\n const transcript = builder.finish();\n\n return {\n reference: { agentName: this.name, sessionId: meta.id },\n id: meta.id,\n title: meta.title,\n slug: `claudecode/${meta.id}`,\n directory: meta.directory,\n parent_reference:\n meta.parentSessionId == null\n ? undefined\n : { agentName: this.name, sessionId: meta.parentSessionId },\n version: undefined,\n time_created: meta.createdAt,\n time_updated: meta.updatedAt,\n stats: transcript.stats,\n messages: transcript.messages,\n };\n }\n\n // --- Private helpers ---\n\n private listProjectDirs(): string[] {\n if (!this.basePath) return [];\n try {\n return readdirSync(this.basePath)\n .map((e) => join(this.basePath!, e))\n .filter((p) => existsSync(p));\n } catch {\n return [];\n }\n }\n\n private ensureChildIndex(): void {\n if (this.childIndexReady) return;\n this.basePath ??= this.findBasePath();\n if (!this.basePath) {\n this.childIndexReady = true;\n return;\n }\n\n const projectDirs = this.listProjectDirs();\n this.indexChildContexts(\n this.walkFiles(projectDirs, (entry) => entry.name.endsWith(\".jsonl\"), {\n recursive: true,\n }),\n projectDirs,\n );\n }\n\n private indexChildContexts(\n sources: readonly SessionSourceFile[],\n projectDirs: readonly string[],\n ): void {\n this.childContextsBySource.clear();\n this.childSessionIdByToolUseId.clear();\n const projectDirSet = new Set(projectDirs);\n const contexts = new Map<string, ClaudeChildContext>();\n const knownSessionIds = new Set<string>();\n\n for (const source of sources) {\n const child = this.readChildContext(source.file);\n if (!child) {\n if (projectDirSet.has(dirname(source.file))) {\n knownSessionIds.add(basename(source.file, \".jsonl\"));\n }\n continue;\n }\n contexts.set(source.file, child);\n knownSessionIds.add(child.sessionId);\n }\n\n for (const [sourcePath, child] of contexts) {\n const parentSessionId =\n child.parentSessionId && knownSessionIds.has(child.parentSessionId)\n ? child.parentSessionId\n : null;\n const normalized =\n parentSessionId === child.parentSessionId ? child : { ...child, parentSessionId };\n this.childContextsBySource.set(sourcePath, normalized);\n if (child.toolUseId) {\n this.childSessionIdByToolUseId.set(child.toolUseId, normalized.sessionId);\n }\n }\n\n this.childIndexReady = true;\n }\n\n private getChildContext(sourcePath: string): ClaudeChildContext | null {\n const cached = this.childContextsBySource.get(sourcePath);\n if (cached) return cached;\n\n const child = this.readChildContext(sourcePath);\n if (!child) return null;\n this.childContextsBySource.set(sourcePath, child);\n if (child.toolUseId) {\n this.childSessionIdByToolUseId.set(child.toolUseId, child.sessionId);\n }\n return child;\n }\n\n private readChildContext(sourcePath: string): ClaudeChildContext | null {\n const subagentsDir = dirname(sourcePath);\n if (basename(subagentsDir) !== \"subagents\") return null;\n\n const parentDir = dirname(subagentsDir);\n // Claude stores nested transcripts flat here; parentAgentId carries the nesting relation.\n const projectDir = dirname(parentDir);\n const fileStem = basename(sourcePath, \".jsonl\");\n const metaPath = join(subagentsDir, fileStem + \".meta.json\");\n const metaMtimeMs = this.readFileMtimeMs(metaPath);\n const cached = this.childContextCache.get(sourcePath);\n if (cached?.metaMtimeMs === metaMtimeMs) return cached.context;\n\n let metadata: Record<string, unknown> | null = null;\n if (metaMtimeMs !== null) {\n try {\n metadata = asRecord(JSON.parse(readFileSync(metaPath, \"utf-8\"))) ?? null;\n } catch {\n // Child transcripts can outlive their metadata during an interrupted spawn.\n }\n }\n\n const sessionId = asString(metadata?.[\"agentId\"])?.trim() || fileStem.replace(/^agent-/, \"\");\n if (!sessionId) return null;\n\n const parentAgentId = asString(metadata?.[\"parentAgentId\"])?.trim();\n const candidateParentId = parentAgentId || basename(parentDir) || null;\n const parentSessionId =\n candidateParentId && this.hasChildParent(sourcePath, projectDir, candidateParentId)\n ? candidateParentId\n : null;\n const name = asString(metadata?.[\"name\"])?.trim();\n const description = asString(metadata?.[\"description\"])?.trim();\n\n const context = {\n sessionId,\n projectDir,\n parentSessionId,\n explicitTitle: name || description || null,\n metaMtimeMs,\n toolUseId: asString(metadata?.[\"toolUseId\"])?.trim() || null,\n };\n this.childContextCache.set(sourcePath, { metaMtimeMs, context });\n return context;\n }\n\n private hasChildParent(sourcePath: string, projectDir: string, parentSessionId: string): boolean {\n const subagentsDir = dirname(sourcePath);\n return [\n join(projectDir, parentSessionId + \".jsonl\"),\n join(subagentsDir, \"agent-\" + parentSessionId + \".jsonl\"),\n join(subagentsDir, parentSessionId + \".jsonl\"),\n ].some((path) => existsSync(path));\n }\n\n protected createFileSessionMeta(head: SessionHead, source: SessionSourceFile): SessionMeta {\n const child = this.getChildContext(source.file);\n const projectDir = child?.projectDir ?? dirname(source.file);\n const indexPath = this.getSessionsIndexPath(projectDir);\n const indexMtime = this.readFileMtimeMs(indexPath);\n return this.buildFileSessionMeta({\n head,\n source,\n fingerprint: this.sourceFingerprint(source.stat, indexMtime, child?.metaMtimeMs),\n extras: {\n indexPath: indexMtime === null ? null : indexPath,\n indexMtimeMs: indexMtime,\n headIndexVersion: HEAD_INDEX_VERSION,\n model: head.stats.total_tokens ? \"unknown\" : undefined,\n parentSessionId: head.parent_reference?.sessionId ?? null,\n },\n });\n }\n\n /** Fingerprint depends on an already-fetched stat to avoid re-statting the same file. */\n private sourceFingerprint(\n stat: { mtimeMs: number; size: number },\n indexMtime: number | null,\n metaMtime?: number | null,\n ): string {\n const fingerprint = [HEAD_INDEX_VERSION, stat.mtimeMs, stat.size, indexMtime];\n if (metaMtime !== undefined) fingerprint.push(metaMtime);\n return JSON.stringify(fingerprint);\n }\n\n private getSessionsIndexPath(projectDir: string): string {\n return join(projectDir, \"sessions-index.json\");\n }\n\n private loadSessionsIndex(projectDir: string): Map<string, Record<string, unknown>> {\n const cacheKey = basename(projectDir);\n const indexPath = this.getSessionsIndexPath(projectDir);\n const mtime = this.readFileMtimeMs(indexPath);\n\n // Invalidate when the index file mtime advances so long-running processes\n // pick up title changes without relying on callers to evict manually.\n if (cacheKey in this.sessionsIndexCache && this.sessionsIndexMtime[cacheKey] === mtime) {\n return this.sessionsIndexCache[cacheKey];\n }\n\n const map = new Map<string, Record<string, unknown>>();\n\n if (existsSync(indexPath)) {\n try {\n const data = JSON.parse(readFileSync(indexPath, \"utf-8\"));\n const entries: Record<string, unknown>[] = data?.entries ?? [];\n for (const entry of entries) {\n const sid = entry?.sessionId;\n if (typeof sid === \"string\") {\n map.set(sid, entry);\n }\n }\n } catch {\n // ignore\n }\n }\n\n this.sessionsIndexCache[cacheKey] = map;\n this.sessionsIndexMtime[cacheKey] = mtime;\n return map;\n }\n\n private parseSessionHeadResult(\n filePath: string,\n projectDir: string,\n child?: ClaudeChildContext | null,\n ): ParseSessionResult<SessionHead> {\n const sessionId = child?.sessionId ?? basename(filePath, \".jsonl\");\n\n // Try to get title from sessions-index.json\n const index = this.loadSessionsIndex(projectDir);\n const indexEntry = index.get(sessionId);\n const explicitTitle =\n child?.explicitTitle ?? (indexEntry?.summary ? String(indexEntry.summary) : null);\n\n // Extract lightweight metadata; cwd lives in user-type records, not the first line\n let createdAt = 0;\n let updatedAt = 0;\n let lineIndex = 0;\n let messageCount = 0;\n let model: string | null = null;\n let cwd: string | null = null;\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCacheReadTokens = 0;\n let totalCacheCreateTokens = 0;\n let totalCost = 0;\n const modelUsageMap: Record<string, number> = {};\n const countedUsageKeys = new Set<string>();\n let messageTitle: string | null = null;\n\n for (const line of readJsonlFileLines(filePath)) {\n let data: Record<string, unknown>;\n try {\n data = JSON.parse(line) as Record<string, unknown>;\n } catch {\n // A malformed opening record means the file is not a session we can read;\n // later ones are individually skippable.\n if (lineIndex === 0) return skippedSession(\"malformed first record\");\n lineIndex += 1;\n continue;\n }\n\n if (lineIndex === 0) {\n createdAt = parseTimestampMs(data) || statSync(filePath).mtimeMs;\n updatedAt = createdAt;\n }\n const recordIndex = lineIndex;\n lineIndex += 1;\n\n try {\n if (isInternalEventType(data[\"type\"])) continue;\n const ts = parseTimestampMs(data);\n if (ts > updatedAt) updatedAt = ts;\n\n if (!cwd && data[\"cwd\"] && typeof data[\"cwd\"] === \"string\") {\n cwd = data[\"cwd\"];\n }\n\n const msg = asRecord(data[\"message\"]);\n if (!msg && data[\"message\"] !== undefined && data[\"message\"] !== null) {\n reportFieldMismatch(\"claudecode\", \"message\");\n }\n if (msg) {\n const role = asString(msg[\"role\"]);\n if (msg[\"role\"] !== undefined && role === undefined) {\n reportFieldMismatch(\"claudecode\", \"message.role\");\n }\n if (role?.trim()) {\n messageCount++;\n }\n if (!model) {\n const m = asString(msg[\"model\"]);\n if (m?.trim()) model = m.trim();\n }\n // Title fallback mirrors the removed extractTitle(): first non-empty\n // visible user text within the first 20 lines.\n if (messageTitle === null && recordIndex < 20 && role === \"user\") {\n const candidate = this.extractUserMessageTitle(msg[\"content\"]);\n if (candidate) messageTitle = candidate;\n }\n if (role === \"assistant\") {\n const usage = extractClaudeUsage(data, msg);\n if (usage && !countedUsageKeys.has(usage.key)) {\n countedUsageKeys.add(usage.key);\n const inputTokens = usage.input;\n const cacheRead = usage.cacheRead;\n const cacheCreate = usage.cacheCreate;\n const outputTokens = usage.output;\n\n totalInputTokens += inputTokens + cacheRead + cacheCreate;\n totalOutputTokens += outputTokens;\n totalCacheReadTokens += cacheRead;\n totalCacheCreateTokens += cacheCreate;\n\n const m = asString(msg[\"model\"]);\n if (m?.trim()) {\n const name = m.trim();\n const msgTotal = inputTokens + cacheRead + cacheCreate + outputTokens;\n modelUsageMap[name] = (modelUsageMap[name] ?? 0) + msgTotal;\n const cost = estimateTokenCost(name, {\n input: inputTokens + cacheRead + cacheCreate,\n output: outputTokens,\n cache_read: cacheRead,\n cache_create: cacheCreate,\n });\n if (cost !== null) totalCost += cost;\n }\n }\n }\n }\n } catch {\n // skip\n }\n }\n\n if (lineIndex === 0) return skippedSession(\"empty file\");\n\n const directory = cwd ?? projectDir;\n const directoryTitle = basenameTitle(directory) || basenameTitle(projectDir);\n\n const title = resolveSessionTitle(explicitTitle, messageTitle, directoryTitle);\n\n const hasModelUsage = Object.keys(modelUsageMap).length > 0;\n if (messageCount === 0) return filteredSession(\"no visible messages\");\n\n return parsedSession({\n id: sessionId,\n slug: `claudecode/${sessionId}`,\n title,\n directory,\n parent_reference:\n child?.parentSessionId == null\n ? undefined\n : { agentName: this.name, sessionId: child.parentSessionId },\n time_created: createdAt,\n time_updated: updatedAt,\n stats: {\n message_count: messageCount,\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cost: totalCost,\n cost_source: totalCost > 0 ? \"estimated\" : undefined,\n total_cache_read_tokens: totalCacheReadTokens,\n total_cache_create_tokens: totalCacheCreateTokens,\n },\n model_usage: hasModelUsage ? modelUsageMap : undefined,\n });\n }\n\n /** Mirrors the title-candidate extraction previously done in a second JSON.parse pass. */\n private extractUserMessageTitle(content: unknown): string | null {\n if (!content) return null;\n\n if (typeof content === \"string\") {\n const title = normalizeTitleText(content);\n return title || null;\n }\n if (Array.isArray(content)) {\n const texts = content\n .filter((item): item is Record<string, unknown> => {\n const record = asRecord(item);\n return record !== undefined && \"text\" in record;\n })\n .map((item) => String(item[\"text\"] ?? \"\"))\n .join(\" \");\n const title = normalizeTitleText(texts);\n return title || null;\n }\n return null;\n }\n\n // --- Record conversion ---\n\n private convertRecord(\n data: Record<string, unknown>,\n builder: TranscriptBuilder,\n assistantUuidToToolCalls: Map<string, string[]>,\n countedUsageKeys: Set<string>,\n childSessionIdByToolUseId: ReadonlyMap<string, string>,\n ): void {\n if (data[\"isMeta\"] === true) return;\n\n const msgType = String(data[\"type\"] ?? \"\");\n if (isInternalEventType(msgType)) return;\n\n if (msgType === \"assistant\") {\n this.convertAssistantRecord(\n data,\n builder,\n assistantUuidToToolCalls,\n countedUsageKeys,\n childSessionIdByToolUseId,\n );\n } else if (msgType === \"user\") {\n this.convertUserRecord(data, builder, assistantUuidToToolCalls);\n } else if (msgType === \"tool_result\") {\n this.convertToolResultRecord(data, builder);\n }\n }\n\n private convertAssistantRecord(\n data: Record<string, unknown>,\n builder: TranscriptBuilder,\n assistantUuidToToolCalls: Map<string, string[]>,\n countedUsageKeys: Set<string>,\n childSessionIdByToolUseId: ReadonlyMap<string, string>,\n ): void {\n const msg = asRecord(data[\"message\"]) ?? {};\n const timestampMs = parseTimestampMs(data);\n const rawContent = asArray(msg[\"content\"]) ?? [];\n const uuid = String(data[\"uuid\"] ?? \"\");\n\n const toolCallIds: string[] = [];\n for (const item of rawContent) {\n const part = asRecord(item);\n if (!part) continue;\n const partType = String(part[\"type\"] ?? \"\");\n\n if (partType === \"thinking\") {\n const text = cleanInternalText(String(part[\"thinking\"] ?? \"\"));\n if (text) {\n const message = builder.appendAssistantPart(\n this.buildReasoningPart(text, timestampMs),\n { id: uuid, timestampMs, agent: \"claude\" },\n { deduplicateTail: true },\n );\n this.applyAssistantMetadata(message, data, msg, countedUsageKeys);\n }\n continue;\n }\n\n if (partType === \"text\") {\n const text = cleanInternalText(String(part[\"text\"] ?? \"\"));\n if (text) {\n const message = builder.appendAssistantPart(\n this.buildTextPart(text, timestampMs),\n {\n id: uuid,\n timestampMs,\n agent: \"claude\",\n },\n { deduplicateTail: true },\n );\n this.applyAssistantMetadata(message, data, msg, countedUsageKeys);\n }\n continue;\n }\n\n if (partType !== \"tool_use\") continue;\n\n const toolCallId = String(part[\"id\"] ?? \"\").trim();\n const subagentId = childSessionIdByToolUseId.get(toolCallId);\n\n const toolPart = this.buildToolPart(part, timestampMs);\n const message = builder.appendToolCall(\n toolPart,\n { id: uuid, timestampMs, agent: \"claude\", subagentId },\n { modeOnCreate: \"tool\" },\n );\n if (subagentId) message.subagent_id = subagentId;\n this.applyAssistantMetadata(message, data, msg, countedUsageKeys);\n if (toolCallId) {\n toolCallIds.push(toolCallId);\n }\n }\n\n if (toolCallIds.length > 0) {\n assistantUuidToToolCalls.set(uuid, toolCallIds);\n }\n }\n\n private convertUserRecord(\n data: Record<string, unknown>,\n builder: TranscriptBuilder,\n assistantUuidToToolCalls: Map<string, string[]>,\n ): void {\n const msg = asRecord(data[\"message\"]) ?? {};\n const timestampMs = parseTimestampMs(data);\n const content = msg[\"content\"] ?? \"\";\n const uuid = String(data[\"uuid\"] ?? \"\");\n\n // String content — simple user message\n if (typeof content === \"string\") {\n const parts = this.normalizeUserTextParts(content, timestampMs);\n if (parts.length === 0) {\n builder.beginTurn();\n return;\n }\n builder.appendMessage({ id: uuid, role: \"user\", timestampMs, parts });\n return;\n }\n\n if (!Array.isArray(content)) {\n builder.beginTurn();\n return;\n }\n\n const visibleParts = this.normalizeUserTextParts(content, timestampMs);\n const toolStateUpdates = this.extractToolStateUpdates(data[\"toolUseResult\"]);\n\n for (const item of content) {\n const ci = asRecord(item);\n if (!ci || ci[\"type\"] !== \"tool_result\") continue;\n\n const toolCallId = this.resolveToolCallId(data, ci, assistantUuidToToolCalls);\n\n const outputParts = this.normalizeClaudeToolOutput(ci[\"content\"], timestampMs);\n if (this.backfillToolOutput(builder, toolCallId, outputParts, toolStateUpdates)) {\n continue;\n }\n\n const fallback = this.buildFallbackToolMessage({\n messageId: uuid,\n timestampMs,\n toolCallId,\n outputParts,\n });\n if (fallback) builder.appendMessage(fallback);\n }\n\n if (visibleParts.length > 0) {\n builder.appendMessage({ id: uuid, role: \"user\", timestampMs, parts: visibleParts });\n }\n\n builder.beginTurn();\n }\n\n private convertToolResultRecord(data: Record<string, unknown>, builder: TranscriptBuilder): void {\n const timestampMs = parseTimestampMs(data);\n const msg = asRecord(data[\"message\"]) ?? {};\n const outputParts = this.normalizeClaudeToolOutput(msg[\"content\"], timestampMs);\n const uuid = String(data[\"uuid\"] ?? \"\");\n\n const fallback = this.buildFallbackToolMessage({\n messageId: uuid,\n timestampMs,\n toolCallId: null,\n outputParts,\n });\n if (fallback) builder.appendMessage(fallback);\n builder.beginTurn();\n }\n\n private buildTextPart(text: string, timestampMs: number): MessagePart {\n return { type: \"text\", text, time_created: timestampMs };\n }\n\n private buildReasoningPart(text: string, timestampMs: number): MessagePart {\n return { type: \"reasoning\", text, time_created: timestampMs };\n }\n\n private buildToolPart(part: Record<string, unknown>, timestampMs: number): ToolPart {\n const toolName = String(part[\"name\"] ?? \"\");\n return {\n type: \"tool\",\n tool: toolName,\n callID: String(part[\"id\"] ?? \"\"),\n title: `Tool: ${toolName}`,\n state: {\n status: \"running\",\n input: part[\"input\"] ?? {},\n output: null,\n },\n time_created: timestampMs,\n };\n }\n\n private applyAssistantMetadata(\n message: Message,\n data: Record<string, unknown>,\n msg: Record<string, unknown>,\n countedUsageKeys: Set<string>,\n ): void {\n const model = msg[\"model\"];\n if (model && typeof model === \"string\" && !message.model) {\n message.model = model;\n }\n const usage = extractClaudeUsage(data, msg);\n if (usage && !message.tokens && !countedUsageKeys.has(usage.key)) {\n countedUsageKeys.add(usage.key);\n message.tokens = {\n input: usage.input + usage.cacheCreate + usage.cacheRead,\n output: usage.output,\n cache_read: usage.cacheRead,\n cache_create: usage.cacheCreate,\n };\n const cost = estimateTokenCost(message.model, message.tokens);\n if (cost !== null) {\n message.cost = cost;\n message.cost_source = \"estimated\";\n }\n }\n }\n\n // --- User content normalization ---\n\n private normalizeUserTextParts(content: unknown, timestampMs: number): MessagePart[] {\n if (typeof content === \"string\") {\n const text = cleanInternalText(content);\n return text ? [this.buildTextPart(text, timestampMs)] : [];\n }\n if (!Array.isArray(content)) return [];\n\n const parts: MessagePart[] = [];\n for (const item of content) {\n const ci = asRecord(item);\n if (ci) {\n if (ci[\"type\"] === \"tool_result\") continue;\n const text = cleanInternalText(String(ci[\"text\"] ?? \"\"));\n if (text) parts.push(this.buildTextPart(text, timestampMs));\n } else if (typeof item === \"string\") {\n const text = cleanInternalText(item);\n if (text) parts.push(this.buildTextPart(text, timestampMs));\n }\n }\n return parts;\n }\n\n private normalizeClaudeToolOutput(content: unknown, timestampMs: number): MessagePart[] {\n if (typeof content === \"string\") {\n const text = cleanInternalText(content);\n return text ? [this.buildTextPart(text, timestampMs)] : [];\n }\n if (content === null || content === undefined) return [];\n\n if (Array.isArray(content)) {\n const parts: MessagePart[] = [];\n for (const item of content) {\n const itemRecord = asRecord(item);\n if (itemRecord) {\n const rawSource = itemRecord[\"source\"];\n if (itemRecord[\"type\"] === \"image\" && rawSource) {\n const source = asRecord(rawSource);\n const data = asString(source?.[\"data\"]) ?? \"\";\n const mimeType = asString(source?.[\"media_type\"]) ?? \"\";\n if (data && mimeType.startsWith(\"image/\")) {\n parts.push({ type: \"image\", data, mime_type: mimeType, time_created: timestampMs });\n }\n continue;\n }\n const text = String(itemRecord[\"text\"] ?? itemRecord[\"content\"] ?? \"\");\n const cleaned = cleanInternalText(text);\n if (cleaned) parts.push(this.buildTextPart(cleaned, timestampMs));\n } else if (typeof item === \"string\") {\n const text = cleanInternalText(item);\n if (text) parts.push(this.buildTextPart(text, timestampMs));\n }\n }\n return parts;\n }\n\n const text = cleanInternalText(String(content));\n return text ? [this.buildTextPart(text, timestampMs)] : [];\n }\n\n // --- Tool backfill ---\n\n private backfillToolOutput(\n builder: TranscriptBuilder,\n callId: string,\n outputParts: MessagePart[],\n stateUpdates?: Partial<Pick<ToolPartState, \"status\" | \"metadata\">>,\n ): boolean {\n if (!callId) return false;\n\n return builder.updateToolCall(callId, (part) => {\n const state = part.state;\n if (outputParts.length > 0) {\n const existing = state.output;\n if (Array.isArray(existing)) existing.push(...outputParts);\n else if (existing == null) state.output = [...outputParts];\n else state.output = [existing, ...outputParts];\n }\n if (stateUpdates?.status) state.status = stateUpdates.status;\n if (stateUpdates?.metadata !== undefined) state.metadata = stateUpdates.metadata;\n if (outputParts.length > 0 && state.status === \"running\") state.status = \"completed\";\n });\n }\n\n private resolveToolCallId(\n data: Record<string, unknown>,\n item: Record<string, unknown>,\n assistantUuidToToolCalls: Map<string, string[]>,\n ): string {\n const directId = String(item[\"tool_use_id\"] ?? \"\").trim();\n if (directId) return directId;\n\n const sourceUuid = String(data[\"sourceToolAssistantUUID\"] ?? \"\").trim();\n if (!sourceUuid) return \"\";\n\n const ids = assistantUuidToToolCalls.get(sourceUuid);\n if (ids && ids.length === 1) return ids[0]!;\n return \"\";\n }\n\n private extractToolStateUpdates(\n toolUseResult: unknown,\n ): Partial<Pick<ToolPartState, \"status\" | \"metadata\">> {\n const result = asRecord(toolUseResult);\n if (!result) return {};\n\n const updates: Partial<Pick<ToolPartState, \"status\" | \"metadata\">> = {};\n\n const success = result[\"success\"];\n if (typeof success === \"boolean\") {\n updates.status = success ? \"completed\" : \"error\";\n }\n\n const commandName = result[\"commandName\"];\n if (commandName) {\n updates.metadata = { commandName };\n }\n\n return updates;\n }\n\n // --- Fallback ---\n\n private buildFallbackToolMessage(opts: {\n messageId: string;\n timestampMs: number;\n toolCallId: string | null;\n outputParts: MessagePart[];\n }): TranscriptMessageInput | null {\n if (opts.outputParts.length === 0) return null;\n return {\n id: opts.messageId,\n role: \"tool\",\n timestampMs: opts.timestampMs,\n parts: opts.outputParts,\n };\n }\n}\n","import { existsSync, readdirSync, statSync, type Dirent, type Stats } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { SessionHead, SessionDetail, ParseSessionResult } from \"../types/index.js\";\nimport { getCoreDiagnostics } from \"../utils/diagnostics.js\";\n\nexport type { ParseSessionResult };\n\nexport function parsedSession<T>(session: T): ParseSessionResult<T> {\n return { status: \"parsed\", data: session };\n}\n\nexport function skippedSession<T>(reason: string): ParseSessionResult<T> {\n return { status: \"skipped\", reason };\n}\n\nexport function filteredSession<T>(reason: string): ParseSessionResult<T> {\n return { status: \"filtered\", reason };\n}\n\nexport function getParsedSession<T>(result: ParseSessionResult<T>): T | null {\n return result.status === \"parsed\" ? result.data : null;\n}\n\nexport interface SessionCacheMeta {\n id: string;\n sourcePath: string;\n [key: string]: unknown;\n}\n\nexport interface AgentScanOptions {\n from?: number;\n to?: number;\n fast?: boolean;\n includeRelatedSessions?: boolean;\n onProgress?: (progress: AgentScanProgress) => void;\n}\n\nexport interface AgentScanProgress {\n phase?: \"scanning\" | \"finalizing\";\n total?: number;\n processed?: number;\n sessions?: number;\n}\n\nexport interface FileWalkOptions {\n recursive?: boolean;\n scanWindow?: Pick<AgentScanOptions, \"from\" | \"to\">;\n}\n\nexport function matchesScanWindow(activityTime: number, options?: AgentScanOptions): boolean {\n if (options?.from != null && activityTime < options.from) return false;\n if (options?.to != null && activityTime > options.to) return false;\n return true;\n}\n\n/** 变更检测结果 */\nexport interface ChangeCheckResult {\n /** 是否有变更 */\n hasChanges: boolean;\n /** 可精确定位时的变更会话 ID;省略表示只能确认数据源发生过变化 */\n changedIds?: string[];\n /** 检测时间戳 */\n timestamp: number;\n /** 检测过程中已枚举的会话源(可选),供 incrementalScan 复用以避免二次枚举 */\n refs?: SessionSourceRef[];\n}\n\nexport interface SessionSourceRef {\n sessionId: string;\n sourcePath: string;\n fingerprint: string;\n}\n\nexport interface SessionSourceFile {\n file: string;\n stat: Stats;\n}\n\nexport interface FileSessionMeta extends SessionCacheMeta {\n id: string;\n title: string;\n sourcePath: string;\n sourceFingerprint: string;\n sourceMtimeMs: number;\n directory: string;\n messageCount: number;\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface SessionWatchTarget {\n /** Session source path whose related changes should trigger a refresh. */\n path: string;\n /** Stable ancestor to watch when the source path can be created or replaced. */\n root?: string;\n}\n\n/** `supported` may have no targets when the provider has no location in the current environment. */\nexport type SessionWatchPlan =\n | { status: \"supported\"; targets: SessionWatchTarget[] }\n | { status: \"unsupported\"; reason: string }\n | { status: \"not-needed\"; reason: string };\n\n/** What a source enumeration says needs re-parsing and what disappeared. */\nexport interface SessionSourceDiff {\n changedIds: string[];\n removedIds: string[];\n}\n\n/**\n * Cached meta reaches this comparison as a live Map on the main thread and as a\n * plain object over the worker's structured-clone boundary.\n */\nexport type CachedMetaLookup =\n | ReadonlyMap<string, SessionCacheMeta>\n | Record<string, SessionCacheMeta>;\n\nfunction readCachedMeta(meta: CachedMetaLookup, sessionId: string): SessionCacheMeta | undefined {\n if (meta instanceof Map) return meta.get(sessionId);\n return (meta as Record<string, SessionCacheMeta>)[sessionId];\n}\n\n/**\n * Fingerprints compare by exact string equality. Agents encode their head-index\n * and parser versions into the fingerprint precisely so that bumping either one\n * invalidates every cached head — a tolerant comparison would defeat that.\n */\nfunction fingerprintMatches(ref: SessionSourceRef, cached: SessionCacheMeta | undefined): boolean {\n return (\n typeof cached?.sourceFingerprint === \"string\" && cached.sourceFingerprint === ref.fingerprint\n );\n}\n\n/**\n * Decides whether a cached session was in scope for this enumeration pass, which\n * is what makes its absence from the refs mean \"deleted on disk\" rather than\n * \"outside the window\".\n *\n * `sourceMtimeMs` must hold the same quantity the agent's `listSessionSources`\n * window-filters on, or the two disagree and sessions are dropped or kept wrongly.\n *\n * When it is missing we cannot tell, and the two wrong answers are not\n * symmetric: wrongly removing destroys cached sessions and their messages, while\n * wrongly keeping leaves a stale entry that the next unwindowed pass clears. So\n * an unknown mtime means \"not enumerated\" — keep it.\n */\nfunction wasEnumeratedThisPass(\n cached: SessionCacheMeta | undefined,\n options: AgentScanOptions | undefined,\n): boolean {\n if (options?.from == null && options?.to == null) return true;\n const mtimeMs = cached?.sourceMtimeMs;\n return typeof mtimeMs === \"number\" && matchesScanWindow(mtimeMs, options);\n}\n\n/**\n * Single owner of \"which sources changed\" for file-backed agents. The main\n * thread reaches it through FileSystemSessionSource.checkForChanges; the\n * scan-refresh worker calls it directly, because it holds cached meta received\n * over workerData rather than a live agent metaMap.\n */\nexport function diffSessionSources(\n refs: SessionSourceRef[],\n cachedSessions: SessionHead[],\n cachedMeta: CachedMetaLookup,\n options?: AgentScanOptions,\n): SessionSourceDiff {\n const cachedIds = new Set(cachedSessions.map((session) => session.id));\n const enumeratedIds = new Set<string>();\n const changedIds: string[] = [];\n\n for (const ref of refs) {\n enumeratedIds.add(ref.sessionId);\n const meta = readCachedMeta(cachedMeta, ref.sessionId);\n // A ref with no cached session has to be parsed even when its meta matches:\n // the caller's session list is what the refresh merges into.\n const unchanged =\n cachedIds.has(ref.sessionId) &&\n meta?.sourcePath === ref.sourcePath &&\n fingerprintMatches(ref, meta);\n if (!unchanged) changedIds.push(ref.sessionId);\n }\n\n const removedIds: string[] = [];\n for (const session of cachedSessions) {\n if (enumeratedIds.has(session.id)) continue;\n if (!wasEnumeratedThisPass(readCachedMeta(cachedMeta, session.id), options)) continue;\n removedIds.push(session.id);\n }\n\n return { changedIds, removedIds };\n}\n\nexport abstract class BaseAgent {\n abstract readonly name: string;\n abstract readonly displayName: string;\n\n /** Check if this agent has data available on the local filesystem. */\n abstract isAvailable(): boolean;\n\n /** Scan for available sessions, returning lightweight metadata. */\n abstract scan(options?: AgentScanOptions): SessionHead[];\n\n /** Load full session data including all messages. */\n abstract getSessionData(sessionId: string): SessionDetail;\n\n /** Describe how changes to this agent's session sources can be observed. */\n abstract getSessionWatchPlan(): SessionWatchPlan;\n\n /**\n * 检查是否有变更(用于智能刷新)\n * @param sinceTimestamp 上次缓存时间戳\n * @param cachedSessions 缓存的会话列表\n * @returns 变更检测结果\n */\n abstract checkForChanges(\n sinceTimestamp: number,\n cachedSessions: SessionHead[],\n ): Promise<ChangeCheckResult> | ChangeCheckResult;\n\n /**\n * 增量扫描(仅扫描变更的会话)\n * @param cachedSessions 缓存的会话列表\n * @param changedIds 变更的会话 ID 列表\n * @returns 更新后的会话列表\n */\n abstract incrementalScan(\n cachedSessions: SessionHead[],\n changedIds: string[],\n refs?: SessionSourceRef[],\n ): Promise<SessionHead[]> | SessionHead[];\n\n filterCachedSessions(sessions: SessionHead[]): SessionHead[] {\n return sessions;\n }\n\n /** Get session metadata for caching. */\n abstract getSessionMetaMap(): Map<string, SessionCacheMeta>;\n\n /** Restore session metadata from cache. */\n abstract setSessionMetaMap(meta: Map<string, SessionCacheMeta>): void;\n\n getUri(sessionId: string): string {\n return `${this.name}://${sessionId}`;\n }\n}\n\n/**\n * 文件型 Agent 基类:每个会话对应磁盘上一个独立文件/目录。\n *\n * 子类只需实现两个文件级原语:\n * - listSessionSources(): 枚举所有源 + 计算指纹\n * - scanSessionSource(): 解析单个源(同时写入 metaMap)\n *\n * 变更检测 / 增量扫描 / metaMap 管理由本基类统一提供:\n * checkForChanges 用 listSessionSources 的指纹与缓存 metaMap 比对,\n * incrementalScan 对变更集合调用 scanSessionSource 重解析。\n * 两原语在各子类中复用同一个 sourceFingerprint 计算,故指纹精确比对即等价于变更检测。\n */\nexport abstract class FileSystemSessionSource<\n TMeta extends SessionCacheMeta = SessionCacheMeta,\n> extends BaseAgent {\n protected sessionMetaMap = new Map<string, TMeta>();\n private sourceFileStats = new Map<string, Stats>();\n\n /** 枚举所有会话源及其指纹。传入 options 时按 mtime 限定扫描窗口。 */\n abstract listSessionSources(options?: AgentScanOptions): SessionSourceRef[];\n\n /** 解析单个源并写入 metaMap,返回会话 head(解析失败/不可见返回 null)。 */\n abstract scanSessionSource(sourcePath: string, options?: AgentScanOptions): SessionHead | null;\n\n /**\n * 变更集合扩展:当某些会话变更会影响其他会话的派生数据时\n * (如 subagent 文件变更需要父会话重新聚合 token 统计),\n * 子类返回需要一并重解析的会话 ID 集合。默认无关联,原样返回。\n */\n expandChangedSessionIds(changedIds: string[], _refs?: SessionSourceRef[]): string[] {\n return changedIds;\n }\n\n scan(options?: AgentScanOptions): SessionHead[] {\n const sources = this.listSessionSources(options);\n const sessions: SessionHead[] = [];\n options?.onProgress?.({ total: sources.length, processed: 0, sessions: 0 });\n\n for (const [index, source] of sources.entries()) {\n try {\n const session = this.scanSessionSource(source.sourcePath, options);\n if (session) sessions.push(session);\n } catch (error) {\n getCoreDiagnostics()?.warn(\"agent.session_parse_failed\", {\n agentName: this.name,\n sourcePath: source.sourcePath,\n message: error instanceof Error ? error.message : String(error),\n });\n continue;\n } finally {\n options?.onProgress?.({\n total: sources.length,\n processed: index + 1,\n sessions: sessions.length,\n });\n }\n }\n\n return sessions;\n }\n\n getSessionMetaMap(): Map<string, SessionCacheMeta> {\n return this.sessionMetaMap as Map<string, SessionCacheMeta>;\n }\n\n setSessionMetaMap(meta: Map<string, SessionCacheMeta>): void {\n this.sessionMetaMap = meta as Map<string, TMeta>;\n }\n\n protected walkFiles(\n roots: string | readonly string[],\n isSessionFile: (entry: Dirent) => boolean,\n options: FileWalkOptions = {},\n ): SessionSourceFile[] {\n const files: SessionSourceFile[] = [];\n this.sourceFileStats.clear();\n\n const walk = (directory: string): void => {\n let entries: Dirent[];\n try {\n entries = readdirSync(directory, { withFileTypes: true });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n const filePath = join(directory, entry.name);\n if (entry.isDirectory()) {\n if (options.recursive !== false) walk(filePath);\n continue;\n }\n if (!isSessionFile(entry)) continue;\n\n let stat: Stats;\n try {\n stat = statSync(filePath);\n } catch {\n continue;\n }\n if (!matchesScanWindow(stat.mtimeMs, options.scanWindow)) continue;\n\n files.push({ file: filePath, stat });\n this.sourceFileStats.set(filePath, stat);\n }\n };\n\n for (const root of typeof roots === \"string\" ? [roots] : roots) walk(root);\n return files;\n }\n\n protected sessionSourceFile(sourcePath: string): SessionSourceFile {\n return {\n file: sourcePath,\n stat: this.sourceFileStats.get(sourcePath) ?? statSync(sourcePath),\n };\n }\n\n protected readFileMtimeMs(filePath: string | null): number | null {\n if (!filePath) return null;\n try {\n return statSync(filePath).mtimeMs;\n } catch {\n return null;\n }\n }\n\n /**\n * 变更检测:枚举当前源 → 交给 diffSessionSources 比对。\n * 新增、变更、删除三类统一产出 changedIds。\n */\n checkForChanges(_sinceTimestamp: number, cachedSessions: SessionHead[]): ChangeCheckResult {\n const currentRefs = this.listSessionSources();\n const diff = diffSessionSources(currentRefs, cachedSessions, this.sessionMetaMap);\n const changedIds = [...new Set([...diff.changedIds, ...diff.removedIds])];\n\n return {\n hasChanges: changedIds.length > 0,\n changedIds,\n timestamp: Date.now(),\n refs: currentRefs,\n };\n }\n\n /**\n * 增量扫描:对变更/新增源调用 scanSessionSource 重解析,\n * 删除已消失的源,合并回 cachedSessions。\n * refs 未传时回退为自行枚举,供独立调用方(如测试)沿用旧行为。\n */\n incrementalScan(\n cachedSessions: SessionHead[],\n changedIds: string[],\n refs?: SessionSourceRef[],\n ): SessionHead[] {\n const sources = refs ?? this.listSessionSources();\n const sessionMap = new Map(cachedSessions.map((session) => [session.id, session]));\n const changedSet = new Set(this.expandChangedSessionIds(changedIds, sources));\n const currentIds = new Set<string>();\n\n for (const ref of sources) {\n currentIds.add(ref.sessionId);\n if (!changedSet.has(ref.sessionId)) continue;\n const head = this.scanSessionSource(ref.sourcePath);\n if (head) {\n sessionMap.set(head.id, head);\n } else {\n sessionMap.delete(ref.sessionId);\n this.sessionMetaMap.delete(ref.sessionId);\n }\n }\n\n // Drop sessions flagged as changed but no longer present on disk.\n for (const id of changedSet) {\n if (!currentIds.has(id)) {\n sessionMap.delete(id);\n this.sessionMetaMap.delete(id);\n }\n }\n\n return [...sessionMap.values()];\n }\n}\n\n/** Shared scan template for agents whose session source is a single stat-able file. */\nexport abstract class SingleFileSessionSource<\n TMeta extends FileSessionMeta = FileSessionMeta,\n> extends FileSystemSessionSource<TMeta> {\n protected abstract parseFileSessionHead(\n sourcePath: string,\n options?: AgentScanOptions,\n ): SessionHead | null;\n\n protected abstract createFileSessionMeta(head: SessionHead, source: SessionSourceFile): TMeta;\n\n scanSessionSource(sourcePath: string, options?: AgentScanOptions): SessionHead | null {\n const head = this.parseFileSessionHead(sourcePath, options);\n if (head) {\n this.sessionMetaMap.set(\n head.id,\n this.createFileSessionMeta(head, this.sessionSourceFile(sourcePath)),\n );\n }\n return head;\n }\n\n protected buildFileSessionMeta<TExtra extends object>({\n head,\n source,\n fingerprint,\n extras,\n }: {\n head: SessionHead;\n source: SessionSourceFile;\n fingerprint: string;\n extras: TExtra;\n }): FileSessionMeta & TExtra {\n return {\n ...extras,\n id: head.id,\n title: head.title,\n sourcePath: source.file,\n sourceFingerprint: fingerprint,\n sourceMtimeMs: source.stat.mtimeMs,\n directory: head.directory,\n messageCount: head.stats.message_count,\n createdAt: head.time_created,\n updatedAt: head.time_updated ?? head.time_created,\n };\n }\n}\n\n/**\n * 数据库型 Agent 基类:所有会话聚合在单个 SQLite 数据库中,\n * 无法做 per-file 指纹,故变更检测退化为\"库文件 mtime 是否推进\",\n * 增量扫描退化为全量重扫。\n */\n/**\n * A scan that could not prove its result complete — the database would not\n * open, a table was missing, or a top-level query failed.\n *\n * This is not the same as an agent with no sessions. Callers must keep the last\n * successful snapshot: treating it as an empty result would diff every known\n * session into a removal and wipe the agent from cache, search and the UI.\n */\nexport class SessionScanError extends Error {\n constructor(\n readonly agentName: string,\n readonly stage: string,\n options?: { cause?: unknown },\n ) {\n super(`${agentName} session scan failed while ${stage}`, options);\n this.name = \"SessionScanError\";\n }\n}\n\n/**\n * Files that reflect committed data. `-shm` is deliberately absent: opening the\n * database read-only rewrites it, so including it would report a change after\n * every scan.\n */\nexport function sqliteSourceFiles(dbPath: string): string[] {\n return [dbPath, `${dbPath}-wal`];\n}\n\nfunction statOrNull(path: string): { size: number; mtimeMs: number } | null {\n try {\n return statSync(path);\n } catch {\n return null;\n }\n}\n\n/** Changes whenever committed data changes, and only then. */\nfunction sqliteSourceFingerprint(dbPath: string): string {\n return sqliteSourceFiles(dbPath)\n .map((path) => {\n const stats = statOrNull(path);\n return stats ? `${stats.size}:${Math.round(stats.mtimeMs)}` : \"-\";\n })\n .join(\"|\");\n}\n\nfunction latestSqliteSourceMtime(dbPath: string): number {\n return sqliteSourceFiles(dbPath).reduce((latest, path) => {\n const stats = statOrNull(path);\n return stats && stats.mtimeMs > latest ? stats.mtimeMs : latest;\n }, 0);\n}\n\nexport abstract class DatabaseSessionSource extends BaseAgent {\n protected sessionMetaMap = new Map<string, SessionCacheMeta>();\n private lastSourceFingerprint: string | null = null;\n\n /** 返回数据库文件路径(供 mtime 检测)。 */\n protected abstract getDatabasePath(): string | null;\n\n /** 记录单个会话的缓存 meta(sourcePath = dbPath)。 */\n protected rememberSession(sessionId: string): void {\n const dbPath = this.getDatabasePath();\n if (!dbPath) return;\n this.sessionMetaMap.set(sessionId, { id: sessionId, sourcePath: dbPath });\n }\n\n getSessionMetaMap(): Map<string, SessionCacheMeta> {\n return this.sessionMetaMap;\n }\n\n setSessionMetaMap(meta: Map<string, SessionCacheMeta>): void {\n this.sessionMetaMap = meta;\n }\n\n /**\n * 变更检测:数据库内部变更难以按行定位,按库文件集合的指纹判定。\n *\n * In WAL mode a commit appends to the sidecar and leaves the main file\n * untouched until checkpoint, so watching the database alone misses recent\n * writes entirely. Size is part of the fingerprint because an uncheckpointed\n * commit may land in the same millisecond as the previous one.\n */\n checkForChanges(sinceTimestamp: number, _cachedSessions: SessionHead[]): ChangeCheckResult {\n const dbPath = this.getDatabasePath();\n if (!dbPath || !existsSync(dbPath)) {\n return { hasChanges: false, timestamp: Date.now() };\n }\n\n try {\n const fingerprint = sqliteSourceFingerprint(dbPath);\n const previous = this.lastSourceFingerprint;\n this.lastSourceFingerprint = fingerprint;\n // Nothing to compare against on the first pass — fall back to the caller's\n // baseline, which also covers a WAL written while the process was down.\n const hasChanges =\n previous == null\n ? latestSqliteSourceMtime(dbPath) > sinceTimestamp\n : fingerprint !== previous;\n return {\n hasChanges,\n timestamp: Date.now(),\n };\n } catch {\n return { hasChanges: false, timestamp: Date.now() };\n }\n }\n\n /** 增量扫描:数据库型无法增量,直接全量重扫。 */\n incrementalScan(_cachedSessions: SessionHead[], _changedIds: string[]): SessionHead[] {\n return this.scan();\n }\n}\n","/**\n * Injectable diagnostics sink for core's failure paths. core stays\n * framework-agnostic (no logger dependency); hosts opt in by calling\n * setCoreDiagnostics once at startup. Default is a silent no-op so core's\n * behavior is unchanged for consumers that never inject one.\n */\n\nexport interface CoreDiagnostics {\n info?(event: string, detail?: Record<string, unknown>): void;\n warn(event: string, detail?: Record<string, unknown>): void;\n}\n\nlet diagnostics: CoreDiagnostics | null = null;\n\n/**\n * A host-injected sink that throws must not escape into core's own control\n * flow — e.g. abort a `FileSystemSessionSource.scan` loop or turn a cache\n * write's `catch { return null }` into an uncaught throw. Wrap once here so\n * every `diagnostics?.warn(...)` call site stays exception-safe for free.\n */\nfunction toSafeSink(sink: CoreDiagnostics): CoreDiagnostics {\n return {\n info(event, detail) {\n try {\n sink.info?.(event, detail);\n } catch {}\n },\n warn(event, detail) {\n try {\n sink.warn(event, detail);\n } catch {}\n },\n };\n}\n\nexport function setCoreDiagnostics(next: CoreDiagnostics | null): void {\n diagnostics = next ? toSafeSink(next) : null;\n}\n\nexport function getCoreDiagnostics(): CoreDiagnostics | null {\n return diagnostics;\n}\n","import { existsSync } from \"node:fs\";\nimport { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport function readEnvPath(name: string): string | null {\n const value = process.env[name];\n if (!value) return null;\n return value;\n}\n\nfunction firstExisting(...paths: string[]): string | null {\n for (const p of paths) {\n if (existsSync(p)) return p;\n }\n return null;\n}\n\nexport function resolveDataHome(): string {\n const xdg = readEnvPath(\"XDG_DATA_HOME\");\n if (xdg) return xdg;\n\n const p = platform();\n if (p === \"win32\") {\n return (\n readEnvPath(\"LOCALAPPDATA\") ?? readEnvPath(\"APPDATA\") ?? join(homedir(), \"AppData\", \"Local\")\n );\n }\n\n // macOS / Linux\n return join(homedir(), \".local\", \"share\");\n}\n\nexport function resolveHomePath(environmentVariable: string, fallbackDirectory: string): string {\n return readEnvPath(environmentVariable) ?? join(homedir(), fallbackDirectory);\n}\n\nexport { firstExisting };\n","import { closeSync, openSync, readSync } from \"node:fs\";\nimport { StringDecoder } from \"node:string_decoder\";\nimport { getCoreDiagnostics } from \"./diagnostics.js\";\n\nconst READ_CHUNK_BYTES = 1 << 20;\n\nexport function* parseJsonlLines(content: string): Generator<Record<string, unknown>> {\n let total = 0;\n let skipped = 0;\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n total += 1;\n try {\n yield JSON.parse(trimmed) as Record<string, unknown>;\n } catch {\n skipped += 1;\n }\n }\n // Reported after the generator is fully drained — a consumer that breaks\n // out of the loop early (e.g. to grab just the first line) never reaches\n // this point, so its skipped count goes unreported.\n if (skipped > 0) {\n getCoreDiagnostics()?.warn(\"agent.jsonl_lines_skipped\", { skipped, total });\n }\n}\n\n/**\n * Streams trimmed non-empty lines chunk by chunk so a session log is never\n * held in memory at once. Codex rollout files can exceed 400 MB; loading them\n * with readFileSync + split doubles that as UTF-16 strings and OOMs the\n * scan-refresh worker.\n */\nexport function* readJsonlFileLines(\n filePath: string,\n chunkBytes = READ_CHUNK_BYTES,\n): Generator<string> {\n const fd = openSync(filePath, \"r\");\n try {\n const buffer = Buffer.alloc(chunkBytes);\n // StringDecoder buffers multi-byte UTF-8 sequences split across chunks.\n const decoder = new StringDecoder(\"utf8\");\n // Chunks of the record currently being assembled, joined once when its line\n // break arrives. Concatenating onto a string instead would re-copy the whole\n // partial record on every chunk — quadratic on the multi-megabyte single-line\n // records agent logs routinely contain.\n let pending: string[] = [];\n let bytesRead = readSync(fd, buffer, 0, chunkBytes, -1);\n while (bytesRead > 0) {\n const decoded = decoder.write(buffer.subarray(0, bytesRead));\n const lastBreak = decoded.lastIndexOf(\"\\n\");\n if (lastBreak === -1) {\n if (decoded) pending.push(decoded);\n } else {\n pending.push(decoded.slice(0, lastBreak));\n const complete = pending.join(\"\");\n pending = [decoded.slice(lastBreak + 1)];\n for (const line of complete.split(\"\\n\")) {\n const trimmed = line.trim();\n if (trimmed) yield trimmed;\n }\n }\n bytesRead = readSync(fd, buffer, 0, chunkBytes, -1);\n }\n pending.push(decoder.end());\n const tail = pending.join(\"\").trim();\n if (tail) yield tail;\n } finally {\n closeSync(fd);\n }\n}\n\nexport function* readJsonlFile(filePath: string): Generator<Record<string, unknown>> {\n let total = 0;\n let skipped = 0;\n for (const line of readJsonlFileLines(filePath)) {\n total += 1;\n try {\n yield JSON.parse(line) as Record<string, unknown>;\n } catch {\n skipped += 1;\n }\n }\n // Same early-return caveat as parseJsonlLines above.\n if (skipped > 0) {\n getCoreDiagnostics()?.warn(\"agent.jsonl_lines_skipped\", { skipped, total, filePath });\n }\n}\n","import { basename } from \"node:path\";\nimport { cleanDisplayText } from \"./parse-cleanup.js\";\n\nconst TITLE_MAX_LENGTH = 100;\nconst UNTITLED_SESSION = \"Untitled Session\";\n\n/** Normalize extracted title text for display. */\nexport function normalizeTitleText(text: string): string | null {\n const visible =\n cleanDisplayText(text)\n ?.split(\"\\n\")\n .find((line) => line.trim())\n ?.trim() ?? null;\n if (!visible) return null;\n const cleaned = visible.replace(/\\s+/g, \" \").trim();\n if (!cleaned) return null;\n return cleaned.slice(0, TITLE_MAX_LENGTH);\n}\n\n/** Return a stable basename for fallback title. */\nexport function basenameTitle(path: string | null | undefined): string | null {\n if (!path) return null;\n const normalized = path.trim().replace(/[/\\\\]+$/, \"\");\n if (!normalized) return null;\n const name = basename(normalized).trim();\n return name || null;\n}\n\n/** Resolve final session title from explicit, message, and directory fallbacks. */\nexport function resolveSessionTitle(\n explicit: string | null | undefined,\n message: string | null | undefined,\n directory: string | null | undefined,\n): string {\n for (const candidate of [explicit, message, directory]) {\n if (candidate) {\n const normalized = normalizeTitleText(candidate);\n if (normalized) return normalized;\n }\n }\n return UNTITLED_SESSION;\n}\n","const INTERNAL_TAGS = [\n \"command-message\",\n \"command-name\",\n \"local-command-stdout\",\n \"system-reminder\",\n];\n\nconst INTERNAL_EVENT_TYPES = new Set([\n \"progress\",\n \"file history snapshot\",\n \"file-history snapshot\",\n \"file_history snapshot\",\n \"queue operation\",\n \"queue-operation\",\n \"queue_operation\",\n \"last prompt\",\n \"last-prompt\",\n \"last_prompt\",\n]);\n\nfunction blockTagPattern(tag: string): RegExp {\n return new RegExp(`<${tag}\\\\b[^>]*>[\\\\s\\\\S]*?<\\\\/${tag}>`, \"gi\");\n}\n\nfunction blockTagLinePattern(tag: string): RegExp {\n return new RegExp(\n `(^|\\\\r?\\\\n)[ \\\\t]*<${tag}\\\\b[^>]*>[\\\\s\\\\S]*?<\\\\/${tag}>[ \\\\t]*(?:\\\\r?\\\\n|$)`,\n \"gi\",\n );\n}\n\nfunction openBlockTagPattern(tag: string): RegExp {\n return new RegExp(`\\\\n*<${tag}\\\\b[^>]*>[\\\\s\\\\S]*$`, \"gi\");\n}\n\nfunction looseTagPattern(tag: string): RegExp {\n return new RegExp(`<\\\\/?${tag}\\\\b[^>]*>`, \"gi\");\n}\n\nexport function isInternalEventType(value: unknown): boolean {\n if (typeof value !== \"string\") return false;\n const normalized = value.trim().toLowerCase().replace(/[_-]+/g, \" \");\n return INTERNAL_EVENT_TYPES.has(normalized);\n}\n\nexport function cleanDisplayText(text: string): string | null {\n let cleaned = text;\n\n for (const tag of INTERNAL_TAGS) {\n cleaned = cleaned.replace(blockTagLinePattern(tag), \"$1\");\n cleaned = cleaned.replace(blockTagPattern(tag), \"\");\n cleaned = cleaned.replace(openBlockTagPattern(tag), \"\");\n }\n\n for (const tag of INTERNAL_TAGS) {\n cleaned = cleaned.replace(looseTagPattern(tag), \"\");\n }\n\n cleaned = cleaned.replace(/[ \\t]+(?=\\r?\\n|$)/g, \"\").replace(/(?:\\r?\\n)+$/g, \"\");\n\n return cleaned.trim() ? cleaned : null;\n}\n\nexport function firstVisibleLine(text: string): string | null {\n const cleaned = cleanDisplayText(text);\n if (!cleaned) return null;\n return (\n cleaned\n .split(\"\\n\")\n .find((line) => line.trim())\n ?.trim() ?? null\n );\n}\n","import type { Message, MessagePart } from \"../types/index.js\";\nimport {\n cleanDisplayText,\n isInternalEventType as isRawInternalEventType,\n} from \"./parse-cleanup.js\";\nimport { normalizeTitleText } from \"./title-fallback.js\";\n\nexport function isInternalEventType(value: unknown): boolean {\n return isRawInternalEventType(value);\n}\n\nexport function cleanInternalText(text: string): string {\n return cleanDisplayText(text) ?? \"\";\n}\n\nfunction cleanUnknown(value: unknown): unknown {\n if (typeof value === \"string\") return cleanInternalText(value);\n if (Array.isArray(value)) return value.map(cleanUnknown);\n if (!value || typeof value !== \"object\") return value;\n\n const cleaned: Record<string, unknown> = {};\n for (const [key, child] of Object.entries(value)) {\n cleaned[key] = cleanUnknown(child);\n }\n return cleaned;\n}\n\nexport function cleanMessagePart(part: MessagePart): MessagePart | null {\n if (part.type === \"text\" || part.type === \"reasoning\" || part.type === \"plan\") {\n const text = cleanInternalText(part.text);\n return text ? { ...part, text } : null;\n }\n if (part.type !== \"tool\") return part;\n\n const title = part.title ? cleanInternalText(part.title) : \"\";\n const state = {\n ...part.state,\n ...(part.state.input !== undefined ? { input: cleanUnknown(part.state.input) } : {}),\n ...(part.state.output !== undefined ? { output: cleanUnknown(part.state.output) } : {}),\n ...(part.state.error !== undefined ? { error: cleanUnknown(part.state.error) } : {}),\n ...(part.state.metadata !== undefined ? { metadata: cleanUnknown(part.state.metadata) } : {}),\n };\n const { title: _title, ...withoutTitle } = part;\n return {\n ...withoutTitle,\n ...(title ? { title } : {}),\n state,\n };\n}\n\nexport function cleanMessageParts(parts: MessagePart[]): MessagePart[] {\n return parts.flatMap((part) => {\n const cleaned = cleanMessagePart(part);\n return cleaned ? [cleaned] : [];\n });\n}\n\nexport function cleanParsedMessage(message: Message): Message | null {\n const parts = cleanMessageParts(message.parts);\n if (parts.length === 0) return null;\n return { ...message, parts };\n}\n\nexport function cleanParsedMessages(messages: Message[]): Message[] {\n return messages.flatMap((message) => {\n const cleaned = cleanParsedMessage(message);\n return cleaned ? [cleaned] : [];\n });\n}\n\nexport function firstUserMessageTitle(messages: Message[]): string | null {\n for (const message of messages) {\n if (message.role !== \"user\") continue;\n for (const part of message.parts) {\n if (part.type !== \"text\") continue;\n const title = normalizeTitleText(cleanInternalText(part.text));\n if (title) return title;\n }\n }\n return null;\n}\n","{\n \"anthropic--claude-4.6-opus\": \"claude-opus-4-6\",\n \"anthropic--claude-4.6-sonnet\": \"claude-sonnet-4-6\",\n \"claude-4.6-sonnet\": \"claude-sonnet-4-6\",\n \"anthropic--claude-4.5-opus\": \"claude-opus-4-5\",\n \"anthropic--claude-4.5-sonnet\": \"claude-sonnet-4-5\",\n \"anthropic--claude-4.5-haiku\": \"claude-haiku-4-5\",\n \"claude-4.5-sonnet-thinking\": \"claude-sonnet-4-5\",\n \"claude-4-sonnet-thinking\": \"claude-sonnet-4-5\",\n \"claude-4-opus\": \"claude-opus-4-5\",\n \"cursor-auto\": \"claude-sonnet-4-5\",\n \"cursor-agent-auto\": \"claude-sonnet-4-5\",\n \"copilot-auto\": \"claude-sonnet-4-5\",\n \"copilot-openai-auto\": \"gpt-5.3-codex\",\n \"copilot-anthropic-auto\": \"claude-sonnet-4-5\",\n \"kimi-for-coding\": \"moonshotai/kimi-k2-0905\",\n \"kimi-k2.5\": \"moonshotai/kimi-k2-0905\",\n \"moonshot-cn/kimi-k2.5\": \"moonshotai/kimi-k2-0905\",\n \"gpt-5-codex\": \"gpt-5\",\n \"gpt-5.1-codex-high\": \"gpt-5.3-codex\",\n \"gpt-5.2-low\": \"gpt-5.2\"\n}\n","import { existsSync, readFileSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { ensurePrivateDirectory, restrictPrivateFile } from \"../utils/private-storage.js\";\nimport { getCoreDiagnostics } from \"../utils/diagnostics.js\";\nimport snapshotData from \"./data/snapshot.json\";\n\nexport interface ModelPricing {\n inputCostPerToken: number;\n outputCostPerToken: number;\n cacheCreateCostPerToken: number;\n cacheReadCostPerToken: number;\n reasoningCostPerToken: number;\n webSearchCostPerRequest: number;\n}\n\ntype SnapshotEntry = [number, number, number | null, number | null, number?, number?];\n\ninterface LiteLLMEntry {\n input_cost_per_token?: number;\n output_cost_per_token?: number;\n cache_creation_input_token_cost?: number;\n cache_read_input_token_cost?: number;\n output_reasoning_cost_per_token?: number;\n web_search_cost_per_request?: unknown;\n search_context_cost_per_query?: unknown;\n}\n\nconst LITELLM_URL =\n \"https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json\";\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000;\nconst WEB_SEARCH_COST = 0.01;\nconst REFRESH_TIMEOUT_MS = 10_000;\n\n/**\n * A published set of prices. Estimates read one generation for as long as they\n * need it: a refresh landing mid-scan used to mean the first sessions of a scan\n * were priced differently from the last, with no record of which applied.\n */\nexport interface PricingGeneration {\n id: number;\n pricing: Map<string, ModelPricing>;\n}\n\nlet published: PricingGeneration = { id: 1, pricing: loadSnapshot() };\n/** A completed refresh waiting for a safe point to become current. */\nlet pending: Map<string, ModelPricing> | null = null;\nloadDiskCache();\n\nfunction normalizeKey(key: string): string {\n return key.trim().toLowerCase();\n}\n\nfunction costNumber(value: unknown, fallback: number): number {\n return typeof value === \"number\" && Number.isFinite(value) ? value : fallback;\n}\n\nfunction getCacheDir() {\n return join(homedir(), \".cache\", \"codesesh\");\n}\n\nfunction getCachePath() {\n return join(getCacheDir(), \"litellm-pricing.json\");\n}\n\nfunction loadSnapshot(): Map<string, ModelPricing> {\n const map = new Map<string, ModelPricing>();\n const snapshot = snapshotData as unknown as Record<string, SnapshotEntry>;\n for (const [name, entry] of Object.entries(snapshot)) {\n const [input, output, cacheCreate, cacheRead, reasoning, webSearch] = entry;\n map.set(normalizeKey(name), {\n inputCostPerToken: input,\n outputCostPerToken: output,\n cacheCreateCostPerToken: cacheCreate ?? input * 1.25,\n cacheReadCostPerToken: cacheRead ?? input * 0.1,\n reasoningCostPerToken: reasoning ?? output,\n webSearchCostPerRequest: webSearch ?? WEB_SEARCH_COST,\n });\n }\n return map;\n}\n\nfunction parseLiteLLMEntry(entry: LiteLLMEntry): ModelPricing | null {\n const input = entry.input_cost_per_token;\n const output = entry.output_cost_per_token;\n if (typeof input !== \"number\" || typeof output !== \"number\") return null;\n\n return {\n inputCostPerToken: input,\n outputCostPerToken: output,\n cacheCreateCostPerToken: entry.cache_creation_input_token_cost ?? input * 1.25,\n cacheReadCostPerToken: entry.cache_read_input_token_cost ?? input * 0.1,\n reasoningCostPerToken: entry.output_reasoning_cost_per_token ?? output,\n webSearchCostPerRequest: costNumber(\n entry.web_search_cost_per_request ?? entry.search_context_cost_per_query,\n WEB_SEARCH_COST,\n ),\n };\n}\n\nfunction normalizeCachedPricing(raw: Record<string, unknown>): ModelPricing | null {\n const input = costNumber(raw[\"inputCostPerToken\"], 0);\n const output = costNumber(raw[\"outputCostPerToken\"], 0);\n if (input <= 0 || output <= 0) return null;\n\n return {\n inputCostPerToken: input,\n outputCostPerToken: output,\n cacheCreateCostPerToken: costNumber(raw[\"cacheCreateCostPerToken\"], input * 1.25),\n cacheReadCostPerToken: costNumber(raw[\"cacheReadCostPerToken\"], input * 0.1),\n reasoningCostPerToken: costNumber(raw[\"reasoningCostPerToken\"], output),\n webSearchCostPerRequest: costNumber(raw[\"webSearchCostPerRequest\"], WEB_SEARCH_COST),\n };\n}\n\nfunction indexPricing(map: Map<string, ModelPricing>, name: string, pricing: ModelPricing) {\n const normalized = normalizeKey(name);\n map.set(normalized, pricing);\n\n const slashIndex = normalized.indexOf(\"/\");\n if (slashIndex >= 0) {\n const stripped = normalized.slice(slashIndex + 1);\n if (!map.has(stripped)) map.set(stripped, pricing);\n }\n}\n\nfunction parseLiteLLMData(data: Record<string, LiteLLMEntry>): Map<string, ModelPricing> {\n const map = new Map<string, ModelPricing>();\n for (const [name, entry] of Object.entries(data)) {\n const pricing = parseLiteLLMEntry(entry);\n if (pricing) indexPricing(map, name, pricing);\n }\n return map;\n}\n\nfunction loadDiskCache() {\n const path = getCachePath();\n if (!existsSync(path)) return;\n\n try {\n const cached = JSON.parse(readFileSync(path, \"utf-8\")) as {\n timestamp: number;\n data: Record<string, Record<string, unknown>>;\n };\n if (Date.now() - cached.timestamp <= CACHE_TTL_MS) {\n const next = loadSnapshot();\n for (const [name, rawPricing] of Object.entries(cached.data)) {\n const pricing = normalizeCachedPricing(rawPricing);\n if (!pricing) continue;\n next.set(normalizeKey(name), pricing);\n }\n published = { id: published.id + 1, pricing: next };\n }\n } catch {\n // ignore malformed cache\n }\n}\n\nexport function getPricingRegistry(): Map<string, ModelPricing> {\n return published.pricing;\n}\n\n/** The generation estimates are currently reading. */\nexport function getPricingGeneration(): PricingGeneration {\n return published;\n}\n\n/**\n * Makes a completed refresh current. Owners call this between scans, never\n * during one, so a scan cannot span two generations.\n */\nexport function publishPendingPricing(): boolean {\n if (!pending) return false;\n published = { id: published.id + 1, pricing: pending };\n pending = null;\n getCoreDiagnostics()?.info?.(\"pricing.generation.published\", {\n generation: published.id,\n models: published.pricing.size,\n });\n return true;\n}\n\n/** Whether a refresh is waiting to be published. */\nexport function hasPendingPricing(): boolean {\n return pending !== null;\n}\n\nexport function hasBillablePricing(pricing: ModelPricing): boolean {\n return (\n pricing.inputCostPerToken > 0 ||\n pricing.outputCostPerToken > 0 ||\n pricing.cacheReadCostPerToken > 0 ||\n pricing.cacheCreateCostPerToken > 0\n );\n}\n\n/** Replaces the cache in one step, so an interrupted write cannot truncate it. */\nfunction writeDiskCacheAtomically(path: string, pricing: Map<string, ModelPricing>): void {\n const temporaryPath = `${path}.${process.pid}.tmp`;\n const payload = JSON.stringify({ timestamp: Date.now(), data: Object.fromEntries(pricing) });\n try {\n ensurePrivateDirectory(getCacheDir());\n writeFileSync(temporaryPath, payload);\n restrictPrivateFile(temporaryPath);\n renameSync(temporaryPath, path);\n } catch (error) {\n rmSync(temporaryPath, { force: true });\n getCoreDiagnostics()?.warn(\"pricing.cache_write_failed\", {\n message: error instanceof Error ? error.message : String(error),\n });\n }\n}\n\nexport interface RefreshPricingOptions {\n /** Abort the request when it outlives a startup's patience. */\n signal?: AbortSignal;\n timeoutMs?: number;\n}\n\n/**\n * Fetches prices into a pending generation. It does not become current until\n * {@link publishPendingPricing}, so an in-flight scan keeps the prices it\n * started with.\n */\nexport async function refreshPricingCache(options: RefreshPricingOptions = {}): Promise<boolean> {\n const path = getCachePath();\n if (existsSync(path)) {\n try {\n const cached = JSON.parse(readFileSync(path, \"utf-8\")) as { timestamp?: number };\n if (typeof cached.timestamp === \"number\" && Date.now() - cached.timestamp <= CACHE_TTL_MS) {\n return false;\n }\n } catch {\n // refresh malformed cache\n }\n }\n\n const timeout = AbortSignal.timeout(options.timeoutMs ?? REFRESH_TIMEOUT_MS);\n const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout;\n\n getCoreDiagnostics()?.info?.(\"pricing.refresh.started\", { generation: published.id });\n try {\n const response = await fetch(LITELLM_URL, { signal });\n if (!response.ok) return false;\n const data = (await response.json()) as Record<string, LiteLLMEntry>;\n const remote = parseLiteLLMData(data);\n if (remote.size === 0) return false;\n\n const next = loadSnapshot();\n for (const [name, pricing] of remote.entries()) {\n next.set(name, pricing);\n }\n\n pending = next;\n writeDiskCacheAtomically(path, next);\n getCoreDiagnostics()?.info?.(\"pricing.refresh.completed\", {\n generation: published.id,\n models: next.size,\n });\n return true;\n } catch (error) {\n getCoreDiagnostics()?.warn(\"pricing.refresh.failed\", {\n generation: published.id,\n aborted: signal.aborted,\n message: error instanceof Error ? error.message : String(error),\n });\n return false;\n }\n}\n","/**\n * Owner-only permissions for the files CodeSesh writes.\n *\n * The session cache holds full transcripts; state holds bookmarks and aliases;\n * logs hold project paths and error detail. All of them were created under the\n * process umask, which is commonly 022 — so 0755 directories and 0644 files. On\n * a shared machine with a traversable home, another user could read them.\n *\n * POSIX modes do not apply on Windows, where `chmod` is a no-op; access there is\n * governed by the profile directory's ACL.\n */\nimport { chmodSync, existsSync, mkdirSync, readdirSync, statSync } from \"node:fs\";\nimport { basename, dirname, join } from \"node:path\";\nimport { getCoreDiagnostics } from \"./diagnostics.js\";\n\n/** Owner read/write/execute. */\nexport const PRIVATE_DIR_MODE = 0o700;\n/** Owner read/write. */\nexport const PRIVATE_FILE_MODE = 0o600;\n\n/** Sidecars SQLite creates next to a database, which carry the same data. */\nconst SQLITE_SIDECAR_SUFFIXES = [\"-wal\", \"-shm\", \"-journal\"];\n\nconst isPosix = process.platform !== \"win32\";\n\nfunction reportChmodFailure(path: string, error: unknown): void {\n getCoreDiagnostics()?.warn(\"storage.permissions_failed\", {\n path,\n message: error instanceof Error ? error.message : String(error),\n });\n}\n\n/** Narrows an existing path's permissions, reporting rather than throwing. */\nfunction restrict(path: string, mode: number): void {\n if (!isPosix || !existsSync(path)) return;\n try {\n // Skip the syscall when it would not change anything.\n if ((statSync(path).mode & 0o777) === mode) return;\n chmodSync(path, mode);\n } catch (error) {\n reportChmodFailure(path, error);\n }\n}\n\n/**\n * Creates a directory only its owner can enter, and tightens it if it existed.\n *\n * A failed mkdir propagates — the caller has nowhere to store anything. A failed\n * chmod does not: the directory is usable, just not as private as intended, and\n * that is reported instead.\n */\nexport function ensurePrivateDirectory(path: string): void {\n mkdirSync(path, { recursive: true, mode: PRIVATE_DIR_MODE });\n // `recursive` skips the mode for a directory that already existed.\n restrict(path, PRIVATE_DIR_MODE);\n}\n\n/** Narrows a file CodeSesh owns to owner-only. */\nexport function restrictPrivateFile(path: string): void {\n restrict(path, PRIVATE_FILE_MODE);\n}\n\n/**\n * Tightens files already in a directory — those written before this policy\n * existed, or by an older version. The caller names exactly what it owns, so\n * the sweep never reaches beyond CodeSesh's own files.\n */\nexport function restrictExistingPrivateFiles(\n directory: string,\n owns: (name: string) => boolean,\n): void {\n try {\n for (const entry of readdirSync(directory)) {\n if (owns(entry)) restrictPrivateFile(join(directory, entry));\n }\n } catch (error) {\n reportChmodFailure(directory, error);\n }\n}\n\n/** Databases whose neighbouring backups have already been swept this process. */\nconst sweptBackupsFor = new Set<string>();\n\n/** A backup holds the same rows as the database it came from. */\nfunction restrictExistingBackups(dbPath: string): void {\n if (sweptBackupsFor.has(dbPath)) return;\n sweptBackupsFor.add(dbPath);\n\n const prefix = `${basename(dbPath)}.`;\n restrictExistingPrivateFiles(\n dirname(dbPath),\n (name) => name.startsWith(prefix) && name.endsWith(\".bak\"),\n );\n}\n\n/**\n * Narrows a database, any sidecar SQLite has created, and backups left beside\n * it. Call after opening: the sidecars do not exist until the connection is\n * established.\n */\nexport function restrictPrivateDatabase(dbPath: string): void {\n restrictPrivateFile(dbPath);\n for (const suffix of SQLITE_SIDECAR_SUFFIXES) restrictPrivateFile(`${dbPath}${suffix}`);\n restrictExistingBackups(dbPath);\n}\n","{\n \"claude-3-5-haiku\": [8e-7, 0.000004, 0.000001, 8e-8],\n \"claude-3-5-sonnet\": [0.000003, 0.000015, 0.00000375, 3e-7],\n \"claude-3-7-sonnet\": [0.000003, 0.000015, 0.00000375, 3e-7],\n \"claude-haiku-4-5\": [0.000001, 0.000005, 0.00000125, 1e-7],\n \"claude-sonnet-4\": [0.000003, 0.000015, 0.00000375, 3e-7],\n \"claude-sonnet-4-5\": [0.000003, 0.000015, 0.00000375, 3e-7],\n \"claude-sonnet-4-6\": [0.000003, 0.000015, 0.00000375, 3e-7],\n \"claude-opus-4\": [0.000015, 0.000075, 0.00001875, 0.0000015],\n \"claude-opus-4-1\": [0.000015, 0.000075, 0.00001875, 0.0000015],\n \"claude-opus-4-5\": [0.000005, 0.000025, 0.00000625, 5e-7],\n \"claude-opus-4-6\": [0.000005, 0.000025, 0.00000625, 5e-7],\n \"claude-opus-4-7\": [0.000005, 0.000025, 0.00000625, 5e-7],\n \"anthropic/claude-sonnet-4-5\": [0.000003, 0.000015, 0.00000375, 3e-7],\n \"anthropic/claude-sonnet-4-6\": [0.000003, 0.000015, 0.00000375, 3e-7],\n \"anthropic/claude-opus-4-6\": [0.000005, 0.000025, 0.00000625, 5e-7],\n \"gpt-4.1\": [0.000002, 0.000008, null, 5e-7],\n \"gpt-4.1-mini\": [4e-7, 0.0000016, null, 1e-7],\n \"gpt-4.1-nano\": [1e-7, 4e-7, null, 2.5e-8],\n \"gpt-4o\": [0.0000025, 0.00001, null, 0.00000125],\n \"gpt-4o-mini\": [1.5e-7, 6e-7, null, 7.5e-8],\n \"gpt-5\": [0.00000125, 0.00001, null, 1.25e-7],\n \"gpt-5.1\": [0.00000125, 0.00001, null, 1.25e-7],\n \"gpt-5.1-codex\": [0.00000125, 0.00001, null, 1.25e-7],\n \"gpt-5.1-codex-mini\": [2.5e-7, 0.000002, null, 2.5e-8],\n \"gpt-5.2\": [0.00000175, 0.000014, null, 1.75e-7],\n \"gpt-5.2-codex\": [0.00000175, 0.000014, null, 1.75e-7],\n \"gpt-5.3-codex\": [0.00000175, 0.000014, null, 1.75e-7],\n \"gpt-5.4\": [0.0000025, 0.000015, null, 2.5e-7],\n \"gpt-5.4-mini\": [7.5e-7, 0.0000045, null, 7.5e-8],\n \"gpt-5.4-nano\": [2e-7, 0.00000125, null, 2e-8],\n \"gpt-5.5\": [0.000005, 0.00003, null, 5e-7],\n \"gpt-5-mini\": [2.5e-7, 0.000002, null, 2.5e-8],\n \"gpt-5-nano\": [5e-8, 4e-7, null, 5e-9],\n \"moonshotai/kimi-k2-0905\": [6e-7, 0.0000025, null, null],\n \"moonshotai/kimi-k2-instruct\": [5.7e-7, 0.0000023, null, null],\n \"moonshotai/kimi-k2-thinking\": [6e-7, 0.0000025, null, null],\n \"deepseek-chat\": [2.8e-7, 4.2e-7, null, 2.8e-8],\n \"deepseek-reasoner\": [2.8e-7, 4.2e-7, null, 2.8e-8],\n \"qwen3-coder-480b-a35b-instruct\": [3e-7, 0.0000013, null, null],\n \"gemini-2.5-pro\": [0.00000125, 0.00001, null, 1.25e-7],\n \"gemini-2.5-flash\": [3e-7, 0.0000025, null, 3e-8]\n}\n","import aliasesData from \"./data/aliases.json\";\nimport { getPricingRegistry, hasBillablePricing, type ModelPricing } from \"./fetcher.js\";\n\nconst BUILTIN_ALIASES = Object.fromEntries(\n Object.entries(aliasesData as Record<string, string>).map(([key, value]) => [\n normalizeModelKey(key),\n normalizeModelKey(value),\n ]),\n);\n\nfunction normalizeModelKey(model: string): string {\n return model.trim().toLowerCase().replaceAll(\"_\", \"-\");\n}\n\nfunction stripVersion(model: string): string {\n return model.replace(/@.*$/, \"\").replace(/-\\d{8}$/, \"\");\n}\n\nfunction stripProviderPrefix(model: string): string {\n const parts = model.split(\"/\");\n return parts[parts.length - 1] ?? model;\n}\n\nfunction resolveAlias(model: string): string {\n return BUILTIN_ALIASES[model] ?? model;\n}\n\nfunction getCandidates(rawModel: string): string[] {\n const withPrefix = stripVersion(normalizeModelKey(rawModel));\n const stripped = stripProviderPrefix(withPrefix);\n const aliased = resolveAlias(stripped);\n const candidates = [\n withPrefix,\n resolveAlias(withPrefix),\n stripped,\n aliased,\n `anthropic/${stripped}`,\n `openai/${stripped}`,\n `openrouter/openai/${stripped}`,\n `openrouter/anthropic/${stripped}`,\n `moonshotai/${stripped}`,\n `novita/moonshotai/${stripped}`,\n ];\n\n return [...new Set(candidates.filter(Boolean))];\n}\n\nfunction lookupCandidate(model: string, registry: Map<string, ModelPricing>) {\n const direct = registry.get(model);\n if (direct && hasBillablePricing(direct)) return direct;\n\n const alias = resolveAlias(model);\n if (alias !== model) {\n const aliased = registry.get(alias);\n if (aliased && hasBillablePricing(aliased)) return aliased;\n }\n\n return null;\n}\n\nfunction fuzzyLookup(model: string, registry: Map<string, ModelPricing>) {\n let best: [string, ModelPricing] | null = null;\n for (const [key, pricing] of registry.entries()) {\n if (!hasBillablePricing(pricing)) continue;\n if (model.startsWith(`${key}-`) || model.startsWith(`${key}@`) || model === key) {\n if (!best || key.length > best[0].length) best = [key, pricing];\n }\n }\n return best?.[1] ?? null;\n}\n\nexport interface PricingResolver {\n resolve(rawModelName: string): ModelPricing | null;\n}\n\nexport const pricingResolver: PricingResolver = {\n resolve(rawModelName: string): ModelPricing | null {\n const registry = getPricingRegistry();\n const candidates = getCandidates(rawModelName);\n\n for (const candidate of candidates) {\n const pricing = lookupCandidate(candidate, registry);\n if (pricing) return pricing;\n }\n\n for (const candidate of candidates) {\n const pricing = fuzzyLookup(candidate, registry);\n if (pricing) return pricing;\n }\n\n return null;\n },\n};\n","import type { CostSource, Message, MessageTokens, SessionStats } from \"../types/index.js\";\nimport { pricingResolver } from \"./resolver.js\";\n\nexport interface CostUsage extends MessageTokens {\n web_search_requests?: number;\n}\n\nexport interface CostEstimate {\n cost: number;\n source: CostSource;\n}\n\nfunction positive(value: number | undefined): number {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0 ? value : 0;\n}\n\nexport function estimateCostForTokens(\n model: string | null | undefined,\n usage: CostUsage | undefined,\n): CostEstimate | null {\n if (!model || !usage) return null;\n\n const pricing = pricingResolver.resolve(model);\n if (!pricing) return null;\n\n const cacheRead = positive(usage.cache_read);\n const cacheCreate = positive(usage.cache_create);\n const input = Math.max(0, positive(usage.input) - cacheRead - cacheCreate);\n const output = positive(usage.output);\n const reasoning = positive(usage.reasoning);\n const webSearchRequests = positive(usage.web_search_requests);\n\n const cost =\n input * pricing.inputCostPerToken +\n output * pricing.outputCostPerToken +\n reasoning * pricing.reasoningCostPerToken +\n cacheRead * pricing.cacheReadCostPerToken +\n cacheCreate * pricing.cacheCreateCostPerToken +\n webSearchRequests * pricing.webSearchCostPerRequest;\n\n return cost > 0 ? { cost: Number(cost.toFixed(8)), source: \"estimated\" } : null;\n}\n\nexport function applyMessageCost(message: Message): void {\n if ((message.cost ?? 0) > 0) {\n message.cost_source = \"recorded\";\n return;\n }\n\n const estimate = estimateCostForTokens(message.model, message.tokens);\n if (!estimate) return;\n\n message.cost = estimate.cost;\n message.cost_source = estimate.source;\n}\n\nexport function applyMessageCosts(messages: Message[]): { totalCost: number; source?: CostSource } {\n let totalCost = 0;\n let source: CostSource | undefined;\n\n for (const message of messages) {\n applyMessageCost(message);\n const cost = message.cost ?? 0;\n if (cost <= 0) continue;\n\n totalCost += cost;\n if (message.cost_source === \"estimated\") source = \"estimated\";\n else if (!source) source = \"recorded\";\n }\n\n return { totalCost: Number(totalCost.toFixed(8)), source };\n}\n\nexport function withEstimatedSessionCost<T extends SessionStats>(\n stats: T,\n model: string | null | undefined,\n): T {\n if (stats.total_cost > 0) {\n return { ...stats, cost_source: stats.cost_source ?? \"recorded\" };\n }\n\n const estimate = estimateCostForTokens(model, {\n input: stats.total_input_tokens,\n output: stats.total_output_tokens,\n cache_read: stats.total_cache_read_tokens,\n cache_create: stats.total_cache_create_tokens,\n });\n if (!estimate) return stats;\n\n return { ...stats, total_cost: estimate.cost, cost_source: estimate.source };\n}\n","import type { MessageTokens } from \"../types/index.js\";\nimport { estimateCostForTokens } from \"../pricing/index.js\";\n\nexport function estimateTokenCost(\n model: string | null | undefined,\n tokens?: MessageTokens,\n): number | null {\n return estimateCostForTokens(model, tokens)?.cost ?? null;\n}\n","import { getCoreDiagnostics } from \"./diagnostics.js\";\n\n/** Narrow to a plain object (excludes arrays and null); undefined on mismatch. */\nexport function asRecord(value: unknown): Record<string, unknown> | undefined {\n if (value && typeof value === \"object\" && !Array.isArray(value)) {\n return value as Record<string, unknown>;\n }\n return undefined;\n}\n\n/** Narrow to a string; undefined on mismatch. */\nexport function asString(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\n/** Narrow to a finite number (rejects NaN/Infinity); undefined on mismatch. */\nexport function asNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n}\n\n/** Narrow to an array; undefined on mismatch. */\nexport function asArray(value: unknown): unknown[] | undefined {\n return Array.isArray(value) ? value : undefined;\n}\n\n/**\n * Parses JSON text to a plain object; undefined on parse failure or a\n * non-object shape (e.g. array, string, null). Callers that need drift\n * reporting compose this with `narrowField`.\n */\nexport function safeParseJsonRecord(json: string): Record<string, unknown> | undefined {\n let raw: unknown;\n try {\n raw = JSON.parse(json);\n } catch {\n return undefined;\n }\n return asRecord(raw);\n}\n\nconst reportedFieldMismatches = new Set<string>();\n\n/**\n * Reports a field shape mismatch once per (agentName, field) for the life of\n * the process — an upstream format drift hits every line of a session file,\n * and warning per line would flood the diagnostics sink for no added signal.\n */\nexport function reportFieldMismatch(agentName: string, field: string): void {\n const key = `${agentName}\\0${field}`;\n if (reportedFieldMismatches.has(key)) return;\n reportedFieldMismatches.add(key);\n getCoreDiagnostics()?.warn(\"agent.field_shape_mismatch\", { agentName, field });\n}\n\n/**\n * Narrows a field's value with `narrow`, reporting once via\n * `reportFieldMismatch` when the field is present but narrowing fails.\n * `undefined`/`null` mean the field is absent (null-as-absent) and return\n * undefined silently — that's a normal shape, not drift.\n */\nexport function narrowField<T>(\n agent: string,\n field: string,\n value: unknown,\n narrow: (v: unknown) => T | undefined,\n): T | undefined {\n if (value === undefined || value === null) return undefined;\n const result = narrow(value);\n if (result === undefined) reportFieldMismatch(agent, field);\n return result;\n}\n","import type {\n Message,\n MessagePart,\n SessionStats,\n ToolPart,\n ToolPartStatus,\n} from \"../types/index.js\";\nimport { cleanParsedMessages } from \"../utils/session-normalization.js\";\n\nexport interface TranscriptMessageInput {\n id: string;\n role: Message[\"role\"];\n timestampMs: number;\n parts?: MessagePart[];\n agent?: string | null;\n mode?: string | null;\n model?: string | null;\n provider?: string | null;\n tokens?: Message[\"tokens\"];\n cost?: number;\n costSource?: Message[\"cost_source\"];\n subagentId?: string;\n nickname?: string;\n}\n\nexport type AssistantMessageInput = Omit<TranscriptMessageInput, \"role\" | \"parts\">;\n\nexport interface ToolResolution {\n output?: unknown;\n status?: ToolPartStatus;\n metadata?: unknown;\n consume?: boolean;\n}\n\nexport interface TranscriptResult {\n messages: Message[];\n stats: SessionStats;\n}\n\nexport class TranscriptBuilder {\n private readonly messages: Message[] = [];\n private readonly pendingToolCalls = new Map<string, ToolPart>();\n private currentAssistant: Message | null = null;\n private latestTextAssistant: Message | null = null;\n\n constructor(private readonly options: { messageDefaults?: \"nullable\" | \"sparse\" } = {}) {}\n\n beginTurn(): void {\n this.currentAssistant = null;\n this.latestTextAssistant = null;\n }\n\n appendMessage(input: TranscriptMessageInput): Message {\n const message = this.createMessage(input);\n this.messages.push(message);\n this.registerToolCalls(message.parts);\n\n if (message.role === \"assistant\") {\n this.currentAssistant = message;\n if (message.parts.some((part) => part.type === \"text\")) {\n this.latestTextAssistant = message;\n }\n } else if (message.role === \"user\") {\n this.beginTurn();\n }\n\n return message;\n }\n\n appendAssistantPart(\n part: MessagePart,\n input: AssistantMessageInput,\n options: {\n grouping?: \"compatible\" | \"current\";\n resetLatestText?: boolean;\n deduplicateTail?: boolean;\n } = {},\n ): Message {\n const current = this.currentAssistant;\n const canReuse =\n current !== null &&\n (options.grouping === \"current\" ||\n (part.type === \"text\"\n ? !current.parts.some((item) => item.type === \"tool\")\n : part.type === \"reasoning\"\n ? !current.parts.some((item) => item.type === \"text\" || item.type === \"tool\")\n : false));\n\n const message = canReuse\n ? current\n : this.appendMessage({ ...input, role: \"assistant\", parts: [part] });\n\n if (canReuse) {\n if (options.deduplicateTail) this.appendPartIfNew(message, part);\n else message.parts.push(part);\n this.applyMissingMetadata(message, input);\n }\n if (part.type === \"text\") {\n this.latestTextAssistant = message;\n } else if (options.resetLatestText) {\n this.latestTextAssistant = null;\n }\n return message;\n }\n\n appendToolCall(\n part: ToolPart,\n input: AssistantMessageInput,\n options: {\n markModeAsTool?: boolean;\n modeOnCreate?: string;\n target?: \"latest-text\" | \"current\";\n } = {},\n ): Message {\n const target =\n options.target === \"current\"\n ? this.currentAssistant\n : (this.latestTextAssistant ?? this.currentAssistant);\n const message = target\n ? target\n : this.appendMessage({\n ...input,\n role: \"assistant\",\n mode: options.modeOnCreate ?? (options.markModeAsTool ? \"tool\" : input.mode),\n parts: [part],\n });\n\n if (target) {\n message.parts.push(part);\n this.applyMissingMetadata(message, input);\n if (options.markModeAsTool) message.mode = \"tool\";\n this.registerToolCall(part);\n }\n\n this.currentAssistant = message;\n return message;\n }\n\n appendToCurrentAssistant(part: MessagePart): boolean {\n if (!this.currentAssistant) return false;\n this.currentAssistant.parts.push(part);\n return true;\n }\n\n updateToolCall(callId: string, update: (part: ToolPart) => void): boolean {\n const part = this.pendingToolCalls.get(callId);\n if (!part) return false;\n update(part);\n return true;\n }\n\n resolveToolCall(callId: string, resolution: ToolResolution): boolean {\n return this.updateToolCall(callId, (part) => {\n const state = part.state;\n if (resolution.output !== undefined) state.output = resolution.output;\n if (resolution.status !== undefined) state.status = resolution.status;\n else if (resolution.output !== undefined && state.status === \"running\") {\n state.status = \"completed\";\n }\n if (resolution.metadata !== undefined) state.metadata = resolution.metadata;\n if (resolution.consume) this.pendingToolCalls.delete(callId);\n });\n }\n\n attachUsageToLatestAssistant(\n tokens: Message[\"tokens\"],\n options: { model?: string | null; cost?: number; costSource?: Message[\"cost_source\"] } = {},\n ): boolean {\n for (let index = this.messages.length - 1; index >= 0; index -= 1) {\n const message = this.messages[index]!;\n if (message.role !== \"assistant\" || message.tokens) continue;\n message.tokens = tokens;\n if (options.model !== undefined) message.model ??= options.model;\n if (options.cost !== undefined) message.cost = options.cost;\n if (options.costSource !== undefined) message.cost_source = options.costSource;\n return true;\n }\n return false;\n }\n\n finish(baseStats?: SessionStats): TranscriptResult {\n const messages = cleanParsedMessages(this.messages);\n const derived = this.deriveStats(messages);\n if (!baseStats) return { messages, stats: derived };\n\n return {\n messages,\n stats: {\n ...derived,\n ...baseStats,\n message_count: messages.length,\n cost_source: baseStats.cost_source,\n },\n };\n }\n\n private createMessage(input: TranscriptMessageInput): Message {\n const sparse = this.options.messageDefaults === \"sparse\";\n return {\n id: input.id,\n role: input.role,\n agent: sparse ? input.agent : (input.agent ?? null),\n time_created: input.timestampMs,\n mode: sparse ? input.mode : (input.mode ?? null),\n model: sparse ? input.model : (input.model ?? null),\n provider: sparse ? input.provider : (input.provider ?? null),\n tokens: input.tokens,\n cost: sparse ? input.cost : (input.cost ?? 0),\n cost_source: input.costSource,\n parts: input.parts ?? [],\n subagent_id: input.subagentId,\n nickname: input.nickname,\n };\n }\n\n private registerToolCalls(parts: MessagePart[]): void {\n for (const part of parts) this.registerToolCall(part);\n }\n\n private registerToolCall(part: MessagePart): void {\n if (part.type === \"tool\" && part.callID) {\n this.pendingToolCalls.set(part.callID, part);\n }\n }\n\n private appendPartIfNew(message: Message, part: MessagePart): void {\n const tail = message.parts.at(-1);\n if (\"text\" in part && tail?.type === part.type && \"text\" in tail && tail.text === part.text) {\n return;\n }\n message.parts.push(part);\n }\n\n private applyMissingMetadata(message: Message, input: AssistantMessageInput): void {\n if (!message.id && input.id) message.id = input.id;\n if (message.agent == null && input.agent !== undefined) message.agent = input.agent;\n if (message.mode == null && input.mode !== undefined) message.mode = input.mode;\n if (message.model == null && input.model !== undefined) message.model = input.model;\n if (message.provider == null && input.provider !== undefined) message.provider = input.provider;\n if (!message.tokens && input.tokens) message.tokens = input.tokens;\n if ((message.cost ?? 0) === 0 && input.cost !== undefined) message.cost = input.cost;\n if (!message.cost_source && input.costSource) message.cost_source = input.costSource;\n }\n\n private deriveStats(messages: Message[]): SessionStats {\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCacheReadTokens = 0;\n let totalCacheCreateTokens = 0;\n let totalCost = 0;\n let hasEstimatedCost = false;\n\n for (const message of messages) {\n totalInputTokens += message.tokens?.input ?? 0;\n totalOutputTokens += message.tokens?.output ?? 0;\n totalCacheReadTokens += message.tokens?.cache_read ?? 0;\n totalCacheCreateTokens += message.tokens?.cache_create ?? 0;\n totalCost += message.cost ?? 0;\n if (message.cost_source === \"estimated\") hasEstimatedCost = true;\n }\n\n return {\n message_count: messages.length,\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cache_read_tokens: totalCacheReadTokens || undefined,\n total_cache_create_tokens: totalCacheCreateTokens || undefined,\n total_cost: totalCost,\n cost_source: totalCost > 0 ? (hasEstimatedCost ? \"estimated\" : \"recorded\") : undefined,\n };\n }\n}\n","import { join } from \"node:path\";\nimport { firstExisting, resolveDataHome } from \"../discovery/paths.js\";\nimport { isSqliteAvailable } from \"../utils/sqlite.js\";\nimport { OpenCodeSqliteAgent } from \"./opencode-sqlite.js\";\n\nexport function resolveOpenCodeDataRoot(): string {\n return join(resolveDataHome(), \"opencode\");\n}\n\nfunction findOpenCodeDbPath(): string | null {\n if (!isSqliteAvailable()) return null;\n return firstExisting(join(resolveOpenCodeDataRoot(), \"opencode.db\"), \"data/opencode/opencode.db\");\n}\n\nfunction getOpenCodeSessionWatchPlan() {\n const dataRoot = resolveOpenCodeDataRoot();\n return {\n status: \"supported\" as const,\n targets: [\n { root: dataRoot, path: join(dataRoot, \"opencode.db\") },\n { root: \"data/opencode\", path: \"data/opencode/opencode.db\" },\n ],\n };\n}\n\nexport class OpenCodeAgent extends OpenCodeSqliteAgent {\n constructor() {\n super({\n name: \"opencode\",\n displayName: \"OpenCode\",\n findDbPath: findOpenCodeDbPath,\n getSessionWatchPlan: getOpenCodeSessionWatchPlan,\n });\n }\n}\n","/**\n * SQLite helper — graceful degradation if better-sqlite3 is unavailable.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { basename, dirname, join } from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport { getCoreDiagnostics } from \"./diagnostics.js\";\nimport {\n ensurePrivateDirectory,\n restrictPrivateDatabase,\n restrictPrivateFile,\n} from \"./private-storage.js\";\n\ninterface SQLiteStatement {\n all(...params: unknown[]): DatabaseRow[];\n get(...params: unknown[]): DatabaseRow | undefined;\n /** Streams rows so a large result set never has to be materialized at once. */\n iterate(...params: unknown[]): IterableIterator<DatabaseRow>;\n run(...params: unknown[]): unknown;\n}\n\ninterface SQLiteTransaction {\n (...params: unknown[]): unknown;\n}\n\ninterface SQLitePragmaCapable {\n pragma(sql: string): unknown;\n}\n\ntype SQLiteDatabaseConstructor = (\n path: string,\n options?: { readonly?: boolean },\n) => SQLiteDatabase & SQLitePragmaCapable;\n\nlet DatabaseConstructor: SQLiteDatabaseConstructor | null = null;\nlet loadErrorMessage: string | null = null;\n\ntry {\n const require = createRequire(import.meta.url);\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const mod = require(\"better-sqlite3\");\n DatabaseConstructor = (\n typeof mod === \"function\" ? mod : (mod as { default?: unknown }).default\n ) as SQLiteDatabaseConstructor;\n} catch (error) {\n // better-sqlite3 not installed — adapters that need SQLite will gracefully skip.\n // This module body evaluates before a host has a chance to call\n // setCoreDiagnostics, so reporting here would always be dropped — defer the\n // warn to reportUnavailableOnce(), called from the first actual open attempt.\n loadErrorMessage = error instanceof Error ? error.message : String(error);\n}\n\nlet unavailableReported = false;\n\nfunction reportUnavailableOnce(): void {\n if (unavailableReported) return;\n unavailableReported = true;\n getCoreDiagnostics()?.warn(\"sqlite.unavailable\", { message: loadErrorMessage });\n}\n\nexport interface DatabaseRow {\n [key: string]: unknown;\n}\n\nexport interface SQLiteDatabase {\n prepare(sql: string): SQLiteStatement;\n exec(sql: string): void;\n transaction<T extends SQLiteTransaction>(fn: T): T;\n close(): void;\n}\n\nexport interface SchemaMigration {\n version: number;\n destructive?: boolean;\n migrate(db: SQLiteDatabase): void;\n}\n\nexport interface RunSchemaMigrationsOptions {\n dbPath: string;\n currentVersion: number;\n targetVersion: number;\n migrations: SchemaMigration[];\n backupTables: string[];\n backupLabel: string;\n}\n\nfunction quoteIdentifier(value: string): string {\n return `\"${value.replaceAll('\"', '\"\"')}\"`;\n}\n\nfunction quoteSqlString(value: string): string {\n return `'${value.replaceAll(\"'\", \"''\")}'`;\n}\n\nfunction isInMemoryPath(dbPath: string): boolean {\n return (\n dbPath === \":memory:\" || dbPath.startsWith(\"file::memory:\") || dbPath.includes(\"mode=memory\")\n );\n}\n\nexport function getUserVersion(db: SQLiteDatabase): number {\n const row = db.prepare(\"PRAGMA user_version\").get() as DatabaseRow | undefined;\n return Number(row?.user_version ?? 0);\n}\n\nexport function setUserVersion(db: SQLiteDatabase, version: number): void {\n db.exec(`PRAGMA user_version = ${Math.trunc(version)}`);\n}\n\nexport function tableExists(db: SQLiteDatabase, tableName: string): boolean {\n const row = db\n .prepare(\n `\n SELECT 1 AS value\n FROM sqlite_master\n WHERE name = ? AND type IN ('table', 'view')\n LIMIT 1\n `,\n )\n .get(tableName) as DatabaseRow | undefined;\n return row !== undefined;\n}\n\nexport function columnExists(db: SQLiteDatabase, tableName: string, columnName: string): boolean {\n if (!tableExists(db, tableName)) {\n return false;\n }\n\n const rows = db.prepare(`PRAGMA table_info(${quoteIdentifier(tableName)})`).all();\n return rows.some((row) => String(row.name) === columnName);\n}\n\nexport function tableHasRows(db: SQLiteDatabase, tableName: string): boolean {\n if (!tableExists(db, tableName)) {\n return false;\n }\n\n const row = db.prepare(`SELECT 1 AS value FROM ${quoteIdentifier(tableName)} LIMIT 1`).get() as\n | DatabaseRow\n | undefined;\n return row !== undefined;\n}\n\nexport function backupDatabase(db: SQLiteDatabase, dbPath: string, label: string): string | null {\n if (isInMemoryPath(dbPath)) {\n return null;\n }\n\n const timestamp = new Date(Date.now()).toISOString().replaceAll(\":\", \"\").replaceAll(\".\", \"-\");\n let backupPath = join(dirname(dbPath), `${basename(dbPath)}.${timestamp}.${label}.bak`);\n for (let counter = 1; existsSync(backupPath); counter += 1) {\n backupPath = join(dirname(dbPath), `${basename(dbPath)}.${timestamp}.${label}.${counter}.bak`);\n }\n db.exec(`VACUUM INTO ${quoteSqlString(backupPath)}`);\n // A fresh inode does not inherit the source database's mode.\n restrictPrivateFile(backupPath);\n return backupPath;\n}\n\nexport function backupDatabaseIfPopulated(\n db: SQLiteDatabase,\n dbPath: string,\n label: string,\n tables: string[],\n): string | null {\n if (!tables.some((table) => tableHasRows(db, table))) {\n return null;\n }\n\n return backupDatabase(db, dbPath, label);\n}\n\nexport function runSchemaMigrations(\n db: SQLiteDatabase,\n options: RunSchemaMigrationsOptions,\n): string[] {\n const backups: string[] = [];\n let currentVersion = options.currentVersion;\n\n for (const migration of options.migrations) {\n if (migration.version <= currentVersion) {\n continue;\n }\n if (migration.version > options.targetVersion) {\n break;\n }\n\n const fromVersion = currentVersion;\n const startedAt = performance.now();\n getCoreDiagnostics()?.info?.(\"sqlite.migration.started\", {\n label: options.backupLabel,\n from_version: fromVersion,\n to_version: migration.version,\n destructive: migration.destructive ?? false,\n });\n\n try {\n let backupCreated = false;\n if (migration.destructive) {\n const backupPath = backupDatabaseIfPopulated(\n db,\n options.dbPath,\n options.backupLabel,\n options.backupTables,\n );\n if (backupPath) {\n backups.push(backupPath);\n backupCreated = true;\n }\n }\n\n const apply = db.transaction(() => {\n migration.migrate(db);\n setUserVersion(db, migration.version);\n });\n apply();\n currentVersion = migration.version;\n getCoreDiagnostics()?.info?.(\"sqlite.migration.completed\", {\n label: options.backupLabel,\n from_version: fromVersion,\n to_version: migration.version,\n destructive: migration.destructive ?? false,\n backup_created: backupCreated,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n } catch (error) {\n getCoreDiagnostics()?.warn(\"sqlite.migration.failed\", {\n label: options.backupLabel,\n from_version: fromVersion,\n to_version: migration.version,\n destructive: migration.destructive ?? false,\n duration_ms: Math.round(performance.now() - startedAt),\n message: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n if (currentVersion < options.targetVersion) {\n setUserVersion(db, options.targetVersion);\n }\n\n return backups;\n}\n\n/**\n * Open a SQLite database in read-only mode.\n * Returns null if better-sqlite3 is unavailable or the file can't be opened.\n */\nexport function openDbReadOnly(dbPath: string): SQLiteDatabase | null {\n if (!DatabaseConstructor) {\n reportUnavailableOnce();\n return null;\n }\n try {\n const db = DatabaseConstructor(dbPath, { readonly: true });\n return db;\n } catch (error) {\n getCoreDiagnostics()?.warn(\"sqlite.open_failed\", {\n dbPath,\n readonly: true,\n message: error instanceof Error ? error.message : String(error),\n });\n return null;\n }\n}\n\nexport function openDb(dbPath: string): SQLiteDatabase | null {\n if (!DatabaseConstructor) {\n reportUnavailableOnce();\n return null;\n }\n try {\n ensurePrivateDirectory(dirname(dbPath));\n const db = DatabaseConstructor(dbPath);\n // The sidecars only exist once the connection is established.\n restrictPrivateDatabase(dbPath);\n try {\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"synchronous = NORMAL\");\n db.pragma(\"foreign_keys = ON\");\n db.pragma(\"busy_timeout = 5000\");\n } catch {\n // The database remains usable when SQLite rejects connection-level tuning.\n }\n return db;\n } catch (error) {\n getCoreDiagnostics()?.warn(\"sqlite.open_failed\", {\n dbPath,\n readonly: false,\n message: error instanceof Error ? error.message : String(error),\n });\n return null;\n }\n}\n\n/**\n * Check if SQLite support is available.\n */\nexport function isSqliteAvailable(): boolean {\n return DatabaseConstructor !== null;\n}\n","import {\n DatabaseSessionSource,\n SessionScanError,\n filteredSession,\n getParsedSession,\n parsedSession,\n skippedSession,\n} from \"./base.js\";\nimport type { AgentScanOptions, ParseSessionResult, SessionWatchPlan } from \"./base.js\";\nimport type { SessionHead, SessionDetail, Message, MessagePart } from \"../types/index.js\";\nimport { normalizeMessageParts } from \"../contract/message-part.js\";\nimport { columnExists, openDbReadOnly, type SQLiteDatabase } from \"../utils/sqlite.js\";\nimport { estimateTokenCost } from \"../utils/cost.js\";\nimport { resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport { isInternalEventType } from \"../utils/parse-cleanup.js\";\nimport { asRecord, asString, narrowField, reportFieldMismatch } from \"../utils/narrow.js\";\nimport {\n cleanMessagePart,\n cleanParsedMessages,\n firstUserMessageTitle,\n} from \"../utils/session-normalization.js\";\n\ninterface OpenCodeMessageRow {\n id?: unknown;\n session_id?: unknown;\n data?: string;\n time_created?: unknown;\n parent_id?: unknown;\n}\n\ninterface OpenCodePartRow {\n message_id?: unknown;\n data?: string;\n time_created?: unknown;\n}\n\ninterface OpenCodeHeadContext {\n stats: SessionHead[\"stats\"];\n messageTitle: string | null;\n}\n\ninterface OpenCodeSqliteAgentConfig {\n name: string;\n displayName: string;\n findDbPath: () => string | null;\n getSessionWatchPlan: () => SessionWatchPlan;\n}\n\nconst MESSAGE_ROLES = new Set<Message[\"role\"]>([\"user\", \"assistant\", \"tool\"]);\nconst SESSION_ID_QUERY_CHUNK_SIZE = 500;\n\nfunction compareSessionRowsByActivityDesc(\n left: Record<string, unknown>,\n right: Record<string, unknown>,\n): number {\n const leftUpdated = Number(left.time_updated ?? left.time_created ?? 0);\n const rightUpdated = Number(right.time_updated ?? right.time_created ?? 0);\n return (\n rightUpdated - leftUpdated ||\n Number(right.time_created ?? 0) - Number(left.time_created ?? 0) ||\n String(right.id ?? \"\").localeCompare(String(left.id ?? \"\"))\n );\n}\n\nfunction accumulateTokenStats(\n stats: SessionHead[\"stats\"],\n msgData: Record<string, unknown>,\n agentName: string,\n): void {\n const cost = Number(msgData.cost ?? 0);\n const tokens = parseTokens(msgData.tokens, agentName);\n const inputTokens = Number(tokens?.input ?? 0);\n const outputTokens = Number(tokens?.output ?? 0);\n const model = parseModel(msgData.modelID, agentName);\n const estimatedCost =\n cost > 0 ? null : estimateTokenCost(model, { input: inputTokens, output: outputTokens });\n\n if (estimatedCost !== null) stats.cost_source = \"estimated\";\n stats.total_cost += cost || estimatedCost || 0;\n stats.total_input_tokens += inputTokens;\n stats.total_output_tokens += outputTokens;\n}\n\n/** Parses a SQLite `data` JSON column; non-object payloads fall back to `{}` (reported as drift). */\nfunction parseJsonRecord(raw: unknown, agentName: string, field: string): Record<string, unknown> {\n const parsed = asRecord(JSON.parse(String(raw ?? \"{}\")));\n if (parsed) return parsed;\n reportFieldMismatch(agentName, field);\n return {};\n}\n\nfunction narrowMessageRole(value: unknown): Message[\"role\"] | undefined {\n const role = asString(value);\n return role !== undefined && (MESSAGE_ROLES as Set<string>).has(role)\n ? (role as Message[\"role\"])\n : undefined;\n}\n\nfunction parseMessageRole(value: unknown, agentName: string): Message[\"role\"] {\n return narrowField(agentName, \"message.role\", value, narrowMessageRole) ?? \"assistant\";\n}\n\nfunction parseTokens(value: unknown, agentName: string): Record<string, unknown> | undefined {\n return narrowField(agentName, \"message.tokens\", value, asRecord);\n}\n\nfunction parseModel(value: unknown, agentName: string): string | null {\n return narrowField(agentName, \"message.modelID\", value, asString) ?? null;\n}\n\nexport class OpenCodeSqliteAgent extends DatabaseSessionSource {\n readonly name: string;\n readonly displayName: string;\n\n private dbPath: string | null = null;\n\n constructor(private readonly config: OpenCodeSqliteAgentConfig) {\n super();\n this.name = config.name;\n this.displayName = config.displayName;\n }\n\n protected getDatabasePath(): string | null {\n if (!this.dbPath) {\n this.dbPath = this.findDbPath();\n }\n return this.dbPath;\n }\n\n getSessionWatchPlan(): SessionWatchPlan {\n return this.config.getSessionWatchPlan();\n }\n\n private findDbPath(): string | null {\n return this.config.findDbPath();\n }\n\n isAvailable(): boolean {\n this.dbPath = this.findDbPath();\n return this.dbPath !== null;\n }\n\n scan(options?: AgentScanOptions): SessionHead[] {\n if (!this.dbPath) return [];\n\n const db = openDbReadOnly(this.dbPath);\n if (!db) throw new SessionScanError(this.name, \"opening the database\");\n\n try {\n const cutoffTime = options?.from ?? Date.now() - 3650 * 24 * 60 * 60 * 1000;\n\n const hasMessageTable = Boolean(\n db\n .prepare(\"SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'message'\")\n .get(),\n );\n\n const hasTaskType = columnExists(db, \"session\", \"task_type\");\n const hasParentId = columnExists(db, \"session\", \"parent_id\");\n const childPredicate = hasParentId\n ? \"AND s.parent_id IS NULL\"\n : hasTaskType\n ? \"AND (s.task_type IS NULL OR s.task_type != 'subagent_child')\"\n : \"\";\n\n let rows: Record<string, unknown>[];\n const parentIdSelect = hasParentId ? \", s.parent_id\" : \"\";\n if (hasMessageTable) {\n rows = db\n .prepare(`\n SELECT\n s.id, s.title, s.time_created, s.time_updated, s.slug, s.directory,\n s.version, s.summary_files${parentIdSelect}\n FROM session s\n WHERE COALESCE(s.time_updated, s.time_created) >= ?\n ${childPredicate}\n ORDER BY COALESCE(s.time_updated, s.time_created) DESC, s.time_created DESC, s.id DESC\n `)\n .all(cutoffTime);\n } else {\n rows = db\n .prepare(`\n SELECT s.id, s.title, s.time_created, s.time_updated, s.slug, s.directory,\n s.version, s.summary_files, 0 AS message_count, NULL AS model_message_data${parentIdSelect}\n FROM session s\n WHERE COALESCE(s.time_updated, s.time_created) >= ?\n ${childPredicate}\n ORDER BY COALESCE(s.time_updated, s.time_created) DESC, s.time_created DESC, s.id DESC\n `)\n .all(cutoffTime);\n }\n\n if (hasParentId && options?.includeRelatedSessions !== false) {\n const rootIds = rows.map((row) => String(row.id ?? \"\")).filter(Boolean);\n const relatedRows = this.readRelatedSessionRows(db, rootIds);\n const knownIds = new Set(rootIds);\n rows.push(...relatedRows.filter((row) => !knownIds.has(String(row.id ?? \"\"))));\n }\n\n rows.sort(compareSessionRowsByActivityDesc);\n\n const sessionIds = new Set(rows.map((row) => String(row.id ?? \"\")).filter(Boolean));\n\n const headContexts = hasMessageTable\n ? this.buildHeadContexts(\n this.readHeadMessageRows(\n db,\n cutoffTime,\n hasParentId,\n sessionIds.size > 0 ? sessionIds : undefined,\n ),\n this.readHeadPartRows(db, cutoffTime, sessionIds.size > 0 ? sessionIds : undefined),\n hasParentId,\n )\n : new Map<string, OpenCodeHeadContext>();\n const heads: SessionHead[] = [];\n options?.onProgress?.({ total: rows.length, processed: 0, sessions: 0 });\n let processed = 0;\n for (const row of rows) {\n const head = getParsedSession(\n this.parseSessionHeadRow(row, hasMessageTable, headContexts.get(String(row.id ?? \"\"))),\n );\n if (head) {\n heads.push(head);\n\n // Store session metadata for caching\n if (this.dbPath) {\n this.sessionMetaMap.set(head.id, {\n id: head.id,\n sourcePath: this.dbPath,\n });\n }\n }\n processed += 1;\n options?.onProgress?.({ total: rows.length, processed, sessions: heads.length });\n }\n\n return heads;\n } catch (error) {\n throw new SessionScanError(this.name, \"reading sessions\", { cause: error });\n } finally {\n db.close();\n }\n }\n\n private parseSessionHeadRow(\n row: Record<string, unknown>,\n hasMessageTable: boolean,\n context?: OpenCodeHeadContext,\n ): ParseSessionResult<SessionHead> {\n const id = String(row.id ?? \"\");\n if (!id) return skippedSession(\"missing session id\");\n\n const timeCreated = Number(row.time_created ?? 0);\n const timeUpdated = Number(row.time_updated ?? timeCreated);\n const stats = context?.stats ?? null;\n const messageCount = stats?.message_count ?? 0;\n if (hasMessageTable && messageCount === 0) return filteredSession(\"no visible messages\");\n const messageTitle = context?.messageTitle ?? null;\n\n return parsedSession({\n id,\n slug: `${this.name}/${id}`,\n title: resolveSessionTitle(String(row.title ?? \"\"), messageTitle, null),\n directory: String(row.directory ?? \"\"),\n parent_reference:\n row.parent_id == null || String(row.parent_id) === \"\"\n ? undefined\n : { agentName: this.name, sessionId: String(row.parent_id) },\n time_created: timeCreated,\n time_updated: timeUpdated,\n stats: {\n message_count: messageCount,\n total_input_tokens: stats?.total_input_tokens ?? 0,\n total_output_tokens: stats?.total_output_tokens ?? 0,\n total_cost: stats?.total_cost ?? 0,\n cost_source: stats?.cost_source,\n },\n });\n }\n\n private readHeadMessageRows(\n db: SQLiteDatabase,\n cutoffTime: number,\n withParentId: boolean,\n sessionIds?: Set<string>,\n ): OpenCodeMessageRow[] {\n const parentIdSelect = withParentId ? \", s.parent_id\" : \"\";\n const ids = sessionIds ? [...sessionIds] : [];\n if (ids.length === 0) {\n return db\n .prepare(\n `\n SELECT m.id, m.session_id, m.data, m.time_created${parentIdSelect}\n FROM message m\n JOIN session s ON s.id = m.session_id\n WHERE COALESCE(s.time_updated, s.time_created) >= ?\n ORDER BY m.session_id, m.time_created ASC\n `,\n )\n .all(cutoffTime) as OpenCodeMessageRow[];\n }\n\n const rows: OpenCodeMessageRow[] = [];\n for (let offset = 0; offset < ids.length; offset += SESSION_ID_QUERY_CHUNK_SIZE) {\n const chunk = ids.slice(offset, offset + SESSION_ID_QUERY_CHUNK_SIZE);\n rows.push(\n ...(db\n .prepare(\n `\n SELECT m.id, m.session_id, m.data, m.time_created${parentIdSelect}\n FROM message m\n JOIN session s ON s.id = m.session_id\n WHERE s.id IN (${chunk.map(() => \"?\").join(\",\")})\n ORDER BY m.session_id, m.time_created ASC\n `,\n )\n .all(...chunk) as OpenCodeMessageRow[]),\n );\n }\n return rows;\n }\n\n private readHeadPartRows(\n db: SQLiteDatabase,\n cutoffTime: number,\n sessionIds?: Set<string>,\n ): OpenCodePartRow[] {\n const ids = sessionIds ? [...sessionIds] : [];\n if (ids.length === 0) {\n return db\n .prepare(\n `\n SELECT p.message_id, p.data, p.time_created\n FROM part p\n JOIN message m ON m.id = p.message_id\n JOIN session s ON s.id = m.session_id\n WHERE COALESCE(s.time_updated, s.time_created) >= ?\n ORDER BY p.message_id, p.time_created ASC, p.id ASC\n `,\n )\n .all(cutoffTime) as OpenCodePartRow[];\n }\n\n const rows: OpenCodePartRow[] = [];\n for (let offset = 0; offset < ids.length; offset += SESSION_ID_QUERY_CHUNK_SIZE) {\n const chunk = ids.slice(offset, offset + SESSION_ID_QUERY_CHUNK_SIZE);\n rows.push(\n ...(db\n .prepare(\n `\n SELECT p.message_id, p.data, p.time_created\n FROM part p\n JOIN message m ON m.id = p.message_id\n JOIN session s ON s.id = m.session_id\n WHERE s.id IN (${chunk.map(() => \"?\").join(\",\")})\n ORDER BY p.message_id, p.time_created ASC, p.id ASC\n `,\n )\n .all(...chunk) as OpenCodePartRow[]),\n );\n }\n return rows;\n }\n\n private readRelatedSessionRows(db: SQLiteDatabase, rootIds: string[]): Record<string, unknown>[] {\n if (rootIds.length === 0) return [];\n\n const rows = db\n .prepare(\n `\n SELECT\n s.id, s.title, s.time_created, s.time_updated, s.slug, s.directory,\n s.version, s.summary_files, s.parent_id\n FROM session s\n WHERE s.parent_id IS NOT NULL\n ORDER BY s.time_created ASC\n `,\n )\n .all() as Record<string, unknown>[];\n const childrenByParent = new Map<string, Record<string, unknown>[]>();\n for (const row of rows) {\n const parentId = String(row.parent_id ?? \"\");\n if (!parentId) continue;\n const children = childrenByParent.get(parentId);\n if (children) children.push(row);\n else childrenByParent.set(parentId, [row]);\n }\n\n const result: Record<string, unknown>[] = [];\n const pending = [...rootIds];\n const seen = new Set<string>();\n while (pending.length > 0) {\n const parentId = pending.pop()!;\n for (const row of childrenByParent.get(parentId) ?? []) {\n const id = String(row.id ?? \"\");\n if (!id || seen.has(id)) continue;\n seen.add(id);\n result.push(row);\n pending.push(id);\n }\n }\n return result;\n }\n\n private parsePartRow(\n partRow: Pick<OpenCodePartRow, \"data\" | \"time_created\">,\n ): MessagePart | null {\n const partData = parseJsonRecord(partRow.data, this.name, \"part.data\");\n const partType = String(partData.type ?? \"\");\n if (isInternalEventType(partType)) return null;\n const [part] = normalizeMessageParts([\n { ...partData, time_created: Number(partRow.time_created ?? 0) },\n ]);\n return part ? cleanMessagePart(part) : null;\n }\n\n /**\n * Every part of one session in a single read. Fetching per message turned a\n * detail into M+2 queries, and without an index on part(message_id) each one\n * scanned the whole table.\n */\n private readSessionPartRows(db: SQLiteDatabase, sessionId: string): OpenCodePartRow[] {\n return db\n .prepare(\n `\n SELECT p.message_id, p.data, p.time_created\n FROM part p\n JOIN message m ON m.id = p.message_id\n WHERE m.session_id = ?\n ORDER BY p.message_id, p.time_created ASC, p.id ASC\n `,\n )\n .all(sessionId) as OpenCodePartRow[];\n }\n\n private buildPartsByMessage(partRows: OpenCodePartRow[]): Map<string, MessagePart[]> {\n const partsByMessage = new Map<string, MessagePart[]>();\n for (const row of partRows) {\n const messageId = String(row.message_id ?? \"\");\n if (!messageId) continue;\n const part = this.parsePartRow(row);\n if (!part) continue;\n const parts = partsByMessage.get(messageId);\n if (parts) {\n parts.push(part);\n } else {\n partsByMessage.set(messageId, [part]);\n }\n }\n return partsByMessage;\n }\n\n private buildHeadContexts(\n messageRows: OpenCodeMessageRow[],\n partRows: OpenCodePartRow[],\n withParentId: boolean,\n ): Map<string, OpenCodeHeadContext> {\n const partsByMessage = this.buildPartsByMessage(partRows);\n const contexts = new Map<string, OpenCodeHeadContext>();\n\n const ensureContext = (sessionId: string): OpenCodeHeadContext => {\n let context = contexts.get(sessionId);\n if (!context) {\n context = {\n stats: {\n message_count: 0,\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_cost: 0,\n },\n messageTitle: null,\n };\n contexts.set(sessionId, context);\n }\n return context;\n };\n\n for (const row of messageRows) {\n const sessionId = String(row.session_id ?? \"\");\n if (!sessionId) continue;\n const msgData = parseJsonRecord(row.data, this.name, \"message.data\");\n if (isInternalEventType(msgData.type)) continue;\n\n const parentId = withParentId ? String(row.parent_id ?? \"\") : \"\";\n const isChild = parentId !== \"\";\n\n if (isChild) {\n const childContext = ensureContext(sessionId);\n const parts = partsByMessage.get(String(row.id ?? \"\")) ?? [];\n if (parts.length > 0) {\n accumulateTokenStats(childContext.stats, msgData, this.name);\n childContext.stats.message_count += 1;\n if (!childContext.messageTitle && String(msgData.role ?? \"\") === \"user\") {\n childContext.messageTitle = firstUserMessageTitle([\n {\n id: String(row.id ?? \"\"),\n role: \"user\",\n agent: null,\n time_created: Number(row.time_created ?? 0),\n parts,\n },\n ]);\n }\n }\n const parentContext = ensureContext(parentId);\n accumulateTokenStats(parentContext.stats, msgData, this.name);\n continue;\n }\n\n const parts = partsByMessage.get(String(row.id ?? \"\")) ?? [];\n if (parts.length === 0) continue;\n\n const context = ensureContext(sessionId);\n accumulateTokenStats(context.stats, msgData, this.name);\n context.stats.message_count += 1;\n\n if (!context.messageTitle && String(msgData.role ?? \"\") === \"user\") {\n context.messageTitle = firstUserMessageTitle([\n {\n id: String(row.id ?? \"\"),\n role: \"user\",\n agent: null,\n time_created: Number(row.time_created ?? 0),\n parts,\n },\n ]);\n }\n }\n\n for (const context of contexts.values()) {\n if (context.stats.total_cost > 0 && context.stats.cost_source !== \"estimated\") {\n context.stats.cost_source = \"recorded\";\n }\n }\n\n return contexts;\n }\n\n private sumChildTokenStats(db: SQLiteDatabase, parentSessionId: string): SessionHead[\"stats\"][] {\n if (!columnExists(db, \"session\", \"parent_id\")) return [];\n\n const childRows = db\n .prepare(\"SELECT id FROM session WHERE parent_id = ?\")\n .all(parentSessionId) as Record<string, unknown>[];\n\n const results: SessionHead[\"stats\"][] = [];\n for (const child of childRows) {\n const childId = String(child.id ?? \"\");\n if (!childId) continue;\n const msgRows = db\n .prepare(\"SELECT data FROM message WHERE session_id = ? ORDER BY time_created ASC, id ASC\")\n .all(childId) as OpenCodeMessageRow[];\n const stats: SessionHead[\"stats\"] = {\n message_count: 0,\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_cost: 0,\n };\n for (const row of msgRows) {\n const msgData = parseJsonRecord(row.data, this.name, \"message.data\");\n if (isInternalEventType(msgData.type)) continue;\n accumulateTokenStats(stats, msgData, this.name);\n }\n results.push(stats);\n }\n return results;\n }\n\n getSessionData(sessionId: string): SessionDetail {\n // Ensure dbPath is set\n if (!this.dbPath) {\n this.dbPath = this.findDbPath();\n }\n if (!this.dbPath) {\n throw new Error(`${this.displayName} database is missing`);\n }\n\n const db = openDbReadOnly(this.dbPath);\n if (!db) {\n throw new Error(`${this.displayName} database is missing`);\n }\n\n try {\n // First get session metadata\n const sessionRow = db.prepare(\"SELECT * FROM session WHERE id = ?\").get(sessionId) as\n | Record<string, unknown>\n | undefined;\n if (!sessionRow) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n\n const id = String(sessionRow.id ?? sessionId);\n const slug = `${this.name}/${id}`;\n const directory = String(sessionRow.directory ?? \"\");\n const timeCreated = Number(sessionRow.time_created ?? 0);\n const timeUpdated = Number(sessionRow.time_updated ?? timeCreated);\n\n const messages: Message[] = [];\n let hasEstimatedCost = false;\n\n // Get messages\n const msgRows = db\n .prepare(\"SELECT * FROM message WHERE session_id = ? ORDER BY time_created ASC, id ASC\")\n .all(sessionId) as Record<string, unknown>[];\n const partsByMessage = this.buildPartsByMessage(this.readSessionPartRows(db, sessionId));\n\n for (const msgRow of msgRows) {\n const msgData = parseJsonRecord(msgRow.data, this.name, \"message.data\");\n if (isInternalEventType(msgData.type)) continue;\n\n const cost = Number(msgData.cost ?? 0);\n const tokens = parseTokens(msgData.tokens, this.name);\n const inputTokens = Number(tokens?.input ?? 0);\n const outputTokens = Number(tokens?.output ?? 0);\n const model = parseModel(msgData.modelID, this.name);\n const estimatedCost =\n cost > 0 ? null : estimateTokenCost(model, { input: inputTokens, output: outputTokens });\n const resolvedCost = cost || estimatedCost || 0;\n\n const parts = partsByMessage.get(String(msgRow.id ?? \"\")) ?? [];\n if (parts.length === 0) continue;\n\n messages.push({\n id: String(msgRow.id ?? \"\"),\n role: parseMessageRole(msgData.role, this.name),\n agent: asString(msgData.agent) ?? null,\n mode: asString(msgData.mode) ?? null,\n model,\n provider: asString(msgData.providerID) ?? null,\n time_created: Number(msgRow.time_created ?? 0),\n tokens: tokens ? { input: inputTokens, output: outputTokens } : undefined,\n cost: resolvedCost,\n cost_source: resolvedCost > 0 ? (cost > 0 ? \"recorded\" : \"estimated\") : undefined,\n parts,\n });\n }\n\n const cleanedMessages = cleanParsedMessages(messages);\n const title = resolveSessionTitle(\n String(sessionRow.title ?? \"\"),\n firstUserMessageTitle(cleanedMessages),\n null,\n );\n const stats: SessionHead[\"stats\"] = {\n message_count: cleanedMessages.length,\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_cost: 0,\n };\n for (const message of cleanedMessages) {\n stats.total_cost += message.cost ?? 0;\n stats.total_input_tokens += message.tokens?.input ?? 0;\n stats.total_output_tokens += message.tokens?.output ?? 0;\n if (message.cost_source === \"estimated\") hasEstimatedCost = true;\n }\n\n for (const childStats of this.sumChildTokenStats(db, sessionId)) {\n stats.total_cost += childStats.total_cost;\n stats.total_input_tokens += childStats.total_input_tokens;\n stats.total_output_tokens += childStats.total_output_tokens;\n if (childStats.cost_source === \"estimated\") hasEstimatedCost = true;\n }\n\n return {\n reference: { agentName: this.name, sessionId: id },\n id,\n title,\n slug,\n directory,\n parent_reference:\n sessionRow.parent_id == null || String(sessionRow.parent_id) === \"\"\n ? undefined\n : { agentName: this.name, sessionId: String(sessionRow.parent_id) },\n version: asString(sessionRow.version) ?? undefined,\n time_created: timeCreated,\n time_updated: timeUpdated,\n summary_files: sessionRow.summary_files ?? undefined,\n stats: {\n message_count: stats.message_count,\n total_input_tokens: stats.total_input_tokens,\n total_output_tokens: stats.total_output_tokens,\n total_cost: stats.total_cost,\n cost_source:\n stats.total_cost > 0 ? (hasEstimatedCost ? \"estimated\" : \"recorded\") : undefined,\n },\n messages: cleanedMessages,\n };\n } finally {\n db.close();\n }\n }\n}\n","import { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { join, basename, dirname } from \"node:path\";\nimport {\n FileSystemSessionSource,\n getParsedSession,\n matchesScanWindow,\n parsedSession,\n skippedSession,\n} from \"./base.js\";\nimport type {\n AgentScanOptions,\n ParseSessionResult,\n SessionCacheMeta,\n SessionSourceRef,\n} from \"./base.js\";\nimport type { SessionHead, SessionDetail, MessagePart } from \"../types/index.js\";\nimport { firstExisting, resolveHomePath } from \"../discovery/paths.js\";\nimport { readJsonlFile } from \"../utils/jsonl.js\";\nimport { normalizeTitleText, resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport { isInternalEventType } from \"../utils/parse-cleanup.js\";\nimport { cleanInternalText } from \"../utils/session-normalization.js\";\nimport { estimateTokenCost } from \"../utils/cost.js\";\nimport {\n asArray,\n asNumber,\n asRecord,\n asString,\n narrowField,\n reportFieldMismatch,\n} from \"../utils/narrow.js\";\nimport { TranscriptBuilder, type TranscriptMessageInput } from \"./transcript-builder.js\";\n\nconst KIMI_TOOL_TITLE_MAP: Record<string, string> = {\n ReadFile: \"read\",\n Glob: \"glob\",\n StrReplaceFile: \"edit\",\n Grep: \"grep\",\n WriteFile: \"write\",\n Shell: \"bash\",\n};\n\nconst KIMI_IGNORED_TOOLS = new Set([\"SetTodoList\"]);\n\nexport function resolveKimiDataRoot(): string {\n return resolveHomePath(\"KIMI_SHARE_DIR\", \".kimi\");\n}\n\nfunction mapToolTitle(toolName: string): string {\n return KIMI_TOOL_TITLE_MAP[toolName] ?? toolName;\n}\n\n/**\n * 会话源的轻量视图:只需要目录遍历 + 小 JSON 文件(state/metadata)即可得出,\n * 不触碰 transcript。枚举路径(listSessionSources)每次刷新都会跑,只用这一层。\n */\ninterface SessionSource {\n id: string;\n sourcePath: string;\n cwd: string;\n contextFile: string | null;\n wireFile: string | null;\n createdAt: number;\n metaFile: string;\n explicitTitle: string;\n}\n\ninterface SessionMeta extends SessionCacheMeta, SessionSource {\n title: string;\n /**\n * Mirrors createdAt, which is what listSessionSources window-filters on.\n * diffSessionSources compares this against the scan window to tell \"outside\n * the window\" apart from \"deleted on disk\"; the two must be the same quantity.\n */\n sourceMtimeMs: number;\n}\n\n/** Reads state/metadata `wire_mtime`; reports drift when the field is present but not a number. */\nfunction readWireMtime(record: Record<string, unknown>): number | null {\n return narrowField(\"kimi\", \"session.wire_mtime\", record.wire_mtime, asNumber) ?? null;\n}\n\n/** Reads a wire record's `timestamp`; reports drift when the field is present but not a number. */\nfunction readWireTimestamp(record: Record<string, unknown>): number {\n return narrowField(\"kimi\", \"wire.timestamp\", record.timestamp, asNumber) ?? 0;\n}\n\n/** Reads a token count from a usage record; reports drift when the field is present but not a number. */\nfunction extractTokenField(usage: Record<string, unknown>, field: string): number {\n return narrowField(\"kimi\", `usage.${field}`, usage[field], asNumber) ?? 0;\n}\n\nfunction normalizeToolArguments(raw: unknown): unknown {\n if (typeof raw === \"string\") {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n }\n return raw;\n}\n\nfunction normalizeToolOutputParts(content: unknown, timestampMs: number): MessagePart[] {\n if (typeof content === \"string\") {\n const text = cleanInternalText(content);\n return text ? [{ type: \"text\" as const, text, time_created: timestampMs }] : [];\n }\n if (Array.isArray(content)) {\n const parts: MessagePart[] = [];\n for (const item of content) {\n const record = asRecord(item);\n if (record && \"text\" in record) {\n const text = String(record.text ?? \"\");\n const cleaned = cleanInternalText(text);\n if (cleaned) parts.push({ type: \"text\", text: cleaned, time_created: timestampMs });\n } else if (typeof item === \"string\") {\n const text = cleanInternalText(item);\n if (text) parts.push({ type: \"text\", text, time_created: timestampMs });\n }\n }\n return parts;\n }\n if (content == null) return [];\n const text = cleanInternalText(String(content));\n return text ? [{ type: \"text\", text, time_created: timestampMs }] : [];\n}\n\nfunction normalizeWireToolOutputParts(returnValue: unknown, timestampMs: number): MessagePart[] {\n if (returnValue == null) return [];\n if (typeof returnValue === \"string\") {\n const text = cleanInternalText(returnValue);\n return text ? [{ type: \"text\" as const, text, time_created: timestampMs }] : [];\n }\n if (typeof returnValue === \"object\") {\n const text = cleanInternalText(JSON.stringify(returnValue, null, 2));\n return text ? [{ type: \"text\", text, time_created: timestampMs }] : [];\n }\n const text = cleanInternalText(String(returnValue));\n return text ? [{ type: \"text\", text, time_created: timestampMs }] : [];\n}\n\nfunction kimiContentText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n\n return content\n .map((item) => {\n if (typeof item === \"string\") return item;\n const record = asRecord(item);\n if (record) return String(record.text ?? record.content ?? \"\");\n return \"\";\n })\n .join(\" \");\n}\n\nfunction extractFirstUserTitle(contextFile: string | null, wireFile: string | null): string | null {\n if (contextFile && existsSync(contextFile)) {\n for (const record of readJsonlFile(contextFile)) {\n if (record.role !== \"user\") continue;\n const title = normalizeTitleText(kimiContentText(record.content));\n if (title) return title;\n }\n }\n\n if (wireFile && existsSync(wireFile)) {\n for (const record of readJsonlFile(wireFile)) {\n const message = asRecord(record.message) ?? {};\n if (message.type !== \"TurnBegin\") continue;\n const payload = asRecord(message.payload) ?? {};\n const userInput = payload.user_input;\n if (!Array.isArray(userInput)) continue;\n const title = normalizeTitleText(kimiContentText(userInput));\n if (title) return title;\n }\n }\n\n return null;\n}\n\nexport class KimiAgent extends FileSystemSessionSource<SessionMeta> {\n readonly name = \"kimi\";\n readonly displayName = \"Kimi-Cli\";\n\n private basePath: string | null = null;\n private projectMap = new Map<string, string>();\n private defaultModel: string | null = null;\n\n private findBasePath(): string | null {\n return firstExisting(join(resolveKimiDataRoot(), \"sessions\"), \"data/kimi\");\n }\n\n getSessionWatchPlan() {\n const dataRoot = resolveKimiDataRoot();\n return {\n status: \"supported\" as const,\n targets: [{ root: dataRoot, path: join(dataRoot, \"sessions\") }, { path: \"data/kimi\" }],\n };\n }\n\n /** Parse kimi.json and build md5(project_path) → cwd mapping */\n private loadKimiConfig(): void {\n const dataRoot = resolveKimiDataRoot();\n const configPath = join(dataRoot, \"kimi.json\");\n const tomlPath = join(dataRoot, \"config.toml\");\n if (existsSync(tomlPath)) {\n const configText = readFileSync(tomlPath, \"utf-8\");\n this.defaultModel = configText.match(/^default_model\\s*=\\s*\"([^\"]+)\"/m)?.[1] ?? null;\n }\n if (!existsSync(configPath)) return;\n try {\n const raw = asRecord(JSON.parse(readFileSync(configPath, \"utf-8\")));\n const workDirs = asArray(raw?.work_dirs);\n if (!workDirs) return;\n for (const wd of workDirs) {\n const path = asString(asRecord(wd)?.path);\n if (!path) continue;\n const hash = createHash(\"md5\").update(path).digest(\"hex\");\n this.projectMap.set(hash, path);\n }\n } catch {\n // ignore malformed config\n }\n }\n\n isAvailable(): boolean {\n this.basePath = this.findBasePath();\n if (!this.basePath) return false;\n this.loadKimiConfig();\n try {\n return this.listSessionDirs().length > 0;\n } catch {\n // ignore\n }\n return false;\n }\n\n /** Walk sessions/{project_hash}/{session_id}/ and find valid session dirs */\n private listSessionDirs(): string[] {\n if (!this.basePath) return [];\n const dirs: string[] = [];\n try {\n for (const hashEntry of readdirSync(this.basePath, { withFileTypes: true })) {\n if (!hashEntry.isDirectory()) continue;\n const hashPath = join(this.basePath, hashEntry.name);\n try {\n for (const sessionEntry of readdirSync(hashPath, { withFileTypes: true })) {\n if (!sessionEntry.isDirectory()) continue;\n const sessionPath = join(hashPath, sessionEntry.name);\n if (\n existsSync(join(sessionPath, \"metadata.json\")) ||\n existsSync(join(sessionPath, \"state.json\"))\n ) {\n dirs.push(sessionPath);\n }\n }\n } catch {\n // skip unreadable hash dirs\n }\n }\n } catch {\n // skip unreadable base\n }\n return dirs;\n }\n\n /**\n * 解析会话源,优先 state.json 而非 metadata.json。\n * 只读小 JSON 文件与 statSync,不触碰 transcript——枚举路径依赖这一点。\n */\n private resolveSessionSourceResult(sessionDir: string): ParseSessionResult<SessionSource> {\n try {\n const sessionId = basename(sessionDir);\n const projectHash = basename(dirname(sessionDir));\n const contextFile = join(sessionDir, \"context.jsonl\");\n const wireFile = join(sessionDir, \"wire.jsonl\");\n\n const existingContextFile = existsSync(contextFile) ? contextFile : null;\n const existingWireFile = existsSync(wireFile) ? wireFile : null;\n if (!existingContextFile && !existingWireFile) {\n return skippedSession(\"missing transcript\");\n }\n\n const statePath = join(sessionDir, \"state.json\");\n const metaPath = join(sessionDir, \"metadata.json\");\n\n let explicitTitle = \"\";\n let wireMtime: number | null = null;\n let metaFile = \"\";\n\n if (existsSync(statePath)) {\n const state = asRecord(JSON.parse(readFileSync(statePath, \"utf-8\"))) ?? {};\n explicitTitle = String(state.custom_title ?? \"\");\n wireMtime = readWireMtime(state);\n metaFile = statePath;\n } else if (existsSync(metaPath)) {\n const meta = asRecord(JSON.parse(readFileSync(metaPath, \"utf-8\"))) ?? {};\n explicitTitle = String(meta.title ?? \"\");\n wireMtime = readWireMtime(meta);\n metaFile = metaPath;\n }\n\n const createdAt =\n wireMtime !== null\n ? wireMtime * 1000\n : metaFile\n ? statSync(metaFile).mtimeMs\n : statSync(sessionDir).mtimeMs;\n\n return parsedSession({\n id: sessionId,\n sourcePath: sessionDir,\n cwd: this.projectMap.get(projectHash) || \"\",\n contextFile: existingContextFile,\n wireFile: existingWireFile,\n createdAt,\n metaFile,\n explicitTitle,\n });\n } catch {\n return skippedSession(\"malformed metadata\");\n }\n }\n\n /**\n * 在会话源之上补齐 title。仅当 state/metadata 里没有可用标题时才回退去读\n * transcript 找首条用户消息,所以标题解析的成本只在真正需要重解析时付出。\n */\n private parseSessionDirResult(sessionDir: string): ParseSessionResult<SessionMeta> {\n const result = this.resolveSessionSourceResult(sessionDir);\n if (result.status !== \"parsed\") return result;\n\n const source = result.data;\n const title =\n normalizeTitleText(source.explicitTitle) ??\n resolveSessionTitle(null, extractFirstUserTitle(source.contextFile, source.wireFile), null);\n\n return parsedSession({ ...source, title, sourceMtimeMs: source.createdAt });\n }\n\n listSessionSources(options?: AgentScanOptions): SessionSourceRef[] {\n if (!this.basePath) return [];\n const refs: SessionSourceRef[] = [];\n for (const dir of this.listSessionDirs()) {\n const source = getParsedSession(this.resolveSessionSourceResult(dir));\n if (!source || !matchesScanWindow(source.createdAt, options)) continue;\n refs.push({\n sessionId: source.id,\n sourcePath: source.sourcePath,\n fingerprint: this.sourceFingerprint(source),\n });\n }\n return refs;\n }\n\n scanSessionSource(sourcePath: string): SessionHead | null {\n const meta = getParsedSession(this.parseSessionDirResult(sourcePath));\n if (!meta) return null;\n meta.sourceFingerprint = this.sourceFingerprint(meta);\n this.sessionMetaMap.set(meta.id, meta);\n const stats = this.extractStats(meta.sourcePath);\n return {\n id: meta.id,\n slug: `kimi/${meta.id}`,\n title: meta.title,\n directory: meta.cwd,\n time_created: meta.createdAt,\n time_updated: meta.createdAt,\n stats,\n };\n }\n\n getSessionData(sessionId: string): SessionDetail {\n const meta = this.sessionMetaMap.get(sessionId);\n if (!meta) throw new Error(`Session not found: ${sessionId}`);\n\n if (meta.contextFile) {\n return this.getSessionDataFromContext(meta);\n }\n return this.getSessionDataFromWire(meta);\n }\n\n private getSessionDataFromContext(meta: SessionMeta): SessionDetail {\n if (!meta.contextFile) throw new Error(\"context.jsonl is missing\");\n\n const builder = new TranscriptBuilder();\n const ignoredToolCallIds = new Set<string>();\n\n let seq = 0;\n const fallbackTs = meta.createdAt;\n for (const record of readJsonlFile(meta.contextFile)) {\n seq++;\n try {\n const role = String(record.role ?? \"\");\n if (role === \"_checkpoint\" || role === \"_usage\" || isInternalEventType(role)) continue;\n\n if (role === \"user\") {\n const text = cleanInternalText(kimiContentText(record.content));\n if (text) {\n builder.appendMessage({\n id: `context-${seq}`,\n role: \"user\",\n timestampMs: fallbackTs,\n parts: [{ type: \"text\", text, time_created: fallbackTs }],\n });\n }\n continue;\n }\n\n if (role === \"assistant\") {\n const message = this.buildContextAssistantMessage(\n record,\n seq,\n ignoredToolCallIds,\n fallbackTs,\n );\n if (!message) continue;\n builder.appendMessage(message);\n continue;\n }\n\n if (role === \"tool\") {\n const callId = String(record.tool_call_id ?? \"\").trim();\n if (callId && ignoredToolCallIds.has(callId)) continue;\n const outputParts = normalizeToolOutputParts(record.content, fallbackTs);\n if (callId && this.backfillToolOutput(builder, callId, outputParts)) {\n continue;\n }\n if (outputParts.length > 0) {\n builder.appendMessage({\n id: `context-${seq}`,\n role: \"tool\",\n timestampMs: fallbackTs,\n parts: outputParts,\n });\n }\n }\n } catch {\n // skip\n }\n }\n\n const stats = this.extractStats(meta.sourcePath);\n return this.buildSessionData(meta, builder, stats);\n }\n\n private getSessionDataFromWire(meta: SessionMeta): SessionDetail {\n const wirePath = meta.wireFile ?? join(meta.sourcePath, \"wire.jsonl\");\n if (!existsSync(wirePath)) throw new Error(\"wire.jsonl is missing\");\n\n const builder = new TranscriptBuilder();\n const ignoredToolCallIds = new Set<string>();\n const openToolArgumentBuffer = new Map<string, string>();\n\n let openToolCallId: string | null = null;\n let seq = 0;\n\n for (const record of readJsonlFile(wirePath)) {\n seq++;\n try {\n const message = asRecord(record.message) ?? {};\n const msgType = asString(message.type) ?? \"\";\n if (isInternalEventType(msgType)) continue;\n const payload = asRecord(message.payload) ?? {};\n const timestampMs = Math.floor(readWireTimestamp(record) * 1000);\n\n // Bind usage to the most recent assistant message without tokens\n const usage = asRecord(message[\"usage\"]);\n if (usage) {\n const inputTokens = extractTokenField(usage, \"input_tokens\");\n const outputTokens = extractTokenField(usage, \"output_tokens\");\n if (inputTokens || outputTokens) {\n const tokens = { input: inputTokens, output: outputTokens };\n const cost = estimateTokenCost(this.defaultModel, tokens);\n builder.attachUsageToLatestAssistant(tokens, {\n model: this.defaultModel,\n cost: cost ?? undefined,\n costSource: cost === null ? undefined : \"estimated\",\n });\n }\n }\n\n if (msgType === \"TurnBegin\") {\n const userInput = payload.user_input;\n if (Array.isArray(userInput) && userInput.length > 0) {\n const text = cleanInternalText(kimiContentText(userInput));\n if (text) {\n builder.appendMessage({\n id: `wire-${seq}`,\n role: \"user\",\n timestampMs,\n parts: [{ type: \"text\", text, time_created: timestampMs }],\n });\n }\n }\n builder.beginTurn();\n openToolCallId = null;\n continue;\n }\n\n if (msgType === \"ContentPart\") {\n const partType = String(payload.type ?? \"\");\n if (partType === \"think\") {\n const text = cleanInternalText(String(payload.think ?? \"\"));\n if (text) {\n builder.appendAssistantPart(\n { type: \"reasoning\", text, time_created: timestampMs },\n { id: `wire-${seq}`, timestampMs: 0, agent: \"kimi\" },\n { grouping: \"current\" },\n );\n }\n } else if (partType === \"text\") {\n const text = cleanInternalText(String(payload.text ?? \"\"));\n if (text) {\n builder.appendAssistantPart(\n { type: \"text\", text, time_created: timestampMs },\n { id: `wire-${seq}`, timestampMs: 0, agent: \"kimi\" },\n { grouping: \"current\" },\n );\n }\n }\n continue;\n }\n\n if (msgType === \"ToolCall\") {\n const function_ = asRecord(payload.function);\n const toolName = String(function_?.name ?? \"\").trim();\n const callId = String(payload.id ?? \"\").trim();\n\n if (toolName && callId && KIMI_IGNORED_TOOLS.has(toolName)) {\n ignoredToolCallIds.add(callId);\n openToolCallId = callId;\n continue;\n }\n\n if (!function_ || !callId || !toolName) continue;\n\n const rawArgs = function_.arguments;\n const normalizedArgs = normalizeToolArguments(rawArgs);\n const buffer =\n typeof rawArgs === \"string\" && typeof normalizedArgs !== \"string\" ? rawArgs : null;\n\n const toolPart: MessagePart = {\n type: \"tool\",\n tool: toolName,\n callID: callId,\n title: mapToolTitle(toolName),\n state: { status: \"running\", input: normalizedArgs, output: null },\n time_created: timestampMs,\n };\n\n builder.appendToolCall(\n toolPart,\n { id: `wire-${seq}`, timestampMs: 0, agent: \"kimi\" },\n { markModeAsTool: true, target: \"current\" },\n );\n openToolCallId = callId;\n\n if (buffer !== null) {\n openToolArgumentBuffer.set(callId, buffer);\n }\n continue;\n }\n\n if (msgType === \"ToolCallPart\") {\n if (openToolCallId && ignoredToolCallIds.has(openToolCallId)) continue;\n const argumentsPart = String(payload.arguments_part ?? \"\");\n this.appendWireToolCallPart(\n argumentsPart,\n openToolCallId,\n openToolArgumentBuffer,\n builder,\n );\n continue;\n }\n\n if (msgType === \"ToolResult\") {\n const callId = String(payload.tool_call_id ?? \"\").trim();\n if (callId && ignoredToolCallIds.has(callId)) continue;\n const outputParts = normalizeWireToolOutputParts(payload.return_value, timestampMs);\n if (callId && this.backfillToolOutput(builder, callId, outputParts)) {\n continue;\n }\n if (outputParts.length > 0) {\n builder.appendMessage({\n id: `wire-${seq}`,\n role: \"tool\",\n timestampMs,\n parts: outputParts,\n });\n }\n continue;\n }\n\n // Skip StepBegin, StatusUpdate, ApprovalRequest, ApprovalResponse, TurnEnd\n } catch {\n // skip\n }\n }\n\n const stats = this.extractStats(meta.sourcePath);\n return this.buildSessionData(meta, builder, stats);\n }\n\n // --- Helpers ---\n\n private sourceFingerprint(meta: Pick<SessionSource, \"metaFile\" | \"contextFile\" | \"wireFile\">) {\n return JSON.stringify([\n this.readFileMtimeMs(meta.metaFile),\n this.readFileMtimeMs(meta.contextFile),\n this.readFileMtimeMs(meta.wireFile),\n ]);\n }\n\n private buildContextAssistantMessage(\n record: Record<string, unknown>,\n seq: number,\n ignoredToolCallIds: Set<string>,\n fallbackTs: number,\n ): TranscriptMessageInput | null {\n const parts: MessagePart[] = [];\n\n const content = record.content;\n if (Array.isArray(content)) {\n for (const item of content) {\n const ci = asRecord(item);\n if (!ci) continue;\n const partType = String(ci.type ?? \"\");\n\n if (partType === \"think\") {\n const text = cleanInternalText(String(ci.think ?? \"\"));\n if (text) parts.push({ type: \"reasoning\", text, time_created: fallbackTs });\n } else if (partType === \"text\") {\n const text = cleanInternalText(String(ci.text ?? \"\"));\n if (text) parts.push({ type: \"text\", text, time_created: fallbackTs });\n }\n }\n }\n\n const toolCalls = asArray(record.tool_calls);\n if (toolCalls) {\n for (const tc of toolCalls) {\n const tcRecord = asRecord(tc);\n const function_ = asRecord(tcRecord?.function);\n\n if (!function_) continue;\n const toolName = String(function_.name ?? \"\").trim();\n const callId = String(tcRecord?.id ?? \"\").trim();\n\n if (toolName && callId && KIMI_IGNORED_TOOLS.has(toolName)) {\n ignoredToolCallIds.add(callId);\n continue;\n }\n\n if (!toolName || !callId) continue;\n\n const part: MessagePart = {\n type: \"tool\",\n tool: toolName,\n callID: callId,\n title: mapToolTitle(toolName),\n state: {\n status: \"running\",\n input: normalizeToolArguments(function_.arguments),\n output: null,\n },\n time_created: fallbackTs,\n };\n parts.push(part);\n }\n }\n\n if (parts.length === 0) {\n return null;\n }\n\n const allTools = parts.every((p) => p.type === \"tool\");\n return {\n id: `context-${seq}`,\n role: \"assistant\",\n timestampMs: fallbackTs,\n parts,\n agent: \"kimi\",\n mode: allTools ? \"tool\" : undefined,\n };\n }\n\n private appendWireToolCallPart(\n argumentsPart: string,\n openCallId: string | null,\n buffer: Map<string, string>,\n builder: TranscriptBuilder,\n ): void {\n if (!openCallId) return;\n\n const existing = buffer.get(openCallId) ?? \"\";\n const combined = existing + argumentsPart;\n\n try {\n const parsed: unknown = JSON.parse(combined);\n if (\n builder.updateToolCall(openCallId, (part) => {\n part.state.input = parsed;\n })\n ) {\n buffer.delete(openCallId);\n }\n } catch {\n buffer.set(openCallId, combined);\n }\n }\n\n private backfillToolOutput(\n builder: TranscriptBuilder,\n callId: string,\n outputParts: MessagePart[],\n ): boolean {\n if (!outputParts.length || !callId) return false;\n\n return builder.resolveToolCall(callId, { output: [...outputParts] });\n }\n\n /** Applies a `_usage` record's running total; other records are ignored. */\n private applyUsageTotal(record: Record<string, unknown>, stats: SessionDetail[\"stats\"]): void {\n if (record.role !== \"_usage\") return;\n const tokenCount = asNumber(record.token_count);\n if (tokenCount === undefined) {\n reportFieldMismatch(\"kimi\", \"usage.token_count\");\n return;\n }\n stats.total_tokens = tokenCount;\n }\n\n private extractStats(sessionDir: string): SessionDetail[\"stats\"] {\n let totalCost = 0;\n const stats: SessionDetail[\"stats\"] = {\n total_cost: 0,\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_tokens: 0,\n message_count: 0,\n };\n\n const wirePath = join(sessionDir, \"wire.jsonl\");\n if (!existsSync(wirePath)) return stats;\n\n // The `_usage` running total is read from context.jsonl when it exists.\n // Otherwise it lives in wire.jsonl — the same file this pass already walks,\n // so fold it in here rather than reading wire.jsonl a second time.\n const contextPath = join(sessionDir, \"context.jsonl\");\n const hasContext = existsSync(contextPath);\n\n try {\n for (const record of readJsonlFile(wirePath)) {\n const tokenUsage = asRecord(asRecord(record.message)?.usage);\n if (tokenUsage) {\n const inputTokens = extractTokenField(tokenUsage, \"input_tokens\");\n const outputTokens = extractTokenField(tokenUsage, \"output_tokens\");\n stats.total_input_tokens += inputTokens;\n stats.total_output_tokens += outputTokens;\n const cost = estimateTokenCost(this.defaultModel, {\n input: inputTokens,\n output: outputTokens,\n });\n if (cost !== null) totalCost += cost;\n }\n if (!hasContext) this.applyUsageTotal(record, stats);\n }\n } catch {\n // skip unreadable wire logs\n }\n\n if (hasContext) {\n try {\n for (const record of readJsonlFile(contextPath)) this.applyUsageTotal(record, stats);\n } catch {\n // skip unreadable context logs\n }\n }\n\n stats.total_cost = Number(totalCost.toFixed(8));\n if (stats.total_cost > 0) {\n stats.cost_source = \"estimated\";\n }\n\n return stats;\n }\n\n private buildSessionData(\n meta: SessionMeta,\n builder: TranscriptBuilder,\n stats: SessionDetail[\"stats\"],\n ): SessionDetail {\n const transcript = builder.finish(stats);\n return {\n reference: { agentName: this.name, sessionId: meta.id },\n id: meta.id,\n title: meta.title,\n slug: `kimi/${meta.id}`,\n directory: meta.cwd,\n time_created: meta.createdAt,\n time_updated: meta.createdAt,\n stats: transcript.stats,\n messages: transcript.messages,\n };\n }\n}\n","import { existsSync, readFileSync, readdirSync, statSync } from \"node:fs\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport {\n FileSystemSessionSource,\n getParsedSession,\n matchesScanWindow,\n parsedSession,\n skippedSession,\n} from \"./base.js\";\nimport type {\n AgentScanOptions,\n ParseSessionResult,\n SessionCacheMeta,\n SessionSourceRef,\n} from \"./base.js\";\nimport type {\n MessagePart,\n SessionDetail,\n SessionHead,\n SessionStats,\n ToolPart,\n} from \"../types/index.js\";\nimport { resolveHomePath } from \"../discovery/paths.js\";\nimport { readJsonlFile } from \"../utils/jsonl.js\";\nimport { asArray, asNumber, asRecord, asString } from \"../utils/narrow.js\";\nimport { cleanInternalText } from \"../utils/session-normalization.js\";\nimport { normalizeTitleText, resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport { estimateTokenCost } from \"../utils/cost.js\";\nimport { TranscriptBuilder, type TranscriptMessageInput } from \"./transcript-builder.js\";\n\nconst KIMI_CODE_TOOL_TITLE_MAP: Record<string, string> = {\n Read: \"read\",\n Write: \"write\",\n Edit: \"edit\",\n Bash: \"bash\",\n TodoList: \"todo\",\n AskUserQuestion: \"ask\",\n EnterPlanMode: \"plan mode\",\n ExitPlanMode: \"plan approved\",\n ReadFile: \"read\",\n Glob: \"glob\",\n StrReplaceFile: \"edit\",\n Grep: \"grep\",\n WriteFile: \"write\",\n Shell: \"bash\",\n};\n\nconst KIMI_CODE_IGNORED_TOOLS = new Set([\"SetTodoList\"]);\n\nexport function resolveKimiCodeDataRoot(): string {\n return resolveHomePath(\"KIMI_CODE_HOME\", \".kimi-code\");\n}\n\ninterface SessionSource {\n id: string;\n sourcePath: string;\n stateFile: string;\n wireFile: string;\n workDir: string;\n createdAt: number;\n updatedAt: number;\n explicitTitle: string;\n}\n\ninterface SessionMeta extends SessionCacheMeta, SessionSource {\n title: string;\n sourceMtimeMs: number;\n}\n\ninterface UsageTotals {\n totalCost: number;\n totalInputTokens: number;\n totalOutputTokens: number;\n totalCacheReadTokens: number;\n totalCacheCreateTokens: number;\n modelUsage: Record<string, number>;\n}\n\ninterface ParsedWire {\n builder: TranscriptBuilder;\n stats: SessionStats;\n firstUserTitle: string | null;\n modelUsage: Record<string, number>;\n}\n\nfunction mapToolTitle(toolName: string): string {\n return KIMI_CODE_TOOL_TITLE_MAP[toolName] ?? toolName;\n}\n\nfunction normalizeToolArguments(raw: unknown): unknown {\n if (typeof raw !== \"string\") return raw;\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n}\n\nfunction parseTimestamp(raw: unknown): number | null {\n if (typeof raw === \"number\") return Number.isFinite(raw) ? raw : null;\n if (typeof raw !== \"string\" || raw.trim() === \"\") return null;\n\n const numeric = Number(raw);\n if (Number.isFinite(numeric)) return numeric;\n const parsed = Date.parse(raw);\n return Number.isFinite(parsed) ? parsed : null;\n}\n\nfunction timestampFromRecord(record: Record<string, unknown>): number {\n return parseTimestamp(record.time) ?? 0;\n}\n\nfunction contentText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) {\n const record = asRecord(content);\n return record ? String(record.text ?? \"\") : \"\";\n }\n\n return content\n .map((item) => {\n if (typeof item === \"string\") return item;\n const record = asRecord(item);\n return record ? String(record.text ?? \"\") : \"\";\n })\n .join(\" \");\n}\n\nfunction contentParts(content: unknown, timestampMs: number): MessagePart[] {\n const values = Array.isArray(content) ? content : [content];\n const parts: MessagePart[] = [];\n\n for (const value of values) {\n if (typeof value === \"string\") {\n const text = cleanInternalText(value);\n if (text) parts.push({ type: \"text\", text, time_created: timestampMs });\n continue;\n }\n\n const record = asRecord(value);\n if (!record) continue;\n const type = asString(record.type) ?? \"\";\n if (type === \"text\") {\n const text = cleanInternalText(asString(record.text) ?? \"\");\n if (text) parts.push({ type: \"text\", text, time_created: timestampMs });\n continue;\n }\n if (type === \"think\") {\n const text = cleanInternalText(asString(record.think) ?? \"\");\n if (text) parts.push({ type: \"reasoning\", text, time_created: timestampMs });\n continue;\n }\n if (type === \"plan\") {\n const text = cleanInternalText(asString(record.text) ?? \"\");\n if (text) {\n parts.push({\n type: \"plan\",\n text,\n approval_status: record.approved === false ? \"fail\" : \"success\",\n time_created: timestampMs,\n });\n }\n continue;\n }\n if (type === \"image\") {\n const source = asRecord(record.source);\n const imageUrl = asRecord(record.imageUrl);\n const url =\n asString(record.url) ??\n asString(imageUrl?.url) ??\n (source?.kind === \"url\" ? asString(source.url) : undefined);\n const data =\n asString(record.data) ?? (source?.kind === \"base64\" ? asString(source.data) : undefined);\n const mimeType =\n asString(record.mime_type) ??\n asString(record.media_type) ??\n (source?.kind === \"base64\" ? asString(source.media_type) : undefined) ??\n \"application/octet-stream\";\n if (url) parts.push({ type: \"image\", url, mime_type: mimeType, time_created: timestampMs });\n else if (data) {\n parts.push({\n type: \"image\",\n data,\n mime_type: mimeType,\n time_created: timestampMs,\n });\n }\n continue;\n }\n if (type === \"image_url\") {\n const imageUrl = asRecord(record.imageUrl);\n const url = asString(imageUrl?.url) ?? asString(record.url);\n if (url) parts.push({ type: \"image\", url, time_created: timestampMs });\n }\n }\n\n return parts;\n}\n\nfunction toolOutputParts(output: unknown, timestampMs: number): MessagePart[] {\n if (typeof output === \"string\") {\n const text = cleanInternalText(output);\n return text ? [{ type: \"text\", text, time_created: timestampMs }] : [];\n }\n if (Array.isArray(output)) return contentParts(output, timestampMs);\n if (output == null) return [];\n\n const record = asRecord(output);\n if (record?.type === \"text\") return contentParts([record], timestampMs);\n\n const text = cleanInternalText(JSON.stringify(output, null, 2));\n return text ? [{ type: \"text\", text, time_created: timestampMs }] : [];\n}\n\nfunction toolPart(toolName: string, callId: string, input: unknown, timestampMs: number): ToolPart {\n return {\n type: \"tool\",\n tool: toolName,\n callID: callId,\n title: mapToolTitle(toolName),\n state: {\n status: \"running\",\n ...(input === undefined ? {} : { input }),\n output: null,\n },\n time_created: timestampMs,\n };\n}\n\nfunction toolCallParts(\n message: Record<string, unknown>,\n timestampMs: number,\n ignoredToolCallIds: Set<string>,\n): MessagePart[] {\n const calls = asArray(message.toolCalls) ?? [];\n const parts: MessagePart[] = [];\n\n for (const call of calls) {\n const callRecord = asRecord(call);\n const functionRecord = asRecord(callRecord?.function) ?? callRecord;\n const toolName = asString(functionRecord?.name)?.trim() ?? \"\";\n const callId = asString(callRecord?.id)?.trim() ?? \"\";\n if (!toolName || !callId) continue;\n if (KIMI_CODE_IGNORED_TOOLS.has(toolName)) {\n ignoredToolCallIds.add(callId);\n continue;\n }\n\n const rawArguments = functionRecord?.arguments ?? callRecord?.arguments;\n parts.push(toolPart(toolName, callId, normalizeToolArguments(rawArguments), timestampMs));\n }\n\n return parts;\n}\n\nfunction addToolResolution(\n builder: TranscriptBuilder,\n callId: string,\n output: unknown,\n timestampMs: number,\n isError = false,\n note?: string,\n): boolean {\n const outputParts = toolOutputParts(output, timestampMs);\n return builder.resolveToolCall(callId, {\n output: outputParts,\n status: isError ? \"error\" : \"completed\",\n ...(note ? { metadata: { note: cleanInternalText(note) } } : {}),\n });\n}\n\nfunction usageNumber(usage: Record<string, unknown>, field: string): number {\n return asNumber(usage[field]) ?? 0;\n}\n\nfunction emptyStats(): SessionStats {\n return {\n message_count: 0,\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_cost: 0,\n };\n}\n\nfunction buildUsageTotals(): UsageTotals {\n return {\n totalCost: 0,\n totalInputTokens: 0,\n totalOutputTokens: 0,\n totalCacheReadTokens: 0,\n totalCacheCreateTokens: 0,\n modelUsage: {},\n };\n}\n\nfunction applyUsage(\n builder: TranscriptBuilder,\n record: Record<string, unknown>,\n activeModel: string | null,\n totals: UsageTotals,\n): void {\n const usage = asRecord(record.usage);\n if (!usage) return;\n\n const cacheRead = usageNumber(usage, \"inputCacheRead\");\n const cacheCreate = usageNumber(usage, \"inputCacheCreation\");\n const inputOther = usageNumber(usage, \"inputOther\");\n const output = usageNumber(usage, \"output\");\n const input = inputOther + cacheRead + cacheCreate;\n const model = asString(record.model) ?? activeModel;\n const tokens = {\n input,\n output,\n cache_read: cacheRead,\n cache_create: cacheCreate,\n };\n const cost = estimateTokenCost(model, tokens);\n\n totals.totalInputTokens += input;\n totals.totalOutputTokens += output;\n totals.totalCacheReadTokens += cacheRead;\n totals.totalCacheCreateTokens += cacheCreate;\n if (model) totals.modelUsage[model] = (totals.modelUsage[model] ?? 0) + input + output;\n if (cost !== null) totals.totalCost += cost;\n\n builder.attachUsageToLatestAssistant(tokens, {\n model,\n cost: cost ?? undefined,\n costSource: cost === null ? undefined : \"estimated\",\n });\n}\n\nfunction readState(stateFile: string): Record<string, unknown> | null {\n try {\n return asRecord(JSON.parse(readFileSync(stateFile, \"utf-8\"))) ?? null;\n } catch {\n return null;\n }\n}\n\nexport class KimiCodeAgent extends FileSystemSessionSource<SessionMeta> {\n readonly name = \"kimi-code\";\n readonly displayName = \"Kimi-Code\";\n\n private basePath: string | null = null;\n private workDirBySessionPath = new Map<string, string>();\n\n private findBasePath(): string | null {\n const sessionsPath = join(resolveKimiCodeDataRoot(), \"sessions\");\n return existsSync(sessionsPath) ? sessionsPath : null;\n }\n\n getSessionWatchPlan() {\n const dataRoot = resolveKimiCodeDataRoot();\n return {\n status: \"supported\" as const,\n targets: [\n { root: dataRoot, path: join(dataRoot, \"sessions\") },\n { root: dataRoot, path: join(dataRoot, \"session_index.jsonl\") },\n ],\n };\n }\n\n isAvailable(): boolean {\n this.basePath = this.findBasePath();\n if (!this.basePath) return false;\n try {\n return this.listSessionDirs().length > 0;\n } catch {\n return false;\n }\n }\n\n private loadSessionIndex(): void {\n this.workDirBySessionPath.clear();\n if (!this.basePath) return;\n\n const indexPath = join(dirname(this.basePath), \"session_index.jsonl\");\n if (!existsSync(indexPath)) return;\n for (const record of readJsonlFile(indexPath)) {\n const sessionPath = asString(record.sessionDir);\n const workDir = asString(record.workDir);\n if (!sessionPath || !workDir) continue;\n this.workDirBySessionPath.set(resolve(sessionPath), workDir);\n }\n }\n\n private listSessionDirs(): string[] {\n if (!this.basePath) return [];\n const dirs: string[] = [];\n\n try {\n for (const bucket of readdirSync(this.basePath, { withFileTypes: true })) {\n if (!bucket.isDirectory()) continue;\n const bucketPath = join(this.basePath, bucket.name);\n for (const session of readdirSync(bucketPath, { withFileTypes: true })) {\n if (!session.isDirectory()) continue;\n const sessionPath = join(bucketPath, session.name);\n if (\n existsSync(join(sessionPath, \"state.json\")) &&\n existsSync(join(sessionPath, \"agents\", \"main\", \"wire.jsonl\"))\n ) {\n dirs.push(sessionPath);\n }\n }\n }\n } catch {\n return dirs;\n }\n\n return dirs;\n }\n\n private resolveSessionSourceResult(sessionDir: string): ParseSessionResult<SessionSource> {\n try {\n const stateFile = join(sessionDir, \"state.json\");\n const wireFile = join(sessionDir, \"agents\", \"main\", \"wire.jsonl\");\n if (!existsSync(stateFile) || !existsSync(wireFile)) return skippedSession(\"missing wire\");\n\n const state = readState(stateFile);\n if (!state) return skippedSession(\"malformed state\");\n\n const stateMtime = statSync(stateFile).mtimeMs;\n const wireMtime = statSync(wireFile).mtimeMs;\n const createdAt =\n parseTimestamp(state.createdAt) ?? parseTimestamp(state.created_at) ?? stateMtime;\n const updatedAt = Math.max(\n parseTimestamp(state.updatedAt) ?? parseTimestamp(state.updated_at) ?? createdAt,\n wireMtime,\n );\n const custom = asRecord(state.custom);\n const workDir =\n asString(state.workDir) ??\n asString(custom?.cwd) ??\n this.workDirBySessionPath.get(resolve(sessionDir)) ??\n \"\";\n const explicitTitle = asString(state.title) ?? asString(state.customTitle) ?? \"\";\n\n return parsedSession({\n id: basename(sessionDir),\n sourcePath: sessionDir,\n stateFile,\n wireFile,\n workDir,\n createdAt,\n updatedAt,\n explicitTitle,\n });\n } catch {\n return skippedSession(\"malformed session\");\n }\n }\n\n private sourceFingerprint(\n source: Pick<SessionSource, \"stateFile\" | \"wireFile\" | \"workDir\">,\n ): string {\n return JSON.stringify([\n this.readFileMtimeMs(source.stateFile),\n this.readFileMtimeMs(source.wireFile),\n source.workDir,\n ]);\n }\n\n listSessionSources(options?: AgentScanOptions): SessionSourceRef[] {\n if (!this.basePath) return [];\n this.loadSessionIndex();\n const refs: SessionSourceRef[] = [];\n\n for (const sessionDir of this.listSessionDirs()) {\n const source = getParsedSession(this.resolveSessionSourceResult(sessionDir));\n if (!source || !matchesScanWindow(source.createdAt, options)) continue;\n refs.push({\n sessionId: source.id,\n sourcePath: source.sourcePath,\n fingerprint: this.sourceFingerprint(source),\n });\n }\n\n return refs;\n }\n\n checkForChanges(sinceTimestamp: number, cachedSessions: SessionHead[]) {\n const result = super.checkForChanges(sinceTimestamp, cachedSessions);\n const emptySessionIds = cachedSessions\n .filter((session) => !this.hasMessages(session))\n .map((session) => session.id);\n if (emptySessionIds.length === 0) return result;\n\n return {\n ...result,\n hasChanges: true,\n changedIds: [...new Set([...(result.changedIds ?? []), ...emptySessionIds])],\n };\n }\n\n filterCachedSessions(sessions: SessionHead[]): SessionHead[] {\n return this.removeEmptyCachedSessions(sessions);\n }\n\n incrementalScan(\n cachedSessions: SessionHead[],\n changedIds: string[],\n refs?: SessionSourceRef[],\n ): SessionHead[] {\n const visibleSessions = this.removeEmptyCachedSessions(cachedSessions);\n return super.incrementalScan(visibleSessions, changedIds, refs);\n }\n\n private hasMessages(session: SessionHead): boolean {\n return session.stats.message_count > 0;\n }\n\n private removeEmptyCachedSessions(sessions: SessionHead[]): SessionHead[] {\n return sessions.filter((session) => {\n if (this.hasMessages(session)) return true;\n this.sessionMetaMap.delete(session.id);\n return false;\n });\n }\n\n scanSessionSource(sourcePath: string): SessionHead | null {\n this.loadSessionIndex();\n const source = getParsedSession(this.resolveSessionSourceResult(sourcePath));\n if (!source) return null;\n\n const parsed = this.parseWire(source);\n const transcript = parsed.builder.finish(parsed.stats);\n if (transcript.messages.length === 0) {\n this.sessionMetaMap.delete(source.id);\n return null;\n }\n\n const title = resolveSessionTitle(source.explicitTitle, parsed.firstUserTitle, null);\n const meta: SessionMeta = {\n ...source,\n title,\n sourceMtimeMs: source.createdAt,\n sourceFingerprint: this.sourceFingerprint(source),\n };\n this.sessionMetaMap.set(meta.id, meta);\n return {\n id: meta.id,\n slug: `${this.name}/${meta.id}`,\n title: meta.title,\n directory: meta.workDir,\n time_created: meta.createdAt,\n time_updated: meta.updatedAt,\n stats: transcript.stats,\n ...(Object.keys(parsed.modelUsage).length > 0 ? { model_usage: parsed.modelUsage } : {}),\n };\n }\n\n getSessionData(sessionId: string): SessionDetail {\n const meta = this.sessionMetaMap.get(sessionId);\n if (!meta) throw new Error(`Session not found: ${sessionId}`);\n\n const parsed = this.parseWire(meta);\n const transcript = parsed.builder.finish(parsed.stats);\n return {\n reference: { agentName: this.name, sessionId: meta.id },\n id: meta.id,\n title: meta.title,\n slug: `${this.name}/${meta.id}`,\n directory: meta.workDir,\n time_created: meta.createdAt,\n time_updated: meta.updatedAt,\n stats: transcript.stats,\n messages: transcript.messages,\n };\n }\n\n private parseWire(source: SessionSource): ParsedWire {\n const builder = new TranscriptBuilder();\n const totals = buildUsageTotals();\n const ignoredToolCallIds = new Set<string>();\n let activeModel: string | null = null;\n let activeProvider: string | null = null;\n let firstUserTitle: string | null = null;\n let sequence = 0;\n\n for (const record of readJsonlFile(source.wireFile)) {\n sequence += 1;\n try {\n const timestampMs = timestampFromRecord(record);\n const recordType = asString(record.type) ?? \"\";\n\n if (recordType === \"llm.request\") {\n activeModel = asString(record.model) ?? activeModel;\n activeProvider = asString(record.provider) ?? activeProvider;\n continue;\n }\n if (recordType === \"config.update\") {\n activeModel = asString(record.modelAlias) ?? activeModel;\n continue;\n }\n if (recordType === \"usage.record\") {\n applyUsage(builder, record, activeModel, totals);\n continue;\n }\n if (recordType === \"context.append_message\") {\n const message = asRecord(record.message);\n if (!message) continue;\n const role = asString(message.role) ?? \"\";\n const messageTimestamp = timestampMs;\n\n if (role === \"user\") {\n const text = normalizeTitleText(contentText(message.content));\n if (!firstUserTitle && text) firstUserTitle = text;\n }\n\n if (role === \"tool\") {\n const callId = asString(message.toolCallId)?.trim() ?? \"\";\n const output = message.content;\n if (callId && ignoredToolCallIds.has(callId)) continue;\n if (callId && addToolResolution(builder, callId, output, messageTimestamp)) continue;\n const outputParts = toolOutputParts(output, messageTimestamp);\n if (outputParts.length > 0) {\n builder.appendMessage({\n id: `wire-${sequence}`,\n role: \"tool\",\n timestampMs: messageTimestamp,\n parts: outputParts,\n });\n }\n continue;\n }\n\n if (role !== \"user\" && role !== \"assistant\") continue;\n const parts = [\n ...contentParts(message.content, messageTimestamp),\n ...(role === \"assistant\"\n ? toolCallParts(message, messageTimestamp, ignoredToolCallIds)\n : []),\n ];\n if (parts.length === 0) continue;\n const allTools = parts.every((part) => part.type === \"tool\");\n const input: TranscriptMessageInput = {\n id: `wire-${sequence}`,\n role,\n timestampMs: messageTimestamp,\n parts,\n ...(role === \"assistant\"\n ? {\n agent: this.name,\n mode: allTools ? \"tool\" : undefined,\n model: activeModel,\n provider: activeProvider,\n }\n : {}),\n };\n builder.appendMessage(input);\n continue;\n }\n if (recordType === \"context.append_loop_event\") {\n const event = asRecord(record.event);\n if (!event) continue;\n const eventType = asString(event.type) ?? \"\";\n const metadata = {\n id: `wire-${sequence}`,\n timestampMs,\n agent: this.name,\n model: activeModel,\n provider: activeProvider,\n };\n\n if (eventType === \"step.begin\") {\n builder.beginTurn();\n continue;\n }\n if (eventType === \"content.part\") {\n const part = asRecord(event.part);\n if (!part) continue;\n const parts = contentParts([part], timestampMs);\n for (const contentPart of parts) {\n if (contentPart.type === \"tool\") continue;\n if (contentPart.type === \"image\" && builder.appendToCurrentAssistant(contentPart)) {\n continue;\n }\n builder.appendAssistantPart(contentPart, metadata, { grouping: \"current\" });\n }\n continue;\n }\n if (eventType === \"tool.call\") {\n const toolName = asString(event.name)?.trim() ?? \"\";\n const callId = asString(event.toolCallId)?.trim() ?? \"\";\n if (!toolName || !callId) continue;\n if (KIMI_CODE_IGNORED_TOOLS.has(toolName)) {\n ignoredToolCallIds.add(callId);\n continue;\n }\n builder.appendToolCall(toolPart(toolName, callId, event.args, timestampMs), metadata, {\n markModeAsTool: true,\n target: \"current\",\n });\n continue;\n }\n if (eventType === \"tool.result\") {\n const callId = asString(event.toolCallId)?.trim() ?? \"\";\n const result = asRecord(event.result);\n if (!callId || ignoredToolCallIds.has(callId)) continue;\n const output = result?.output;\n const isError = result?.isError === true;\n const note = asString(result?.note);\n if (addToolResolution(builder, callId, output, timestampMs, isError, note)) continue;\n const outputParts = toolOutputParts(output, timestampMs);\n if (outputParts.length > 0) {\n builder.appendMessage({\n id: `wire-${sequence}`,\n role: \"tool\",\n timestampMs,\n parts: outputParts,\n });\n }\n }\n continue;\n }\n if (recordType === \"context.apply_compaction\") {\n const summary = cleanInternalText(asString(record.summary) ?? \"\");\n if (summary) {\n builder.appendMessage({\n id: `wire-${sequence}`,\n role: \"user\",\n timestampMs,\n parts: [{ type: \"text\", text: summary, time_created: timestampMs }],\n });\n }\n }\n } catch {\n continue;\n }\n }\n\n const stats: SessionStats = {\n ...emptyStats(),\n total_input_tokens: totals.totalInputTokens,\n total_output_tokens: totals.totalOutputTokens,\n total_cost: Number(totals.totalCost.toFixed(8)),\n total_tokens: totals.totalInputTokens + totals.totalOutputTokens,\n ...(totals.totalCacheReadTokens > 0\n ? { total_cache_read_tokens: totals.totalCacheReadTokens }\n : {}),\n ...(totals.totalCacheCreateTokens > 0\n ? { total_cache_create_tokens: totals.totalCacheCreateTokens }\n : {}),\n ...(totals.totalCost > 0 ? { cost_source: \"estimated\" as const } : {}),\n };\n return { builder, stats, firstUserTitle, modelUsage: totals.modelUsage };\n }\n}\n","import {\n closeSync,\n existsSync,\n openSync,\n readdirSync,\n readFileSync,\n readSync,\n statSync,\n type Dirent,\n} from \"node:fs\";\nimport { join, basename } from \"node:path\";\nimport {\n SingleFileSessionSource,\n filteredSession,\n getParsedSession,\n parsedSession,\n skippedSession,\n} from \"./base.js\";\nimport type { ParseSessionResult } from \"./base.js\";\nimport type { Message, SessionHead, SessionDetail, MessagePart } from \"../types/index.js\";\nimport { firstExisting, resolveHomePath } from \"../discovery/paths.js\";\nimport { parseJsonlLines, readJsonlFile, readJsonlFileLines } from \"../utils/jsonl.js\";\nimport { basenameTitle, normalizeTitleText, resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport { cleanInternalText, isInternalEventType } from \"../utils/session-normalization.js\";\nimport { estimateTokenCost } from \"../utils/cost.js\";\nimport { asRecord, asString, narrowField } from \"../utils/narrow.js\";\nimport { TranscriptBuilder } from \"./transcript-builder.js\";\nimport {\n type ExecInnerCall,\n decodeExecCalls,\n getExecPatchText,\n pickExecOutputTarget,\n splitExecToolName,\n stripExecOutputEnvelope,\n} from \"./codex-exec-decode.js\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst PROPOSED_PLAN_PATTERN = /<proposed_plan>\\s*([\\s\\S]*?)\\s*<\\/proposed_plan>/;\nconst PLAN_APPROVAL_PREFIX = \"PLEASE IMPLEMENT THIS PLAN\";\nconst SUBAGENT_NOTIFICATION_PATTERN =\n /<subagent_notification>\\s*([\\s\\S]*?)\\s*<\\/subagent_notification>/;\nconst HEAD_INDEX_VERSION = \"codex-head-v1\";\nconst PARSER_VERSION = \"codex-parser-v6\";\n\nexport function resolveCodexDataRoot(): string {\n return resolveHomePath(\"CODEX_HOME\", \".codex\");\n}\n\nconst DEVELOPER_LIKE_USER_MARKERS = [\n \"agents.md instructions for\",\n \"<instructions>\",\n \"<environment_context>\",\n \"<permissions instructions>\",\n \"<collaboration_mode>\",\n];\n\nfunction isDeveloperLikeUserMessage(text: string): boolean {\n const lower = text.toLowerCase();\n return DEVELOPER_LIKE_USER_MARKERS.some((m) => lower.includes(m));\n}\n\nconst CODEX_TOOL_TITLE_MAP: Record<string, string> = {\n exec_command: \"bash\",\n apply_patch: \"patch\",\n patch: \"patch\",\n spawn_agent: \"subagent\",\n subagent: \"subagent\",\n};\n\n// ---------------------------------------------------------------------------\n// Session ID extraction\n// ---------------------------------------------------------------------------\n\n/**\n * Extract session UUID from Codex filename.\n * \"rollout-2026-02-03T10-04-47-019c213e-c251-73a3-af66-0ec9d7cb9e29.jsonl\"\n * → last 5 dash-delimited parts joined with \"-\"\n */\nfunction extractSessionId(filename: string): string {\n const stem = basename(filename, \".jsonl\");\n const parts = stem.split(\"-\");\n if (parts.length >= 5) {\n return parts.slice(-5).join(\"-\");\n }\n return stem;\n}\n\n// ---------------------------------------------------------------------------\n// Timestamp\n// ---------------------------------------------------------------------------\n\nfunction parseTimestampMs(data: Record<string, unknown>): number {\n const ts = String(data[\"timestamp\"] ?? \"\").trim();\n if (!ts) return 0;\n try {\n return new Date(ts.includes(\"Z\") ? ts : ts.replace(\" \", \"T\") + \"Z\").getTime();\n } catch {\n return 0;\n }\n}\n\nfunction extractModelName(raw: unknown): string | null {\n return typeof raw === \"string\" && raw.trim() ? raw.trim() : null;\n}\n\nfunction extractCachedInputTokens(usage: Record<string, unknown> | undefined): number {\n if (!usage) return 0;\n return Number(usage[\"cached_input_tokens\"] ?? usage[\"cache_read_input_tokens\"] ?? 0);\n}\n\nfunction narrowRecordField(value: unknown, field: string): Record<string, unknown> | undefined {\n return narrowField(\"codex\", field, value, asRecord);\n}\n\nfunction extractPayload(data: Record<string, unknown>): Record<string, unknown> {\n return narrowRecordField(data[\"payload\"], \"payload\") ?? {};\n}\n\ninterface ThreadMeta {\n threadSource: string;\n parentThreadId: string | null;\n agentNickname: string | null;\n}\n\nfunction extractThreadMeta(firstRecord: Record<string, unknown>): ThreadMeta | null {\n if (firstRecord[\"type\"] !== \"session_meta\") return null;\n const payload = extractPayload(firstRecord);\n const threadSource = asString(payload[\"thread_source\"]) ?? \"\";\n const parentThreadId = asString(payload[\"parent_thread_id\"]) ?? null;\n const agentNickname = asString(payload[\"agent_nickname\"]) ?? null;\n return { threadSource, parentThreadId, agentNickname };\n}\n\nfunction extractTokenUsage(payload: Record<string, unknown>): {\n totalUsage: Record<string, unknown> | undefined;\n lastUsage: Record<string, unknown> | undefined;\n} {\n const info = narrowRecordField(payload[\"info\"], \"token_count.info\");\n return {\n totalUsage: info\n ? narrowRecordField(info[\"total_token_usage\"], \"token_count.total_token_usage\")\n : undefined,\n lastUsage: info\n ? narrowRecordField(info[\"last_token_usage\"], \"token_count.last_token_usage\")\n : undefined,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Tool helpers\n// ---------------------------------------------------------------------------\n\nfunction resolveToolIdentity(\n name: string,\n namespace: unknown,\n): { tool: string; metadata?: { name: string; namespace: string } } {\n const mappedName = CODEX_TOOL_TITLE_MAP[name];\n if (mappedName) return { tool: mappedName };\n\n const namespaceText = typeof namespace === \"string\" ? namespace.trim() : \"\";\n if (!namespaceText) return { tool: name };\n\n const namespaceName = namespaceText.split(\"__\").at(-1) ?? namespaceText;\n const toolName = name.replace(/^[_.]+/, \"\");\n if (!namespaceName) {\n return {\n tool: toolName || name,\n metadata: { name, namespace: namespaceText },\n };\n }\n\n return {\n tool: `${namespaceName}.${toolName || name}`,\n metadata: { name, namespace: namespaceText },\n };\n}\n\nfunction normalizeToolArguments(raw: unknown): unknown {\n if (typeof raw === \"string\") {\n try {\n return JSON.parse(raw);\n } catch {\n return raw;\n }\n }\n return raw;\n}\n\nfunction normalizeCustomToolArguments(toolName: string, input: unknown): unknown {\n if (toolName === \"apply_patch\") {\n return parseApplyPatchInput(input);\n }\n return input;\n}\n\n/**\n * Flatten tool-call output to text. Classic outputs are strings; code-mode\n * outputs are arrays of `{ type: \"input_text\", text }` segments.\n */\nfunction flattenOutputText(output: unknown): string {\n if (typeof output === \"string\") return output;\n if (Array.isArray(output)) {\n return output\n .map((item) => {\n if (typeof item === \"string\") return item;\n const record = asRecord(item);\n return record ? (asString(record[\"text\"]) ?? \"\") : \"\";\n })\n .join(\"\");\n }\n return \"\";\n}\n\nfunction extractAssistantOutputText(payload: Record<string, unknown>): string {\n const content = payload[\"content\"];\n if (Array.isArray(content)) {\n return content\n .map((item) => {\n const record = asRecord(item);\n return record && String(record[\"type\"] ?? \"\") === \"output_text\"\n ? String(record[\"text\"] ?? \"\")\n : \"\";\n })\n .filter(Boolean)\n .join(\"\\n\");\n }\n return \"\";\n}\n\n// ---------------------------------------------------------------------------\n// Patch parsing\n// ---------------------------------------------------------------------------\n\ninterface PatchBlock {\n type: \"write_file\" | \"delete_file\" | \"move_file\" | \"edit_file\";\n path?: string;\n content?: string;\n targetPath?: string;\n}\n\nconst PATCH_BEGIN_RE = /\\*\\*\\* Begin Patch/;\nconst PATCH_END_RE = /\\*\\*\\* End Patch/;\nconst PATCH_HEADER_RE = /\\*\\*\\*\\s+(Add|Delete|Update|Move)\\s+File:\\s*(.+)/;\nconst PATCH_MOVE_TO_RE = /\\*\\*\\*\\s+Move to:\\s*(.+)/;\n\nfunction parseApplyPatchInput(input: unknown): PatchBlock[] {\n const text = typeof input === \"string\" ? input : \"\";\n if (!text) return [];\n\n const blocks: PatchBlock[] = [];\n const lines = text.split(\"\\n\");\n let inPatch = false;\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i]!;\n\n if (!inPatch && PATCH_BEGIN_RE.test(line)) {\n inPatch = true;\n i++;\n continue;\n }\n\n if (inPatch && PATCH_END_RE.test(line)) {\n inPatch = false;\n i++;\n continue;\n }\n\n if (inPatch) {\n const headerMatch = line.match(PATCH_HEADER_RE);\n if (headerMatch) {\n const action = headerMatch[1]!;\n const filePath = headerMatch[2]!.trim();\n i++;\n\n if (action === \"Add\") {\n const content = extractPatchContent(lines, i);\n i = content.nextLineIndex;\n blocks.push({ type: \"write_file\", path: filePath, content: content.text });\n } else if (action === \"Update\") {\n // Check for Move to on the next non-empty line\n let moveToTarget: string | null = null;\n let contentStart = i;\n for (let j = i; j < lines.length; j++) {\n const l = lines[j]!;\n if (!l.trim()) continue;\n const moveMatch = l.match(PATCH_MOVE_TO_RE);\n if (moveMatch) {\n moveToTarget = moveMatch[1]!.trim();\n contentStart = j + 1;\n break;\n }\n break;\n }\n if (moveToTarget) {\n const content = extractPatchContent(lines, contentStart);\n i = content.nextLineIndex;\n blocks.push({\n type: \"move_file\",\n path: filePath,\n targetPath: moveToTarget,\n content: content.text,\n });\n } else {\n const content = extractPatchContent(lines, i);\n i = content.nextLineIndex;\n blocks.push({ type: \"edit_file\", path: filePath, content: content.text });\n }\n } else if (action === \"Delete\") {\n blocks.push({ type: \"delete_file\", path: filePath });\n // No content to read for delete\n }\n continue;\n }\n }\n\n i++;\n }\n\n return blocks;\n}\n\nfunction extractPatchContent(\n lines: string[],\n startIndex: number,\n): { text: string; nextLineIndex: number } {\n const contentLines: string[] = [];\n let i = startIndex;\n while (i < lines.length) {\n const line = lines[i]!;\n // Stop at next patch header or end patch\n if (PATCH_HEADER_RE.test(line) || PATCH_END_RE.test(line)) break;\n contentLines.push(line);\n i++;\n }\n return { text: contentLines.join(\"\\n\"), nextLineIndex: i };\n}\n\n// ---------------------------------------------------------------------------\n// Session meta\n// ---------------------------------------------------------------------------\n\nimport type {\n AgentScanOptions,\n FileSessionMeta,\n SessionCacheMeta,\n SessionSourceFile,\n SessionSourceRef,\n} from \"./base.js\";\n\n/** 一次全量前缀扫构建的 subagent 关系索引;miss 即代表\"无子会话\"。 */\ninterface SubagentIndex {\n childFilesByParent: Map<string, string[]>;\n subagentFiles: Set<string>;\n}\n\ninterface SessionMeta extends FileSessionMeta {\n indexPath: string | null;\n indexMtimeMs: number | null;\n headIndexVersion: string;\n parserVersion: string;\n model: string | null;\n parentThreadId: string | null;\n}\n\nfunction compareSourceActivityDesc(left: SessionSourceFile, right: SessionSourceFile): number {\n const leftTimestamp = sourceTimestamp(left.file, left.stat.mtimeMs);\n const rightTimestamp = sourceTimestamp(right.file, right.stat.mtimeMs);\n return rightTimestamp - leftTimestamp || left.file.localeCompare(right.file);\n}\n\nfunction sourceTimestamp(filePath: string, fallback: number): number {\n // Sort before parsing heads; the rollout filename is the only cheap activity hint.\n const match = basename(filePath).match(/^rollout-(\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2})-/);\n if (!match) return fallback;\n const timestamp = match[1]!.replace(/-(\\d{2})-(\\d{2})$/, \":$1:$2\");\n const parsed = Date.parse(timestamp);\n return Number.isFinite(parsed) ? parsed : fallback;\n}\n\n// ---------------------------------------------------------------------------\n// CodexAgent\n// ---------------------------------------------------------------------------\n\nexport class CodexAgent extends SingleFileSessionSource<SessionMeta> {\n readonly name = \"codex\";\n readonly displayName = \"Codex\";\n\n private basePath: string | null = null;\n private sessionIndexCache = new Map<string, string>();\n private sessionIndexMtime: number | null | undefined;\n private sessionIndexPath: string | undefined;\n private subagentIndex: SubagentIndex | null = null;\n private subagentStatsByParent = new Map<string, SessionHead[\"stats\"][]>();\n\n // ---- BaseAgent implementation ----\n\n private findBasePath(): string | null {\n return firstExisting(join(resolveCodexDataRoot(), \"sessions\"));\n }\n\n getSessionWatchPlan() {\n const dataRoot = resolveCodexDataRoot();\n return {\n status: \"supported\" as const,\n targets: [\n { path: join(dataRoot, \"sessions\") },\n { path: join(dataRoot, \"session_index.jsonl\") },\n ],\n };\n }\n\n isAvailable(): boolean {\n this.basePath = this.findBasePath();\n if (!this.basePath) return false;\n return this.listRolloutFiles().length > 0;\n }\n\n listSessionSources(options?: AgentScanOptions): SessionSourceRef[] {\n if (!this.basePath) return [];\n this.loadSessionIndex();\n return this.listScanSources(options).map(({ file, stat }) => ({\n sessionId: extractSessionId(file),\n sourcePath: file,\n fingerprint: this.sourceFingerprint(file, stat),\n }));\n }\n\n setSessionMetaMap(meta: Map<string, SessionCacheMeta>): void {\n super.setSessionMetaMap(meta);\n this.subagentIndex = null;\n this.subagentStatsByParent.clear();\n }\n\n /**\n * A changed subagent file leaves its parent's aggregated token stats stale,\n * so the parent must re-parse alongside the child.\n */\n expandChangedSessionIds(changedIds: string[], refs?: SessionSourceRef[]): string[] {\n if (changedIds.length === 0) return changedIds;\n const pathById = new Map((refs ?? []).map((ref) => [ref.sessionId, ref.sourcePath]));\n const expanded = new Set(changedIds);\n for (const id of changedIds) {\n const sourcePath = pathById.get(id) ?? this.sessionMetaMap.get(id)?.sourcePath;\n const threadMeta = sourcePath ? this.readThreadMeta(sourcePath) : null;\n // A removed file cannot be read back; cached meta still knows its parent.\n const parentId = threadMeta\n ? threadMeta.threadSource === \"subagent\"\n ? threadMeta.parentThreadId\n : null\n : (this.sessionMetaMap.get(id)?.parentThreadId ?? null);\n if (!parentId) continue;\n expanded.add(parentId);\n this.subagentIndex = null;\n this.subagentStatsByParent.delete(parentId);\n }\n return [...expanded];\n }\n\n private readThreadMeta(filePath: string): ThreadMeta | null {\n try {\n const firstLine = this.readFilePrefix(filePath)\n .split(\"\\n\")\n .filter((l) => l.trim())[0];\n if (!firstLine) return null;\n return extractThreadMeta(JSON.parse(firstLine));\n } catch {\n return null;\n }\n }\n\n private parseTokenStats(filePath: string): SessionHead[\"stats\"] {\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCacheReadTokens = 0;\n let totalCost = 0;\n let activeModel: string | null = null;\n\n let prevCumulativeTotal = 0;\n let prevInput = 0;\n let prevOutput = 0;\n let prevReasoning = 0;\n let prevCachedInput = 0;\n\n for (const line of readJsonlFileLines(filePath)) {\n try {\n const data = JSON.parse(line);\n const recordType = String(data[\"type\"] ?? \"\");\n const payload = extractPayload(data);\n\n if (recordType === \"session_meta\" || recordType === \"turn_context\") {\n const nextModel = extractModelName(payload[\"model\"]);\n if (nextModel) activeModel = nextModel;\n continue;\n }\n\n if (recordType === \"event_msg\" && String(payload[\"type\"] ?? \"\") === \"token_count\") {\n const { totalUsage, lastUsage } = extractTokenUsage(payload);\n const cumulativeTotal = Number(totalUsage?.[\"total_tokens\"] ?? 0);\n if (cumulativeTotal <= 0 || cumulativeTotal === prevCumulativeTotal) continue;\n prevCumulativeTotal = cumulativeTotal;\n\n let inputTokens = 0;\n let outputTokens = 0;\n let reasoningTokens = 0;\n let cacheReadTokens = 0;\n\n if (lastUsage) {\n inputTokens = Number(lastUsage[\"input_tokens\"] ?? 0);\n outputTokens = Number(lastUsage[\"output_tokens\"] ?? 0);\n reasoningTokens = Number(lastUsage[\"reasoning_output_tokens\"] ?? 0);\n cacheReadTokens = extractCachedInputTokens(lastUsage);\n } else if (totalUsage) {\n inputTokens = Number(totalUsage[\"input_tokens\"] ?? 0) - prevInput;\n outputTokens = Number(totalUsage[\"output_tokens\"] ?? 0) - prevOutput;\n reasoningTokens = Number(totalUsage[\"reasoning_output_tokens\"] ?? 0) - prevReasoning;\n cacheReadTokens = extractCachedInputTokens(totalUsage) - prevCachedInput;\n prevInput = Number(totalUsage[\"input_tokens\"] ?? 0);\n prevOutput = Number(totalUsage[\"output_tokens\"] ?? 0);\n prevReasoning = Number(totalUsage[\"reasoning_output_tokens\"] ?? 0);\n prevCachedInput = extractCachedInputTokens(totalUsage);\n }\n\n const totalInput = Math.max(0, inputTokens);\n const totalCacheRead = Math.max(0, cacheReadTokens);\n totalInputTokens += totalInput;\n totalOutputTokens += outputTokens + reasoningTokens;\n totalCacheReadTokens += totalCacheRead;\n totalCost +=\n estimateTokenCost(activeModel, {\n input: totalInput,\n output: outputTokens,\n reasoning: reasoningTokens || undefined,\n cache_read: totalCacheRead || undefined,\n }) ?? 0;\n }\n } catch {\n // skip malformed records\n }\n }\n\n return {\n message_count: 0,\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cache_read_tokens: totalCacheReadTokens || undefined,\n total_cost: totalCost,\n cost_source: totalCost > 0 ? \"estimated\" : undefined,\n };\n }\n\n getSessionData(sessionId: string): SessionDetail {\n const meta = this.sessionMetaMap.get(sessionId);\n if (!meta) throw new Error(`Session not found: ${sessionId}`);\n if (!existsSync(meta.sourcePath)) throw new Error(`Session file missing: ${meta.sourcePath}`);\n this.basePath ??= this.findBasePath();\n\n const transcript = new TranscriptBuilder();\n\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCacheReadTokens = 0;\n let totalCost = 0;\n\n let pendingPlan: MessagePart | null = null;\n let activeModel: string | null = meta.model;\n\n // Token-count dedup state (matches codeburn strategy)\n let prevCumulativeTotal = 0;\n let prevInput = 0;\n let prevOutput = 0;\n let prevReasoning = 0;\n let prevCachedInput = 0;\n\n for (const record of readJsonlFile(meta.sourcePath)) {\n try {\n const recordType = String(record[\"type\"] ?? \"\");\n if (recordType === \"turn_context\") {\n const payload = extractPayload(record);\n activeModel = extractModelName(payload[\"model\"]) ?? activeModel;\n }\n\n pendingPlan = this.convertRecord(record, transcript, pendingPlan, activeModel);\n\n // Process Codex token_count events\n if (recordType === \"event_msg\") {\n const payload = extractPayload(record);\n if (String(payload[\"type\"] ?? \"\") === \"token_count\") {\n const { totalUsage, lastUsage } = extractTokenUsage(payload);\n const cumulativeTotal = Number(totalUsage?.[\"total_tokens\"] ?? 0);\n\n if (cumulativeTotal > 0 && cumulativeTotal === prevCumulativeTotal) {\n // duplicate event\n } else {\n prevCumulativeTotal = cumulativeTotal;\n\n let inputTokens = 0;\n let outputTokens = 0;\n let reasoningTokens = 0;\n let cacheReadTokens = 0;\n\n if (lastUsage) {\n inputTokens = Number(lastUsage[\"input_tokens\"] ?? 0);\n outputTokens = Number(lastUsage[\"output_tokens\"] ?? 0);\n reasoningTokens = Number(lastUsage[\"reasoning_output_tokens\"] ?? 0);\n cacheReadTokens = extractCachedInputTokens(lastUsage);\n } else if (cumulativeTotal > 0 && totalUsage) {\n inputTokens = Number(totalUsage[\"input_tokens\"] ?? 0) - prevInput;\n outputTokens = Number(totalUsage[\"output_tokens\"] ?? 0) - prevOutput;\n reasoningTokens =\n Number(totalUsage[\"reasoning_output_tokens\"] ?? 0) - prevReasoning;\n cacheReadTokens = extractCachedInputTokens(totalUsage) - prevCachedInput;\n\n prevInput = Number(totalUsage[\"input_tokens\"] ?? 0);\n prevOutput = Number(totalUsage[\"output_tokens\"] ?? 0);\n prevReasoning = Number(totalUsage[\"reasoning_output_tokens\"] ?? 0);\n prevCachedInput = extractCachedInputTokens(totalUsage);\n }\n\n const totalInput = Math.max(0, inputTokens);\n const totalCacheRead = Math.max(0, cacheReadTokens);\n if (totalInput || outputTokens || reasoningTokens) {\n totalInputTokens += totalInput;\n totalOutputTokens += outputTokens + reasoningTokens;\n totalCacheReadTokens += totalCacheRead;\n\n const tokens = {\n input: totalInput,\n output: outputTokens,\n reasoning: reasoningTokens || undefined,\n cache_read: totalCacheRead || undefined,\n };\n const cost = estimateTokenCost(activeModel, tokens);\n transcript.attachUsageToLatestAssistant(tokens, {\n model: activeModel,\n cost: cost ?? undefined,\n costSource: cost === null ? undefined : \"estimated\",\n });\n totalCost += cost ?? 0;\n }\n }\n }\n }\n } catch {\n // skip malformed records\n }\n }\n\n if (pendingPlan) transcript.appendToCurrentAssistant(pendingPlan);\n const result = transcript.finish({\n message_count: 0,\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cache_read_tokens: totalCacheReadTokens || undefined,\n total_cost: totalCost,\n cost_source: totalCost > 0 ? \"estimated\" : undefined,\n });\n\n this.applyChildStats(result.stats, meta.id);\n\n const childMessages = this.collectChildMessages(meta.id);\n for (const message of childMessages) {\n const messageText = message.parts.find((part) => part.type === \"text\")?.text;\n const alreadyVisible = result.messages.some(\n (existing) =>\n (message.subagent_id !== undefined && existing.subagent_id === message.subagent_id) ||\n (existing.subagent_id === undefined &&\n message.nickname !== undefined &&\n messageText !== undefined &&\n existing.nickname === message.nickname &&\n existing.parts.some((part) => part.type === \"text\" && part.text === messageText)),\n );\n if (!alreadyVisible) result.messages.push(message);\n }\n result.stats.message_count = result.messages.length;\n\n return {\n reference: { agentName: this.name, sessionId: meta.id },\n id: meta.id,\n title: meta.title,\n slug: `codex/${meta.id}`,\n directory: meta.directory,\n parent_reference:\n meta.parentThreadId == null\n ? undefined\n : { agentName: this.name, sessionId: meta.parentThreadId },\n time_created: meta.createdAt,\n time_updated: meta.updatedAt,\n stats: result.stats,\n messages: result.messages,\n };\n }\n\n /**\n * Builds the complete parent→children map in one prefix sweep. A cache miss\n * afterwards means \"no children\", so per-session directory rescans (the old\n * O(N²) finalization hotspot) never happen.\n */\n private ensureSubagentIndex(): SubagentIndex {\n if (this.subagentIndex) return this.subagentIndex;\n this.basePath ??= this.findBasePath();\n const index: SubagentIndex = { childFilesByParent: new Map(), subagentFiles: new Set() };\n for (const file of this.listRolloutFilePaths()) {\n const threadMeta = this.readThreadMeta(file);\n if (threadMeta?.threadSource !== \"subagent\") continue;\n index.subagentFiles.add(file);\n if (!threadMeta.parentThreadId) continue;\n const files = index.childFilesByParent.get(threadMeta.parentThreadId);\n if (files) files.push(file);\n else index.childFilesByParent.set(threadMeta.parentThreadId, [file]);\n }\n this.subagentIndex = index;\n return index;\n }\n\n private applyChildStats(target: SessionHead[\"stats\"], sessionId: string): void {\n for (const stats of this.collectChildStats(sessionId)) {\n target.total_input_tokens += stats.total_input_tokens ?? 0;\n target.total_output_tokens += stats.total_output_tokens ?? 0;\n target.total_cost += stats.total_cost ?? 0;\n if (stats.total_cache_read_tokens) {\n target.total_cache_read_tokens =\n (target.total_cache_read_tokens ?? 0) + stats.total_cache_read_tokens;\n }\n }\n }\n\n private collectChildStats(parentSessionId: string): SessionHead[\"stats\"][] {\n const files = this.collectChildFiles(parentSessionId);\n if (files.length === 0) return [];\n const cached = this.subagentStatsByParent.get(parentSessionId);\n if (cached) return cached;\n\n const stats = files.map((file) => this.parseTokenStats(file));\n this.subagentStatsByParent.set(parentSessionId, stats);\n return stats;\n }\n\n private collectChildFiles(parentSessionId: string): string[] {\n return this.ensureSubagentIndex().childFilesByParent.get(parentSessionId) ?? [];\n }\n\n private collectChildMessages(parentSessionId: string): Message[] {\n return this.collectChildFiles(parentSessionId)\n .flatMap((file) => {\n const message = this.parseChildFinalMessage(file);\n return message ? [message] : [];\n })\n .sort((left, right) => left.time_created - right.time_created);\n }\n\n private parseChildFinalMessage(filePath: string): Message | null {\n const sessionId = extractSessionId(filePath);\n const threadMeta = this.readThreadMeta(filePath);\n type ChildOutput = { id: string; text: string; timestampMs: number; isFinal: boolean };\n let latestOutput: ChildOutput | null = null;\n let finalOutput: ChildOutput | null = null;\n\n for (const record of readJsonlFile(filePath)) {\n try {\n const recordType = String(record[\"type\"] ?? \"\");\n if (recordType !== \"response_item\") continue;\n const payload = extractPayload(record);\n if (String(payload[\"type\"] ?? \"\") !== \"message\") continue;\n if (String(payload[\"role\"] ?? \"\") !== \"assistant\") continue;\n\n const text = cleanInternalText(extractAssistantOutputText(payload));\n if (!text) continue;\n\n const candidate: ChildOutput = {\n id: asString(payload[\"id\"]) ?? `codex-subagent-${sessionId}`,\n text,\n timestampMs:\n parseTimestampMs(record) || parseTimestampMs(payload) || statSync(filePath).mtimeMs,\n isFinal:\n String(record[\"phase\"] ?? \"\") === \"final_answer\" ||\n String(payload[\"phase\"] ?? \"\") === \"final_answer\",\n };\n latestOutput = candidate;\n if (candidate.isFinal) finalOutput = candidate;\n } catch {\n // skip malformed records\n }\n }\n\n const selected = finalOutput ?? latestOutput;\n if (!selected) return null;\n\n return {\n id: selected.id,\n role: \"assistant\",\n agent: \"codex\",\n time_created: selected.timestampMs,\n mode: null,\n model: null,\n provider: null,\n cost: 0,\n subagent_id: sessionId,\n nickname: threadMeta?.agentNickname ?? undefined,\n parts: [{ type: \"text\", text: selected.text, time_created: selected.timestampMs }],\n };\n }\n\n // ---- File listing ----\n\n private listRolloutFiles(options?: AgentScanOptions): SessionSourceFile[] {\n if (!this.basePath) return [];\n return this.walkFiles(\n this.basePath,\n (entry) => entry.name.endsWith(\".jsonl\") && entry.name.startsWith(\"rollout-\"),\n { scanWindow: options },\n );\n }\n\n /** Path-only listing for the subagent index: no per-file stat needed. */\n private listRolloutFilePaths(): string[] {\n if (!this.basePath) return [];\n const paths: string[] = [];\n const walk = (directory: string): void => {\n let entries: Dirent[];\n try {\n entries = readdirSync(directory, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const filePath = join(directory, entry.name);\n if (entry.isDirectory()) walk(filePath);\n else if (entry.name.startsWith(\"rollout-\") && entry.name.endsWith(\".jsonl\")) {\n paths.push(filePath);\n }\n }\n };\n walk(this.basePath);\n return paths;\n }\n\n private listScanSources(options?: AgentScanOptions): SessionSourceFile[] {\n const windowed = this.listRolloutFiles(options).sort(compareSourceActivityDesc);\n if (options?.from == null && options?.to == null) return windowed;\n\n const { childFilesByParent, subagentFiles } = this.ensureSubagentIndex();\n const rootFiles = windowed.filter((source) => !subagentFiles.has(source.file));\n const rootIds = new Set(rootFiles.map(({ file }) => extractSessionId(file)));\n if (rootIds.size === 0) return rootFiles;\n\n const selected = new Map(rootFiles.map((source) => [source.file, source]));\n const pending = [...rootIds];\n const seenParents = new Set<string>();\n while (pending.length > 0) {\n const parentId = pending.pop()!;\n if (seenParents.has(parentId)) continue;\n seenParents.add(parentId);\n for (const file of childFilesByParent.get(parentId) ?? []) {\n if (selected.has(file)) continue;\n try {\n selected.set(file, this.sessionSourceFile(file));\n } catch {\n continue;\n }\n pending.push(extractSessionId(file));\n }\n }\n return [...selected.values()].sort(compareSourceActivityDesc);\n }\n\n protected createFileSessionMeta(head: SessionHead, source: SessionSourceFile): SessionMeta {\n const indexPath = this.getSessionIndexPath();\n const indexMtime = this.sessionIndexMtime ?? null;\n return this.buildFileSessionMeta({\n head,\n source,\n fingerprint: this.sourceFingerprint(source.file, source.stat),\n extras: {\n indexPath: indexMtime === null ? null : indexPath,\n indexMtimeMs: indexMtime,\n headIndexVersion: HEAD_INDEX_VERSION,\n parserVersion: PARSER_VERSION,\n model: null,\n parentThreadId: head.parent_reference?.sessionId ?? null,\n },\n });\n }\n\n /** Fingerprint depends on an already-fetched stat to avoid re-statting the same file. */\n private sourceFingerprint(file: string, stat: { mtimeMs: number; size: number }): string {\n const sessionId = extractSessionId(file);\n return JSON.stringify([\n HEAD_INDEX_VERSION,\n PARSER_VERSION,\n stat.mtimeMs,\n stat.size,\n this.getTitleForSession(sessionId),\n ]);\n }\n\n private getSessionIndexPath(): string {\n this.sessionIndexPath ??= join(resolveCodexDataRoot(), \"session_index.jsonl\");\n return this.sessionIndexPath;\n }\n\n // ---- Session index ----\n\n private loadSessionIndex(): void {\n const indexPath = this.getSessionIndexPath();\n const mtime = this.readFileMtimeMs(indexPath);\n\n // Invalidate when the index file mtime advances so long-running processes\n // pick up title changes without relying on callers to evict manually.\n if (this.sessionIndexMtime !== undefined && this.sessionIndexMtime === mtime) return;\n\n if (mtime === null) {\n this.sessionIndexCache.clear();\n this.sessionIndexMtime = null;\n return;\n }\n\n try {\n const content = readFileSync(indexPath, \"utf-8\");\n const cache = new Map<string, string>();\n for (const record of parseJsonlLines(content)) {\n const sid = String(record[\"id\"] ?? \"\").trim();\n const threadName = String(record[\"thread_name\"] ?? \"\").trim();\n if (sid && threadName) {\n cache.set(sid, threadName);\n }\n }\n this.sessionIndexCache = cache;\n this.sessionIndexMtime = mtime;\n } catch {\n this.sessionIndexCache.clear();\n this.sessionIndexMtime = undefined;\n }\n }\n\n private getTitleForSession(sessionId: string): string | null {\n return this.sessionIndexCache.get(sessionId) ?? null;\n }\n\n // ---- Session head parsing ----\n\n private readFilePrefix(filePath: string, bytes = 64 * 1024): string {\n const fd = openSync(filePath, \"r\");\n try {\n const buffer = Buffer.alloc(bytes);\n const bytesRead = readSync(fd, buffer, 0, bytes, 0);\n return buffer.subarray(0, bytesRead).toString(\"utf-8\");\n } finally {\n closeSync(fd);\n }\n }\n\n protected parseFileSessionHead(filePath: string, options?: AgentScanOptions): SessionHead | null {\n this.loadSessionIndex();\n const head = this.parseSessionHead(filePath, options);\n if (head) this.applyChildStats(head.stats, head.id);\n return head;\n }\n\n private parseSessionHead(filePath: string, options?: AgentScanOptions): SessionHead | null {\n return getParsedSession(this.parseSessionHeadResult(filePath, options));\n }\n\n private parseSessionHeadResult(\n filePath: string,\n options?: AgentScanOptions,\n ): ParseSessionResult<SessionHead> {\n if (options?.fast) {\n return this.parseFastSessionHeadResult(filePath);\n }\n\n const sessionId = extractSessionId(filePath);\n\n let firstPayload: Record<string, unknown> = {};\n let parentThreadId: string | null = null;\n let createdAt = 0;\n let lineCount = 0;\n let messageTitle: string | null = null;\n\n // Single streaming pass: read the first record, extract the title\n // candidate, count messages, extract models, and pre-accumulate tokens.\n let updatedAt = 0;\n let messageCount = 0;\n let model: string | null = null;\n let activeModel: string | null = null;\n const modelUsageMap: Record<string, number> = {};\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCacheReadTokens = 0;\n let totalCost = 0;\n\n let scanPrevCumulativeTotal = 0;\n let scanPrevInput = 0;\n let scanPrevOutput = 0;\n let scanPrevReasoning = 0;\n let scanPrevCachedInput = 0;\n\n const COUNTED_TYPES = new Set([\"message\", \"function_call\", \"function_call_output\"]);\n\n let hasNonInternalRecord = false;\n\n for (const line of readJsonlFileLines(filePath)) {\n lineCount += 1;\n if (lineCount === 1) {\n let firstRecord: Record<string, unknown>;\n try {\n firstRecord = JSON.parse(line);\n } catch {\n return skippedSession(\"malformed first record\");\n }\n firstPayload = extractPayload(firstRecord);\n const threadMeta = extractThreadMeta(firstRecord);\n parentThreadId = threadMeta?.threadSource === \"subagent\" ? threadMeta.parentThreadId : null;\n createdAt =\n parseTimestampMs(firstRecord) ||\n parseTimestampMs(firstPayload) ||\n statSync(filePath).mtimeMs;\n updatedAt = createdAt;\n }\n\n try {\n const data = JSON.parse(line);\n const recordType = String(data[\"type\"] ?? \"\");\n const payload = extractPayload(data);\n const payloadType = String(payload[\"type\"] ?? \"\");\n if (isInternalEventType(recordType) || isInternalEventType(payloadType)) continue;\n hasNonInternalRecord = true;\n const recordTs = parseTimestampMs(data) || parseTimestampMs(payload);\n if (recordTs > updatedAt) updatedAt = recordTs;\n\n // Title fallback mirrors the removed extractTitleFromLines(): first\n // visible user message within the first 20 lines.\n if (messageTitle === null && lineCount <= 20) {\n const candidate = this.extractCodexRecordTitle(data);\n if (candidate) messageTitle = candidate;\n }\n\n if (recordType === \"session_meta\" || recordType === \"turn_context\") {\n const nextModel = extractModelName(payload[\"model\"]);\n if (nextModel) {\n activeModel = nextModel;\n model ??= nextModel;\n }\n continue;\n }\n\n if (recordType === \"response_item\") {\n const p = payload;\n const pType = String(p[\"type\"] ?? \"\");\n if (COUNTED_TYPES.has(pType)) {\n messageCount++;\n }\n // Extract model from response_item\n const info = narrowRecordField(p[\"info\"], \"response_item.info\");\n const m = info?.[\"model\"] ?? p[\"model\"];\n if (typeof m === \"string\" && m.trim()) {\n activeModel = m.trim();\n model ??= activeModel;\n }\n }\n\n if (recordType === \"event_msg\") {\n if (String(payload[\"type\"] ?? \"\") === \"token_count\") {\n const { totalUsage, lastUsage } = extractTokenUsage(payload);\n const cumulativeTotal = Number(totalUsage?.[\"total_tokens\"] ?? 0);\n\n if (cumulativeTotal > 0 && cumulativeTotal !== scanPrevCumulativeTotal) {\n scanPrevCumulativeTotal = cumulativeTotal;\n\n let inputTokens = 0;\n let outputTokens = 0;\n let reasoningTokens = 0;\n let cacheReadTokens = 0;\n\n if (lastUsage) {\n inputTokens = Number(lastUsage[\"input_tokens\"] ?? 0);\n outputTokens = Number(lastUsage[\"output_tokens\"] ?? 0);\n reasoningTokens = Number(lastUsage[\"reasoning_output_tokens\"] ?? 0);\n cacheReadTokens = extractCachedInputTokens(lastUsage);\n } else if (cumulativeTotal > 0 && totalUsage) {\n inputTokens = Number(totalUsage[\"input_tokens\"] ?? 0) - scanPrevInput;\n outputTokens = Number(totalUsage[\"output_tokens\"] ?? 0) - scanPrevOutput;\n reasoningTokens =\n Number(totalUsage[\"reasoning_output_tokens\"] ?? 0) - scanPrevReasoning;\n cacheReadTokens = extractCachedInputTokens(totalUsage) - scanPrevCachedInput;\n\n scanPrevInput = Number(totalUsage[\"input_tokens\"] ?? 0);\n scanPrevOutput = Number(totalUsage[\"output_tokens\"] ?? 0);\n scanPrevReasoning = Number(totalUsage[\"reasoning_output_tokens\"] ?? 0);\n scanPrevCachedInput = extractCachedInputTokens(totalUsage);\n }\n\n const totalInput = Math.max(0, inputTokens);\n const totalCacheRead = Math.max(0, cacheReadTokens);\n totalInputTokens += totalInput;\n totalOutputTokens += outputTokens + reasoningTokens;\n totalCacheReadTokens += totalCacheRead;\n const totalForModel = totalInput + outputTokens + reasoningTokens;\n if (activeModel && totalForModel > 0) {\n modelUsageMap[activeModel] = (modelUsageMap[activeModel] ?? 0) + totalForModel;\n }\n const cost = estimateTokenCost(activeModel, {\n input: totalInput,\n output: outputTokens,\n reasoning: reasoningTokens || undefined,\n cache_read: totalCacheRead || undefined,\n });\n if (cost !== null) totalCost += cost;\n }\n }\n }\n } catch {\n // skip\n }\n }\n\n if (lineCount === 0) return skippedSession(\"empty file\");\n if (!hasNonInternalRecord) return filteredSession(\"internal events only\");\n\n const indexTitle = this.getTitleForSession(sessionId);\n const directory = firstPayload[\"cwd\"] ? String(firstPayload[\"cwd\"]) : \"\";\n const title = resolveSessionTitle(indexTitle, messageTitle, basenameTitle(directory || null));\n\n return parsedSession({\n id: sessionId,\n slug: `codex/${sessionId}`,\n title,\n directory,\n parent_reference:\n parentThreadId == null ? undefined : { agentName: this.name, sessionId: parentThreadId },\n time_created: createdAt,\n time_updated: updatedAt,\n stats: {\n message_count: messageCount,\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cache_read_tokens: totalCacheReadTokens || undefined,\n total_cost: totalCost,\n cost_source: totalCost > 0 ? \"estimated\" : undefined,\n },\n model_usage: Object.keys(modelUsageMap).length > 0 ? modelUsageMap : undefined,\n });\n }\n\n private parseFastSessionHeadResult(filePath: string): ParseSessionResult<SessionHead> {\n const prefix = this.readFilePrefix(filePath);\n const lines = prefix.split(\"\\n\").filter((l) => l.trim());\n if (lines.length === 0) return skippedSession(\"empty file\");\n\n const sessionId = extractSessionId(filePath);\n\n let firstRecord: Record<string, unknown>;\n try {\n firstRecord = JSON.parse(lines[0]!);\n } catch {\n return skippedSession(\"malformed first record\");\n }\n\n const threadMeta = extractThreadMeta(firstRecord);\n const parentThreadId =\n threadMeta?.threadSource === \"subagent\" ? threadMeta.parentThreadId : null;\n\n const payload = extractPayload(firstRecord);\n const stat = statSync(filePath);\n const createdAt = parseTimestampMs(firstRecord) || parseTimestampMs(payload) || stat.mtimeMs;\n const indexTitle = this.getTitleForSession(sessionId);\n const messageTitle = this.extractTitleFromLines(lines);\n const directory = payload[\"cwd\"] ? String(payload[\"cwd\"]) : \"\";\n const directoryTitle = basenameTitle(directory || null);\n const title = resolveSessionTitle(indexTitle, messageTitle, directoryTitle);\n\n return parsedSession({\n id: sessionId,\n slug: `codex/${sessionId}`,\n title,\n directory,\n parent_reference:\n parentThreadId == null ? undefined : { agentName: this.name, sessionId: parentThreadId },\n time_created: createdAt,\n time_updated: stat.mtimeMs,\n stats: {\n message_count: 0,\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_cost: 0,\n },\n });\n }\n\n /** Fast path only: parses each of the first 20 lines to find a title (no full stats pass available). */\n private extractTitleFromLines(lines: string[]): string | null {\n for (const line of lines.slice(0, 20)) {\n try {\n const title = this.extractCodexRecordTitle(JSON.parse(line));\n if (title) return title;\n } catch {\n // skip\n }\n }\n return null;\n }\n\n /**\n * Title candidate from a single already-parsed record, if it's a visible\n * user message. Shared by the main streaming pass (which parses every line\n * once) and the fast path's extractTitleFromLines().\n */\n private extractCodexRecordTitle(data: Record<string, unknown>): string | null {\n const recordType = String(data[\"type\"] ?? \"\");\n if (recordType !== \"response_item\" || isInternalEventType(recordType)) return null;\n\n const payload = extractPayload(data);\n const pType = String(payload[\"type\"] ?? \"\");\n if (pType !== \"message\" || isInternalEventType(pType)) return null;\n if (String(payload[\"role\"] ?? \"\") !== \"user\") return null;\n\n const content = payload[\"content\"];\n let text: string | null = null;\n if (Array.isArray(content)) {\n text = content\n .map((item) => {\n const record = asRecord(item);\n return record ? String(record[\"text\"] ?? \"\") : \"\";\n })\n .join(\" \");\n } else if (typeof content === \"string\") {\n text = content;\n }\n if (!text || isDeveloperLikeUserMessage(text)) return null;\n return normalizeTitleText(text) || null;\n }\n\n // ---- Record conversion ----\n\n private convertRecord(\n data: Record<string, unknown>,\n transcript: TranscriptBuilder,\n pendingPlan: MessagePart | null,\n activeModel: string | null,\n ): MessagePart | null {\n const recordType = String(data[\"type\"] ?? \"\");\n if (isInternalEventType(recordType)) return pendingPlan;\n\n if (recordType === \"session_meta\" || recordType === \"event_msg\") {\n return pendingPlan;\n }\n\n if (recordType !== \"response_item\") return pendingPlan;\n\n const payload = extractPayload(data);\n const payloadType = String(payload[\"type\"] ?? \"\");\n if (isInternalEventType(payloadType)) return pendingPlan;\n const timestampMs = parseTimestampMs(data) || parseTimestampMs(payload);\n\n switch (payloadType) {\n case \"message\": {\n const role = String(payload[\"role\"] ?? \"\");\n if (role === \"assistant\") {\n return this.convertAssistantMessage(\n payload,\n transcript,\n timestampMs,\n pendingPlan,\n activeModel,\n );\n }\n if (role === \"user\") {\n return this.convertUserMessage(payload, transcript, timestampMs, pendingPlan);\n }\n break;\n }\n\n case \"reasoning\":\n this.convertReasoning(payload, transcript, timestampMs, activeModel);\n return null;\n\n case \"function_call\":\n this.convertFunctionCall(payload, transcript, timestampMs, activeModel);\n return null;\n\n case \"function_call_output\":\n this.convertToolCallOutput(payload, transcript, timestampMs);\n return pendingPlan;\n\n case \"custom_tool_call\":\n this.convertCustomToolCall(payload, transcript, timestampMs, activeModel);\n return null;\n\n case \"custom_tool_call_output\":\n this.convertToolCallOutput(payload, transcript, timestampMs);\n return pendingPlan;\n }\n\n return pendingPlan;\n }\n\n // ---- Assistant message ----\n\n private convertAssistantMessage(\n payload: Record<string, unknown>,\n transcript: TranscriptBuilder,\n timestampMs: number,\n pendingPlan: MessagePart | null,\n activeModel: string | null,\n ): MessagePart | null {\n const fullText = extractAssistantOutputText(payload);\n if (!fullText) return pendingPlan;\n\n const planMatch = fullText.match(PROPOSED_PLAN_PATTERN);\n if (planMatch) {\n const planText = planMatch[1]!.trim();\n const planPart: MessagePart = {\n type: \"plan\",\n text: planText,\n approval_status: \"success\",\n time_created: timestampMs,\n };\n pendingPlan = planPart;\n }\n\n const displayText = cleanInternalText(fullText.replace(PROPOSED_PLAN_PATTERN, \"\"));\n if (!displayText) return pendingPlan;\n\n const textPart: MessagePart = { type: \"text\", text: displayText, time_created: timestampMs };\n transcript.appendAssistantPart(textPart, {\n id: \"\",\n timestampMs,\n agent: \"codex\",\n model: activeModel,\n });\n return pendingPlan;\n }\n\n // ---- User message ----\n\n private convertUserMessage(\n payload: Record<string, unknown>,\n transcript: TranscriptBuilder,\n timestampMs: number,\n pendingPlan: MessagePart | null,\n ): MessagePart | null {\n const content = payload[\"content\"];\n const text = Array.isArray(content)\n ? content\n .map((c) => {\n if (Array.isArray(c)) return \"\";\n const record = asRecord(c);\n return record ? String(record[\"text\"] ?? \"\") : String(c ?? \"\");\n })\n .join(\" \")\n : String(content ?? \"\");\n\n const visibleText = cleanInternalText(text);\n if (!visibleText) return pendingPlan;\n\n if (isDeveloperLikeUserMessage(visibleText)) return pendingPlan;\n\n if (visibleText.trimStart().startsWith(PLAN_APPROVAL_PREFIX)) {\n if (pendingPlan) transcript.appendToCurrentAssistant(pendingPlan);\n transcript.appendMessage({\n id: \"\",\n role: \"user\",\n timestampMs,\n parts: [{ type: \"text\", text: visibleText, time_created: timestampMs }],\n });\n return null;\n }\n\n const subagentMatch = visibleText.match(SUBAGENT_NOTIFICATION_PATTERN);\n if (subagentMatch) {\n // Malformed or non-object notification payloads fall through and are\n // treated as normal user messages below.\n let notifPayload: Record<string, unknown> | undefined;\n try {\n notifPayload = asRecord(JSON.parse(subagentMatch[1]!));\n } catch {\n notifPayload = undefined;\n }\n\n if (notifPayload) {\n const agentId = String(notifPayload[\"agent_id\"] ?? \"\");\n const nickname = String(notifPayload[\"nickname\"] ?? \"\");\n const completedText = String(notifPayload[\"completed\"] ?? \"\");\n\n const textPart: MessagePart = {\n type: \"text\",\n text: completedText || `Subagent ${nickname} completed`,\n time_created: timestampMs,\n };\n\n transcript.appendMessage({\n id: \"\",\n role: \"assistant\",\n timestampMs,\n parts: [textPart],\n agent: \"codex\",\n subagentId: agentId || undefined,\n nickname: nickname || undefined,\n });\n transcript.beginTurn();\n return pendingPlan;\n }\n }\n\n transcript.appendMessage({\n id: \"\",\n role: \"user\",\n timestampMs,\n parts: [{ type: \"text\", text: visibleText, time_created: timestampMs }],\n });\n return pendingPlan;\n }\n\n // ---- Reasoning ----\n\n private convertReasoning(\n payload: Record<string, unknown>,\n transcript: TranscriptBuilder,\n timestampMs: number,\n activeModel: string | null,\n ): void {\n const summary = payload[\"summary\"];\n if (!Array.isArray(summary)) return;\n\n const texts: string[] = [];\n for (const item of summary) {\n const ci = asRecord(item);\n if (!ci) continue;\n if (String(ci[\"type\"] ?? \"\") === \"summary_text\") {\n const text = String(ci[\"text\"] ?? \"\");\n if (text.trim()) texts.push(text);\n }\n }\n\n if (texts.length === 0) return;\n\n const reasoningText = texts.join(\"\\n\");\n const part: MessagePart = { type: \"reasoning\", text: reasoningText, time_created: timestampMs };\n transcript.appendAssistantPart(\n part,\n {\n id: \"\",\n timestampMs,\n agent: \"codex\",\n model: activeModel,\n },\n { resetLatestText: true },\n );\n }\n\n // ---- Function call ----\n\n private convertFunctionCall(\n payload: Record<string, unknown>,\n transcript: TranscriptBuilder,\n timestampMs: number,\n activeModel: string | null,\n ): void {\n const callId = String(payload[\"call_id\"] ?? \"\").trim();\n const name = String(payload[\"name\"] ?? \"\").trim();\n if (!name) return;\n\n const toolIdentity = resolveToolIdentity(name, payload[\"namespace\"]);\n const arguments_ = normalizeToolArguments(payload[\"arguments\"]);\n\n const toolPart: MessagePart = {\n type: \"tool\",\n tool: toolIdentity.tool,\n callID: callId,\n title: `Tool: ${toolIdentity.tool}`,\n state: {\n status: \"running\",\n input: arguments_,\n output: null,\n metadata: toolIdentity.metadata,\n },\n time_created: timestampMs,\n };\n\n transcript.appendToolCall(\n toolPart,\n { id: \"\", timestampMs, agent: \"codex\", model: activeModel },\n { markModeAsTool: true },\n );\n }\n\n // ---- Function call output ----\n\n private convertToolCallOutput(\n payload: Record<string, unknown>,\n transcript: TranscriptBuilder,\n timestampMs: number,\n ): void {\n const callId = String(payload[\"call_id\"] ?? \"\").trim();\n if (!callId) return;\n\n const outputText = cleanInternalText(\n stripExecOutputEnvelope(flattenOutputText(payload[\"output\"])),\n );\n const outputParts: MessagePart[] = outputText\n ? [{ type: \"text\", text: outputText, time_created: timestampMs }]\n : [];\n\n if (outputParts.length > 0) {\n transcript.resolveToolCall(callId, { output: outputParts, status: \"completed\" });\n }\n }\n\n // ---- Custom tool call ----\n\n private convertCustomToolCall(\n payload: Record<string, unknown>,\n transcript: TranscriptBuilder,\n timestampMs: number,\n activeModel: string | null,\n ): void {\n const callId = String(payload[\"call_id\"] ?? \"\").trim();\n const name = String(payload[\"name\"] ?? \"\").trim();\n if (!name) return;\n\n // Code-mode exec: the JS program wraps native tool calls. Decode each\n // inner call back to its classic tool part so existing displays apply.\n // Programs with no recognizable call fall through to the raw exec part.\n if (name === \"exec\") {\n const decoded = decodeExecCalls(payload[\"input\"]);\n if (decoded.length > 0) {\n this.appendDecodedExecCalls(decoded, callId, transcript, timestampMs, activeModel);\n return;\n }\n }\n\n const toolIdentity = resolveToolIdentity(name, payload[\"namespace\"]);\n const rawInput = payload[\"input\"];\n const normalizedInput = normalizeCustomToolArguments(name, rawInput);\n\n const toolPart: MessagePart = {\n type: \"tool\",\n tool: toolIdentity.tool,\n callID: callId,\n title: `Tool: ${toolIdentity.tool}`,\n state: {\n status: \"running\",\n input: normalizedInput,\n output: null,\n metadata: toolIdentity.metadata,\n },\n time_created: timestampMs,\n };\n\n transcript.appendToolCall(\n toolPart,\n { id: \"\", timestampMs, agent: \"codex\", model: activeModel },\n { markModeAsTool: true },\n );\n }\n\n // ---- Decoded code-mode exec calls ----\n\n private appendDecodedExecCalls(\n calls: ExecInnerCall[],\n callId: string,\n transcript: TranscriptBuilder,\n timestampMs: number,\n activeModel: string | null,\n ): void {\n // Only one output record follows, keyed by the exec call id; route it to\n // the output-bearing part and give the rest unique ids so they still\n // register and render, just without a resolved output.\n const outputIndex = pickExecOutputTarget(calls);\n calls.forEach((call, index) => {\n const partCallId = index === outputIndex ? callId : `${callId}#${index}`;\n this.appendDecodedExecCall(call, partCallId, transcript, timestampMs, activeModel);\n });\n }\n\n private appendDecodedExecCall(\n call: ExecInnerCall,\n callId: string,\n transcript: TranscriptBuilder,\n timestampMs: number,\n activeModel: string | null,\n ): void {\n const { name, namespace } = splitExecToolName(call.name);\n const toolIdentity = resolveToolIdentity(name, namespace);\n const arguments_ =\n name === \"apply_patch\" ? parseApplyPatchInput(getExecPatchText(call.args)) : call.args;\n\n const toolPart: MessagePart = {\n type: \"tool\",\n tool: toolIdentity.tool,\n callID: callId,\n title: `Tool: ${toolIdentity.tool}`,\n state: {\n status: \"running\",\n input: arguments_,\n output: null,\n metadata: toolIdentity.metadata,\n },\n time_created: timestampMs,\n };\n\n transcript.appendToolCall(\n toolPart,\n { id: \"\", timestampMs, agent: \"codex\", model: activeModel },\n { markModeAsTool: true },\n );\n }\n}\n","/**\n * Codex \"code mode\" exec decoding.\n *\n * Since Codex 0.144.x the agent no longer calls tools directly. Every tool\n * invocation is now a `custom_tool_call` named \"exec\" whose `input` is a small\n * JS program that calls `tools.<name>({...})` (e.g. `tools.exec_command`,\n * `tools.apply_patch`). This module extracts those inner invocations so the\n * adapter can present each one as the native tool call it used to be.\n *\n * The inner argument objects are JS object literals, not JSON — unquoted keys,\n * single/double/template strings, and shorthand `{patch}` that references a\n * `const patch = \"...\"` declared earlier. A small tolerant reader handles that\n * subset and resolves string variables; anything it cannot parse degrades to an\n * empty result so the caller can fall back to the raw exec display.\n */\n\nexport interface ExecInnerCall {\n name: string;\n args: unknown;\n}\n\nconst PARSE_FAIL = Symbol(\"parse-fail\");\n\nconst EXEC_OUTPUT_ENVELOPE_RE = /^Script completed\\nWall time [^\\n]*\\nOutput:\\n?/;\n\n/** Strip the `Script completed / Wall time / Output:` wrapper code-mode adds. */\nexport function stripExecOutputEnvelope(text: string): string {\n return text.replace(EXEC_OUTPUT_ENVELOPE_RE, \"\");\n}\n\n/**\n * Split an inner tool name into `resolveToolIdentity(name, namespace)` inputs.\n * `mcp__node_repl__js` → { name: \"js\", namespace: \"mcp__node_repl__\" }.\n */\nexport function splitExecToolName(name: string): { name: string; namespace?: string } {\n if (name.startsWith(\"mcp__\")) {\n const separator = name.lastIndexOf(\"__\");\n if (separator > 0 && separator + 2 < name.length) {\n return { name: name.slice(separator + 2), namespace: name.slice(0, separator + 2) };\n }\n }\n return { name };\n}\n\n/**\n * Pick which decoded call receives the exec program's combined output. Patch\n * and plan calls do not emit stdout, so prefer the last output-bearing call;\n * otherwise fall back to the last call.\n */\nexport function pickExecOutputTarget(calls: ExecInnerCall[]): number {\n for (let index = calls.length - 1; index >= 0; index -= 1) {\n const { name } = splitExecToolName(calls[index]!.name);\n if (name !== \"apply_patch\" && name !== \"update_plan\") return index;\n }\n return calls.length - 1;\n}\n\n/** Extract the patch text from an `apply_patch` argument (`{patch}` or a string). */\nexport function getExecPatchText(args: unknown): string {\n if (typeof args === \"string\") return args;\n if (args && typeof args === \"object\") {\n const patch = (args as Record<string, unknown>)[\"patch\"];\n if (typeof patch === \"string\") return patch;\n }\n return \"\";\n}\n\n/** Decode the `tools.<name>({...})` invocations inside a code-mode exec program. */\nexport function decodeExecCalls(input: unknown): ExecInnerCall[] {\n if (typeof input !== \"string\" || !input.includes(\"tools.\")) return [];\n\n const scope = collectStringVars(input);\n const calls: ExecInnerCall[] = [];\n const callRe = /tools\\.([A-Za-z_$][\\w$]*)\\s*\\(/g;\n let match: RegExpExecArray | null;\n while ((match = callRe.exec(input)) !== null) {\n const reader = new JsValueReader(input, callRe.lastIndex, scope);\n const args = reader.parseValue();\n if (args !== PARSE_FAIL) {\n calls.push({ name: match[1]!, args });\n callRe.lastIndex = reader.pos;\n }\n }\n return calls;\n}\n\n/** Pre-scan `const/let/var NAME = \"...\"` so shorthand args can resolve them. */\nfunction collectStringVars(input: string): Map<string, unknown> {\n const scope = new Map<string, unknown>();\n const assignRe = /(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)\\s*=\\s*/g;\n let match: RegExpExecArray | null;\n while ((match = assignRe.exec(input)) !== null) {\n const reader = new JsValueReader(input, assignRe.lastIndex, scope);\n const value = reader.parseValue();\n if (value !== PARSE_FAIL) {\n if (typeof value === \"string\") scope.set(match[1]!, value);\n assignRe.lastIndex = reader.pos;\n }\n }\n return scope;\n}\n\nconst IDENT_START_RE = /[A-Za-z_$]/;\nconst IDENT_PART_RE = /[\\w$]/;\n\n/** Recursive-descent reader for the JS-literal subset used in exec args. */\nclass JsValueReader {\n pos: number;\n private readonly src: string;\n private readonly scope: Map<string, unknown>;\n\n constructor(src: string, start: number, scope: Map<string, unknown>) {\n this.src = src;\n this.pos = start;\n this.scope = scope;\n }\n\n parseValue(): unknown | typeof PARSE_FAIL {\n this.skipTrivia();\n const char = this.src[this.pos];\n if (char === undefined) return PARSE_FAIL;\n if (char === \"{\") return this.parseObject();\n if (char === \"[\") return this.parseArray();\n if (char === '\"' || char === \"'\" || char === \"`\") return this.parseString(char);\n if (char === \"-\" || char === \"+\" || (char >= \"0\" && char <= \"9\")) return this.parseNumber();\n if (IDENT_START_RE.test(char)) return this.parseIdentifierValue();\n return PARSE_FAIL;\n }\n\n private parseObject(): unknown | typeof PARSE_FAIL {\n this.pos++; // {\n const result: Record<string, unknown> = {};\n this.skipTrivia();\n if (this.src[this.pos] === \"}\") {\n this.pos++;\n return result;\n }\n while (this.pos < this.src.length) {\n this.skipTrivia();\n const key = this.parseKey();\n if (key === PARSE_FAIL) return PARSE_FAIL;\n this.skipTrivia();\n if (this.src[this.pos] === \":\") {\n this.pos++;\n const value = this.parseValue();\n if (value === PARSE_FAIL) return PARSE_FAIL;\n result[key] = value;\n } else {\n result[key] = this.resolveIdentifier(key);\n }\n this.skipTrivia();\n const next = this.src[this.pos];\n if (next === \",\") {\n this.pos++;\n this.skipTrivia();\n if (this.src[this.pos] === \"}\") {\n this.pos++;\n return result;\n }\n continue;\n }\n if (next === \"}\") {\n this.pos++;\n return result;\n }\n return PARSE_FAIL;\n }\n return PARSE_FAIL;\n }\n\n private parseArray(): unknown | typeof PARSE_FAIL {\n this.pos++; // [\n const result: unknown[] = [];\n this.skipTrivia();\n if (this.src[this.pos] === \"]\") {\n this.pos++;\n return result;\n }\n while (this.pos < this.src.length) {\n const value = this.parseValue();\n if (value === PARSE_FAIL) return PARSE_FAIL;\n result.push(value);\n this.skipTrivia();\n const next = this.src[this.pos];\n if (next === \",\") {\n this.pos++;\n this.skipTrivia();\n if (this.src[this.pos] === \"]\") {\n this.pos++;\n return result;\n }\n continue;\n }\n if (next === \"]\") {\n this.pos++;\n return result;\n }\n return PARSE_FAIL;\n }\n return PARSE_FAIL;\n }\n\n private parseKey(): string | typeof PARSE_FAIL {\n const char = this.src[this.pos];\n if (char === '\"' || char === \"'\" || char === \"`\") {\n const value = this.parseString(char);\n return typeof value === \"string\" ? value : PARSE_FAIL;\n }\n if (char !== undefined && IDENT_START_RE.test(char)) return this.readIdentifier();\n return PARSE_FAIL;\n }\n\n private parseString(quote: string): string {\n this.pos++; // opening quote\n let out = \"\";\n while (this.pos < this.src.length) {\n const char = this.src[this.pos++]!;\n if (char === \"\\\\\") {\n out += this.readEscape();\n continue;\n }\n if (char === quote) break;\n out += char;\n }\n return out;\n }\n\n private readEscape(): string {\n const char = this.src[this.pos++];\n switch (char) {\n case \"n\":\n return \"\\n\";\n case \"t\":\n return \"\\t\";\n case \"r\":\n return \"\\r\";\n case \"b\":\n return \"\\b\";\n case \"f\":\n return \"\\f\";\n case \"v\":\n return \"\\v\";\n case \"0\":\n return \"\\0\";\n case \"u\": {\n const hex = this.src.slice(this.pos, this.pos + 4);\n if (/^[0-9a-fA-F]{4}$/.test(hex)) {\n this.pos += 4;\n return String.fromCharCode(parseInt(hex, 16));\n }\n return \"u\";\n }\n case \"x\": {\n const hex = this.src.slice(this.pos, this.pos + 2);\n if (/^[0-9a-fA-F]{2}$/.test(hex)) {\n this.pos += 2;\n return String.fromCharCode(parseInt(hex, 16));\n }\n return \"x\";\n }\n default:\n return char ?? \"\";\n }\n }\n\n private parseNumber(): number | typeof PARSE_FAIL {\n const numberRe = /[-+]?(?:0[xX][0-9a-fA-F]+|(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][-+]?\\d+)?)/y;\n numberRe.lastIndex = this.pos;\n const match = numberRe.exec(this.src);\n if (!match) return PARSE_FAIL;\n this.pos += match[0].length;\n return Number(match[0]);\n }\n\n private parseIdentifierValue(): unknown {\n const name = this.readIdentifier();\n if (name === \"true\") return true;\n if (name === \"false\") return false;\n if (name === \"null\") return null;\n if (name === \"undefined\") return undefined;\n return this.resolveIdentifier(name);\n }\n\n private resolveIdentifier(name: string): unknown {\n return this.scope.has(name) ? this.scope.get(name) : undefined;\n }\n\n private readIdentifier(): string {\n const start = this.pos;\n while (this.pos < this.src.length && IDENT_PART_RE.test(this.src[this.pos]!)) this.pos++;\n return this.src.slice(start, this.pos);\n }\n\n private skipTrivia(): void {\n while (this.pos < this.src.length) {\n const char = this.src[this.pos]!;\n if (char === \" \" || char === \"\\t\" || char === \"\\n\" || char === \"\\r\") {\n this.pos++;\n continue;\n }\n if (char === \"/\" && this.src[this.pos + 1] === \"/\") {\n const newline = this.src.indexOf(\"\\n\", this.pos + 2);\n this.pos = newline === -1 ? this.src.length : newline + 1;\n continue;\n }\n if (char === \"/\" && this.src[this.pos + 1] === \"*\") {\n const close = this.src.indexOf(\"*/\", this.pos + 2);\n this.pos = close === -1 ? this.src.length : close + 2;\n continue;\n }\n break;\n }\n }\n}\n","import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { homedir, platform } from \"node:os\";\nimport { join, normalize } from \"node:path\";\nimport {\n DatabaseSessionSource,\n filteredSession,\n getParsedSession,\n matchesScanWindow,\n parsedSession,\n SessionScanError,\n} from \"./base.js\";\nimport type { AgentScanOptions } from \"./base.js\";\nimport type {\n SessionHead,\n SessionDetail,\n Message,\n MessagePart,\n ToolPartState,\n} from \"../types/index.js\";\nimport { normalizeMessageParts } from \"../contract/message-part.js\";\nimport { firstExisting, readEnvPath } from \"../discovery/paths.js\";\nimport {\n openDbReadOnly,\n isSqliteAvailable,\n type DatabaseRow,\n type SQLiteDatabase,\n} from \"../utils/sqlite.js\";\nimport { resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport { isInternalEventType } from \"../utils/parse-cleanup.js\";\nimport {\n cleanInternalText,\n cleanParsedMessages,\n firstUserMessageTitle,\n} from \"../utils/session-normalization.js\";\nimport { perf } from \"../utils/perf.js\";\nimport { estimateTokenCost } from \"../utils/cost.js\";\nimport {\n asArray,\n asNumber,\n asRecord,\n asString,\n narrowField,\n safeParseJsonRecord,\n} from \"../utils/narrow.js\";\n\nexport function resolveCursorDataRoot(): string | null {\n const override = readEnvPath(\"CURSOR_DATA_PATH\");\n if (override) return override;\n\n const currentPlatform = platform();\n if (currentPlatform === \"darwin\") {\n return firstExisting(join(homedir(), \"Library\", \"Application Support\", \"Cursor\", \"User\"));\n }\n if (currentPlatform === \"linux\") {\n const configRoot = readEnvPath(\"XDG_CONFIG_HOME\") ?? join(homedir(), \".config\");\n return firstExisting(join(configRoot, \"Cursor\", \"User\"));\n }\n if (currentPlatform === \"win32\") {\n const appData = readEnvPath(\"APPDATA\") ?? join(homedir(), \"AppData\", \"Roaming\");\n return firstExisting(join(appData, \"Cursor\", \"User\"));\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Cursor data model interfaces\n// ---------------------------------------------------------------------------\n\ninterface ComposerData {\n id?: string;\n composerId?: string;\n text?: string;\n name?: string;\n title?: string;\n createdAt?: number;\n updatedAt?: number;\n lastSendTime?: number;\n lastUpdatedAt?: number;\n model?: string;\n modelConfig?: { modelName?: string };\n inputTokenCount?: number;\n outputTokenCount?: number;\n subagentInfos?: SubagentInfo[];\n chatMessages?: ChatMessage[];\n usageData?: {\n contextTokensUsed?: number;\n contextTokenLimit?: number;\n contextUsagePercent?: number;\n };\n}\n\ninterface BubbleData {\n id?: string;\n composerId?: string;\n chatMessages?: ChatMessage[];\n type?: number; // 1 = user, 2 = assistant\n text?: string;\n requestId?: string;\n createdAt?: number;\n timestamp?: number;\n timingInfo?: {\n clientRpcSendTime?: number;\n clientSettleTime?: number;\n clientEndTime?: number;\n };\n tokenCount?: {\n inputTokens?: number;\n outputTokens?: number;\n };\n modelInfo?: {\n modelName?: string;\n };\n toolFormerData?: {\n name?: string;\n toolCallId?: string;\n status?: string;\n params?: unknown;\n result?: unknown;\n additionalData?: Record<string, unknown>;\n };\n [key: string]: unknown;\n}\n\ninterface SubagentInfo {\n id?: string;\n composerId?: string;\n title?: string;\n nickname?: string;\n}\n\ninterface ChatMessage {\n role: string;\n text?: string;\n createdAt?: number;\n timestamp?: number;\n actions?: ActionEntry[];\n isCompletion?: boolean;\n [key: string]: unknown;\n}\n\ninterface ActionEntry {\n type?: string;\n tool?: string;\n input?: Record<string, unknown>;\n output?: unknown;\n state?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Safe parsing of external rows — cursorDiskKV values and workspace.json are\n// untrusted (cross Cursor-version drift), so their fields are narrowed\n// individually instead of blindly cast. A field that's absent behaves like\n// today's optional-field fallback (?? 0 / skip); a field that's present but\n// wrong-typed additionally reports once via diagnostics.\n// ---------------------------------------------------------------------------\n\nfunction narrowString(field: string, value: unknown): string | undefined {\n return narrowField(\"cursor\", field, value, asString);\n}\n\nfunction narrowNumber(field: string, value: unknown): number | undefined {\n return narrowField(\"cursor\", field, value, asNumber);\n}\n\nfunction parseSubagentInfos(value: unknown): SubagentInfo[] | undefined {\n const arr = asArray(value);\n if (arr === undefined) return undefined;\n const infos: SubagentInfo[] = [];\n for (const item of arr) {\n const record = asRecord(item);\n if (!record) continue;\n infos.push({\n id: narrowString(\"subagentInfo.id\", record.id),\n composerId: narrowString(\"subagentInfo.composerId\", record.composerId),\n title: narrowString(\"subagentInfo.title\", record.title),\n nickname: narrowString(\"subagentInfo.nickname\", record.nickname),\n });\n }\n return infos;\n}\n\nfunction parseChatMessages(value: unknown): ChatMessage[] | undefined {\n const arr = asArray(value);\n if (arr === undefined) return undefined;\n const messages: ChatMessage[] = [];\n for (const item of arr) {\n const record = asRecord(item);\n if (!record) continue;\n const role = narrowString(\"chatMessage.role\", record.role);\n if (role === undefined) continue;\n messages.push({ ...record, role, text: narrowString(\"chatMessage.text\", record.text) });\n }\n return messages;\n}\n\n/** Parse a `composerData:*` row value into a field-validated ComposerData. */\nfunction parseComposerRow(value: string): ComposerData | null {\n const record = safeParseJsonRecord(value);\n if (!record) return null;\n\n const modelConfig = asRecord(record.modelConfig);\n\n return {\n id: narrowString(\"composer.id\", record.id),\n composerId: narrowString(\"composer.composerId\", record.composerId),\n text: narrowString(\"composer.text\", record.text),\n name: narrowString(\"composer.name\", record.name),\n title: narrowString(\"composer.title\", record.title),\n createdAt: narrowNumber(\"composer.createdAt\", record.createdAt),\n updatedAt: narrowNumber(\"composer.updatedAt\", record.updatedAt),\n lastSendTime: narrowNumber(\"composer.lastSendTime\", record.lastSendTime),\n lastUpdatedAt: narrowNumber(\"composer.lastUpdatedAt\", record.lastUpdatedAt),\n model: narrowString(\"composer.model\", record.model),\n modelConfig: modelConfig\n ? { modelName: narrowString(\"composer.modelConfig.modelName\", modelConfig.modelName) }\n : undefined,\n inputTokenCount: narrowNumber(\"composer.inputTokenCount\", record.inputTokenCount),\n outputTokenCount: narrowNumber(\"composer.outputTokenCount\", record.outputTokenCount),\n subagentInfos: parseSubagentInfos(record.subagentInfos),\n chatMessages: parseChatMessages(record.chatMessages),\n };\n}\n\ninterface BubbleRow extends DatabaseRow {\n row_id: number;\n key: string;\n value: string;\n}\n\ninterface BubbleEntry {\n rowId: number;\n key: string;\n bubble: BubbleData;\n}\n\n/**\n * One composer's bubbles, parsed once and offered in both orders the readers\n * need: request ids come from the key-ordered view, messages from insertion\n * order.\n */\ninterface ComposerBubbles {\n composerId: string;\n byKey: BubbleEntry[];\n byRowId: BubbleEntry[];\n}\n\n/** A composer waiting for its bubbles in the second phase of a scan. */\ninterface PendingComposer {\n composer: ComposerData;\n composerId: string;\n createdAt: number;\n updatedAt: number;\n hasSubagents: boolean;\n order: number;\n}\n\nfunction composerIdFromBubbleKey(key: string): string {\n const start = key.indexOf(\":\") + 1;\n const end = key.indexOf(\":\", start);\n return end === -1 ? key.slice(start) : key.slice(start, end);\n}\n\nfunction groupBubbleRows(rows: BubbleRow[]): ComposerBubbles {\n const byKey: BubbleEntry[] = [];\n for (const row of rows) {\n const bubble = parseBubbleRow(row.value);\n if (bubble) byKey.push({ rowId: row.row_id, key: row.key, bubble });\n }\n byKey.sort((left, right) => left.key.localeCompare(right.key));\n return {\n composerId: rows.length > 0 ? composerIdFromBubbleKey(rows[0]!.key) : \"\",\n byKey,\n byRowId: [...byKey].sort((left, right) => left.rowId - right.rowId),\n };\n}\n\n/** Parse a `bubbleId:*` / `bubble:*` row value into a field-validated BubbleData. */\nfunction parseBubbleRow(value: string): BubbleData | null {\n const record = safeParseJsonRecord(value);\n if (!record) return null;\n\n const timingInfo = asRecord(record.timingInfo);\n const tokenCount = asRecord(record.tokenCount);\n const modelInfo = asRecord(record.modelInfo);\n const toolFormerData = asRecord(record.toolFormerData);\n\n return {\n ...record,\n id: narrowString(\"bubble.id\", record.id),\n composerId: narrowString(\"bubble.composerId\", record.composerId),\n chatMessages: parseChatMessages(record.chatMessages),\n type: narrowNumber(\"bubble.type\", record.type),\n text: narrowString(\"bubble.text\", record.text),\n requestId: narrowString(\"bubble.requestId\", record.requestId),\n createdAt: narrowNumber(\"bubble.createdAt\", record.createdAt),\n timestamp: narrowNumber(\"bubble.timestamp\", record.timestamp),\n timingInfo: timingInfo\n ? {\n clientRpcSendTime: narrowNumber(\n \"bubble.timingInfo.clientRpcSendTime\",\n timingInfo.clientRpcSendTime,\n ),\n clientSettleTime: narrowNumber(\n \"bubble.timingInfo.clientSettleTime\",\n timingInfo.clientSettleTime,\n ),\n clientEndTime: narrowNumber(\"bubble.timingInfo.clientEndTime\", timingInfo.clientEndTime),\n }\n : undefined,\n tokenCount: tokenCount\n ? {\n inputTokens: narrowNumber(\"bubble.tokenCount.inputTokens\", tokenCount.inputTokens),\n outputTokens: narrowNumber(\"bubble.tokenCount.outputTokens\", tokenCount.outputTokens),\n }\n : undefined,\n modelInfo: modelInfo\n ? { modelName: narrowString(\"bubble.modelInfo.modelName\", modelInfo.modelName) }\n : undefined,\n toolFormerData: toolFormerData\n ? {\n name: narrowString(\"bubble.toolFormerData.name\", toolFormerData.name),\n toolCallId: narrowString(\"bubble.toolFormerData.toolCallId\", toolFormerData.toolCallId),\n status: narrowString(\"bubble.toolFormerData.status\", toolFormerData.status),\n params: toolFormerData.params,\n result: toolFormerData.result,\n additionalData: asRecord(toolFormerData.additionalData),\n }\n : undefined,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nconst CURSOR_TOOL_TITLE_MAP: Record<string, string> = {\n read_file_v2: \"read\",\n edit_file_v2: \"edit\",\n run_terminal_command_v2: \"bash\",\n ripgrep_raw_search: \"grep\",\n glob_file_search: \"glob\",\n};\n\nfunction mapToolTitle(toolName: string): string {\n return CURSOR_TOOL_TITLE_MAP[toolName] ?? toolName;\n}\n\n/** Normalize tool output into MessagePart[] */\nfunction normalizeToolOutputParts(output: unknown, timestampMs: number): MessagePart[] {\n if (output == null) return [];\n\n if (typeof output === \"string\") {\n const text = cleanInternalText(output);\n return text ? [{ type: \"text\" as const, text, time_created: timestampMs }] : [];\n }\n\n if (Array.isArray(output)) {\n const parts: MessagePart[] = [];\n for (const item of output) {\n if (typeof item === \"object\" && item !== null) {\n const record = asRecord(item);\n const text = String(record?.text ?? record?.content ?? \"\");\n const cleaned = cleanInternalText(text);\n if (cleaned) parts.push({ type: \"text\", text: cleaned, time_created: timestampMs });\n } else if (typeof item === \"string\") {\n const text = cleanInternalText(item);\n if (text) parts.push({ type: \"text\", text, time_created: timestampMs });\n }\n }\n return parts;\n }\n\n // For object output, stringify for readability\n const text = cleanInternalText(String(output));\n return text ? [{ type: \"text\", text, time_created: timestampMs }] : [];\n}\n\n/** Extract a timestamp (in ms) from a chat message */\nfunction extractTimestamp(msg: ChatMessage): number {\n if (msg.createdAt && typeof msg.createdAt === \"number\" && msg.createdAt > 0) {\n return msg.createdAt;\n }\n if (msg.timestamp && typeof msg.timestamp === \"number\" && msg.timestamp > 0) {\n return msg.timestamp;\n }\n return 0;\n}\n\nfunction isInternalBubble(bubble: BubbleData): boolean {\n return [\"eventType\", \"kind\", \"subtype\", \"name\"].some((key) => isInternalEventType(bubble[key]));\n}\n\n/** Build a normalized tool state object from an action entry */\nfunction buildToolState(action: ActionEntry): ToolPartState {\n let output = action.output;\n if (action.output != null) {\n const ts = 0; // we don't have a finer-grained timestamp for the output\n const outputParts = normalizeToolOutputParts(action.output, ts);\n output = outputParts.length > 0 ? outputParts : action.output;\n }\n\n const [part] = normalizeMessageParts([\n {\n type: \"tool\",\n tool: action.tool ?? \"unknown\",\n input: action.input,\n output,\n state: action.state,\n },\n ]);\n return part?.type === \"tool\" ? part.state : { status: \"running\" };\n}\n\n/** Build a MessagePart for a tool action */\nfunction buildToolPart(action: ActionEntry, timestampMs: number): MessagePart {\n const toolName = action.tool ?? \"unknown\";\n return {\n type: \"tool\",\n tool: mapToolTitle(toolName),\n callID: action.type ? `${action.type}:${String(action.input?.id ?? \"\")}` : \"\",\n title: `Tool: ${mapToolTitle(toolName)}`,\n state: buildToolState(action),\n time_created: timestampMs,\n };\n}\n\n/** Build a MessagePart for terminal command actions */\nfunction buildTerminalToolPart(action: ActionEntry, timestampMs: number): MessagePart {\n const command = String(action.input?.command ?? \"\");\n const description = cleanInternalText(String(action.input?.commandDescription ?? \"\"));\n\n const state = buildToolState(action);\n state.input = { command };\n state.output =\n typeof action.output === \"string\"\n ? [{ type: \"text\" as const, text: action.output, time_created: timestampMs }]\n : normalizeToolOutputParts(action.output, timestampMs);\n\n return {\n type: \"tool\",\n tool: \"bash\",\n callID: \"\",\n title: description || `bash: ${command.slice(0, 60)}`,\n state,\n time_created: timestampMs,\n };\n}\n\n/** Convert an ActionEntry into a MessagePart */\nfunction convertActionToPart(action: ActionEntry, timestampMs: number): MessagePart | null {\n const toolName = action.tool ?? \"\";\n\n // Terminal commands get special handling\n if (toolName === \"run_terminal_command_v2\") {\n return buildTerminalToolPart(action, timestampMs);\n }\n\n // Generic tool call\n if (toolName && action.type === \"tool\") {\n return buildToolPart(action, timestampMs);\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// CursorAgent\n// ---------------------------------------------------------------------------\n\nexport class CursorAgent extends DatabaseSessionSource {\n readonly name = \"cursor\";\n readonly displayName = \"Cursor\";\n\n private dbPath: string | null = null;\n\n // Cache composer data from scan so getSessionData can reuse it\n private composerCache = new Map<string, ComposerData>();\n\n protected getDatabasePath(): string | null {\n if (!this.dbPath) {\n this.dbPath = this.findDbPath();\n }\n return this.dbPath;\n }\n\n private findDbPath(): string | null {\n if (!isSqliteAvailable()) return null;\n const dataPath = resolveCursorDataRoot();\n if (!dataPath) return null;\n return join(dataPath, \"globalStorage\", \"state.vscdb\");\n }\n\n getSessionWatchPlan() {\n const dataPath = resolveCursorDataRoot();\n return {\n status: \"supported\" as const,\n targets: dataPath\n ? [\n {\n root: dataPath,\n path: join(dataPath, \"globalStorage\", \"state.vscdb\"),\n },\n { root: dataPath, path: join(dataPath, \"workspaceStorage\") },\n ]\n : [],\n };\n }\n\n /**\n * Build a map of composerId → workspace folder path by reading\n * workspaceStorage/{id}/workspace.json and the corresponding state.vscdb.\n */\n private buildWorkspacePathMap(): Map<string, string> {\n const map = new Map<string, string>();\n const dataPath = resolveCursorDataRoot();\n if (!dataPath) return map;\n\n const wsStoragePath = join(dataPath, \"workspaceStorage\");\n if (!existsSync(wsStoragePath)) return map;\n\n let entryNames: string[];\n try {\n entryNames = readdirSync(wsStoragePath) as string[];\n } catch {\n return map;\n }\n\n for (const name of entryNames) {\n const wsDir = join(wsStoragePath, name);\n try {\n if (!statSync(wsDir).isDirectory()) continue;\n } catch {\n continue;\n }\n const wsJsonPath = join(wsDir, \"workspace.json\");\n if (!existsSync(wsJsonPath)) continue;\n\n // Parse workspace.json to get the project folder path\n let workspacePath: string;\n try {\n const data = asRecord(JSON.parse(readFileSync(wsJsonPath, \"utf-8\")));\n const uri =\n narrowString(\"workspaceJson.folder\", data?.folder) ??\n narrowString(\"workspaceJson.workspace\", data?.workspace) ??\n \"\";\n if (!uri) continue;\n workspacePath = normalize(decodeURIComponent(uri.replace(/^file:\\/\\//, \"\")));\n } catch {\n continue;\n }\n\n // Read composer IDs from this workspace's state.vscdb (ItemTable)\n const wsDbPath = join(wsDir, \"state.vscdb\");\n if (!existsSync(wsDbPath)) continue;\n\n const wsDb = openDbReadOnly(wsDbPath);\n if (!wsDb) continue;\n\n try {\n const row = wsDb\n .prepare(\"SELECT value FROM ItemTable WHERE key = 'composer.composerData'\")\n .get() as { value: string } | undefined;\n if (!row?.value) continue;\n\n const parsed: unknown = JSON.parse(row.value);\n const composers = asArray(asRecord(parsed)?.allComposers) ?? asArray(parsed) ?? [];\n\n for (const item of composers) {\n const composer = asRecord(item);\n if (!composer) continue;\n const id =\n narrowString(\"workspaceComposer.composerId\", composer.composerId) ??\n narrowString(\"workspaceComposer.id\", composer.id);\n if (id) map.set(id, workspacePath);\n }\n } catch {\n // skip unreadable workspace db\n } finally {\n wsDb.close();\n }\n }\n\n return map;\n }\n\n isAvailable(): boolean {\n this.dbPath = this.findDbPath();\n return this.dbPath !== null && existsSync(this.dbPath);\n }\n\n scan(options?: AgentScanOptions): SessionHead[] {\n if (!this.dbPath) return [];\n\n const scanMarker = perf.start(\"cursor:scan\");\n\n const dbMarker = perf.start(\"openDatabase\");\n const db = this.openDatabase();\n perf.end(dbMarker);\n\n if (!db) throw new SessionScanError(this.name, \"opening the database\");\n\n // Build composerId → workspace path map from workspaceStorage\n const wsMarker = perf.start(\"buildWorkspacePathMap\");\n const workspacePathMap = this.buildWorkspacePathMap();\n perf.end(wsMarker);\n\n try {\n const rows = db\n .prepare(\"SELECT key, value FROM cursorDiskKV WHERE key LIKE 'composerData:%'\")\n .all() as Array<{ key: string; value: string }>;\n\n // Heads are emitted by composer order regardless of which phase produced\n // them, so the scan output does not depend on how bubbles are read.\n const emitted = new Map<number, SessionHead>();\n const pending: PendingComposer[] = [];\n let order = 0;\n options?.onProgress?.({ total: rows.length, processed: 0, sessions: 0 });\n let processed = 0;\n\n for (const row of rows) {\n try {\n const composer = parseComposerRow(row.value);\n if (!composer || (!composer.id && !composer.composerId)) continue;\n\n const composerId = composer.id || composer.composerId || \"\";\n const createdAt = composer.createdAt ?? 0;\n const updatedAt =\n composer.updatedAt ?? composer.lastUpdatedAt ?? composer.lastSendTime ?? createdAt;\n if (!matchesScanWindow(updatedAt, options)) continue;\n\n const fastTitle = this.extractTitle(composer);\n const hasFastMessages = Array.isArray(composer.chatMessages);\n const fastMessageCount = composer.chatMessages?.length ?? 0;\n const hasSubagents =\n Array.isArray(composer.subagentInfos) && composer.subagentInfos.length > 0;\n if (options?.fast) {\n const directory = workspacePathMap.get(composerId) ?? \"\";\n const totalCost =\n estimateTokenCost(composer.modelConfig?.modelName ?? composer.model, {\n input: composer.inputTokenCount ?? 0,\n output: composer.outputTokenCount ?? 0,\n }) ?? 0;\n const head = getParsedSession(\n hasFastMessages && fastMessageCount === 0 && !hasSubagents\n ? filteredSession<SessionHead>(\"no visible messages\")\n : parsedSession<SessionHead>({\n id: composerId,\n slug: `cursor/${composerId}`,\n title: fastTitle,\n directory,\n time_created: createdAt,\n time_updated: updatedAt || undefined,\n stats: {\n message_count: fastMessageCount,\n total_input_tokens: composer.inputTokenCount ?? 0,\n total_output_tokens: composer.outputTokenCount ?? 0,\n total_cost: totalCost,\n cost_source: totalCost > 0 ? \"estimated\" : undefined,\n },\n }),\n );\n if (!head) continue;\n emitted.set(order, head);\n order += 1;\n this.composerCache.set(composerId, composer);\n this.sessionMetaMap.set(composerId, {\n id: composerId,\n sourcePath: this.dbPath || \"\",\n });\n continue;\n }\n\n pending.push({ composer, composerId, createdAt, updatedAt, hasSubagents, order });\n order += 1;\n } catch {\n // skip malformed entries\n } finally {\n processed += 1;\n options?.onProgress?.({ total: rows.length, processed, sessions: emitted.size });\n }\n }\n\n // Second phase: one ordered pass over every bubble row. Keys share the\n // composer prefix, so each group arrives contiguously and only one group\n // is held at a time — replacing two full scans per composer.\n const bubbleMarker = perf.start(\"cursor:bubbles\");\n const wanted = new Map(pending.map((entry) => [entry.composerId, entry]));\n this.forEachComposerBubbles(db, wanted, (bubbles) => {\n const entry = wanted.get(bubbles.composerId);\n if (!entry) return;\n wanted.delete(bubbles.composerId);\n const head = this.buildScanHead(entry, bubbles, workspacePathMap);\n if (head) emitted.set(entry.order, head);\n });\n // Composers with no bubbles at all still go through the same builder.\n for (const entry of wanted.values()) {\n const head = this.buildScanHead(\n entry,\n { composerId: entry.composerId, byKey: [], byRowId: [] },\n workspacePathMap,\n );\n if (head) emitted.set(entry.order, head);\n }\n perf.end(bubbleMarker);\n\n const heads = [...emitted.entries()]\n .sort(([left], [right]) => left - right)\n .map(([, head]) => head);\n options?.onProgress?.({ total: rows.length, processed, sessions: heads.length });\n\n perf.end(scanMarker);\n return heads;\n } catch (error) {\n throw new SessionScanError(this.name, \"reading composers\", { cause: error });\n } finally {\n db.close();\n }\n }\n\n getSessionData(sessionId: string): SessionDetail {\n // Ensure dbPath is set\n if (!this.dbPath) {\n this.dbPath = this.findDbPath();\n }\n if (!this.dbPath) {\n throw new Error(\"Cursor database is missing\");\n }\n\n const db = this.openDatabase();\n if (!db) {\n throw new Error(\"Cursor database is missing\");\n }\n\n try {\n // Try cached composer data first\n let composer = this.composerCache.get(sessionId);\n let resolvedSessionId = sessionId;\n\n if (!composer) {\n // Try loading directly by sessionId (might be composerId)\n composer = this.loadComposer(db, sessionId) ?? undefined;\n }\n\n if (!composer) {\n // sessionId might be a requestId - try to find the composer\n const composerId = this.findComposerIdByRequestId(db, sessionId);\n if (composerId) {\n composer = this.loadComposer(db, composerId) ?? undefined;\n resolvedSessionId = sessionId; // Keep the requestId as sessionId\n }\n }\n\n if (!composer) {\n throw new Error(`Session not found: ${sessionId}`);\n }\n\n const composerId = composer.id || composer.composerId || \"\";\n const createdAt = composer.createdAt ?? 0;\n const updatedAt = composer.updatedAt ?? createdAt;\n\n // Load messages from bubbles (like agent-dump does)\n const messages = this.loadMessagesFromBubbles(\n db,\n composerId,\n resolvedSessionId,\n composer.modelConfig?.modelName ?? composer.model ?? null,\n );\n\n // Append subagent messages\n this.appendSubagentMessages(db, composer, messages);\n const cleanedMessages = cleanParsedMessages(messages);\n const title = this.extractTitle(composer, cleanedMessages);\n\n // Aggregate stats\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n let totalCost = 0;\n\n for (const msg of cleanedMessages) {\n totalInputTokens += msg.tokens?.input ?? 0;\n totalOutputTokens += msg.tokens?.output ?? 0;\n totalCost += msg.cost ?? 0;\n }\n\n // Use session-level token counts if per-message counts are zero\n if (totalInputTokens === 0) totalInputTokens = composer.inputTokenCount ?? 0;\n if (totalOutputTokens === 0) totalOutputTokens = composer.outputTokenCount ?? 0;\n if (totalCost === 0) {\n totalCost =\n estimateTokenCost(composer.modelConfig?.modelName ?? composer.model, {\n input: totalInputTokens,\n output: totalOutputTokens,\n }) ?? 0;\n }\n\n // Retrieve directory from cache (populated during scan) or build map on demand\n const cachedDir = this.composerCache.get(`__dir__${composerId}`);\n const directory =\n (cachedDir as unknown as { directory?: string })?.directory ??\n this.buildWorkspacePathMap().get(composerId) ??\n \"\";\n\n return {\n reference: { agentName: this.name, sessionId: resolvedSessionId },\n id: resolvedSessionId,\n title,\n slug: `cursor/${resolvedSessionId}`,\n directory,\n time_created: createdAt,\n time_updated: updatedAt || undefined,\n stats: {\n message_count: cleanedMessages.length,\n total_input_tokens: totalInputTokens,\n total_output_tokens: totalOutputTokens,\n total_cost: totalCost,\n cost_source: totalCost > 0 ? \"estimated\" : undefined,\n },\n messages: cleanedMessages,\n };\n } finally {\n db.close();\n }\n }\n\n // --- Private helpers ---\n\n private openDatabase(): SQLiteDatabase | null {\n if (!this.dbPath) return null;\n return openDbReadOnly(this.dbPath);\n }\n\n /**\n * Streams every bubble row once, in key order, handing each composer's group\n * to the caller. A key-ordered scan keeps a composer's bubbles contiguous, so\n * only one group is materialized at a time.\n */\n private forEachComposerBubbles(\n db: SQLiteDatabase,\n wanted: Map<string, PendingComposer>,\n onGroup: (bubbles: ComposerBubbles) => void,\n ): void {\n if (wanted.size === 0) return;\n\n let currentId: string | null = null;\n let group: BubbleRow[] = [];\n const flush = () => {\n if (currentId != null && group.length > 0) onGroup(groupBubbleRows(group));\n group = [];\n };\n\n const rows = db\n .prepare(\n \"SELECT rowid AS row_id, key, value FROM cursorDiskKV WHERE key LIKE 'bubbleId:%' ORDER BY key\",\n )\n .iterate() as Iterable<BubbleRow>;\n for (const row of rows) {\n const composerId = composerIdFromBubbleKey(row.key);\n if (composerId !== currentId) {\n flush();\n currentId = composerId;\n }\n if (wanted.has(composerId)) group.push(row);\n }\n flush();\n }\n\n /** Builds the head for one composer from bubbles that were parsed once. */\n private buildScanHead(\n entry: PendingComposer,\n bubbles: ComposerBubbles,\n workspacePathMap: Map<string, string>,\n ): SessionHead | null {\n const { composer, composerId, createdAt, updatedAt, hasSubagents } = entry;\n const requestId = this.requestIdFromBubbles(bubbles);\n const sessionId = requestId || composerId;\n\n const parsedMessages = cleanParsedMessages(\n this.messagesFromBubbles(bubbles, composer.modelConfig?.modelName ?? composer.model ?? null),\n );\n const messages = getParsedSession(\n parsedMessages.length === 0 && !hasSubagents\n ? filteredSession<Message[]>(\"no visible messages\")\n : parsedSession(parsedMessages),\n );\n if (!messages) return null;\n\n const title = this.extractTitle(composer, messages);\n const directory = workspacePathMap.get(composerId) ?? \"\";\n\n const modelUsageMap: Record<string, number> = {};\n let totalCost = 0;\n for (const msg of messages) {\n totalCost += msg.cost ?? 0;\n if (msg.model) {\n const msgTokens = (msg.tokens?.input ?? 0) + (msg.tokens?.output ?? 0);\n if (msgTokens > 0) {\n modelUsageMap[msg.model] = (modelUsageMap[msg.model] ?? 0) + msgTokens;\n }\n }\n }\n const hasModelUsage = Object.keys(modelUsageMap).length > 0;\n\n this.composerCache.set(sessionId, composer);\n this.composerCache.set(`__mapping__${composerId}`, {\n sessionId,\n } as unknown as ComposerData);\n if (directory) {\n this.composerCache.set(`__dir__${composerId}`, {\n directory,\n } as unknown as ComposerData);\n }\n this.sessionMetaMap.set(sessionId, { id: sessionId, sourcePath: this.dbPath || \"\" });\n\n return {\n id: sessionId,\n slug: `cursor/${sessionId}`,\n title,\n directory,\n time_created: createdAt,\n time_updated: updatedAt || undefined,\n stats: {\n message_count: messages.length,\n total_input_tokens: composer.inputTokenCount ?? 0,\n total_output_tokens: composer.outputTokenCount ?? 0,\n total_cost: totalCost,\n cost_source: totalCost > 0 ? \"estimated\" : undefined,\n },\n model_usage: hasModelUsage ? modelUsageMap : undefined,\n };\n }\n\n /** First request id in key order, matching what agent-dump reports. */\n private requestIdFromBubbles(bubbles: ComposerBubbles): string | null {\n for (const entry of bubbles.byKey) {\n const requestId = entry.bubble.requestId?.trim();\n if (requestId) return requestId;\n }\n return null;\n }\n\n /** Find composerId by requestId (reverse lookup) */\n private findComposerIdByRequestId(db: SQLiteDatabase, requestId: string): string | null {\n try {\n const rows = db\n .prepare(\"SELECT key, value FROM cursorDiskKV WHERE key LIKE 'bubbleId:%' AND value LIKE ?\")\n .all(`%\"requestId\":\"${requestId}\"%`) as Array<{ key: string; value: string }>;\n\n for (const row of rows) {\n try {\n const bubble = parseBubbleRow(row.value);\n if (bubble?.requestId === requestId) {\n // Extract composerId from key (bubbleId:{composerId}:{bubbleId})\n const keyParts = row.key.split(\":\");\n if (keyParts.length >= 2 && keyParts[1]) {\n return keyParts[1];\n }\n }\n } catch {\n // skip malformed bubbles\n }\n }\n } catch {\n // ignore errors\n }\n return null;\n }\n\n /** Extract title from composer (like agent-dump) */\n private extractTitle(composer: ComposerData, messages: Message[] = []): string {\n const explicit = composer.name || composer.title;\n const messageTitle = firstUserMessageTitle(messages) ?? composer.text;\n return resolveSessionTitle(explicit, messageTitle, null);\n }\n\n /** Count messages from bubbles */\n private countMessagesFromBubbles(db: SQLiteDatabase, composerId: string): number {\n try {\n const rows = db\n .prepare(\"SELECT value FROM cursorDiskKV WHERE key LIKE ?\")\n .all(`bubbleId:${composerId}:%`) as Array<{ value: string }>;\n\n let count = 0;\n for (const row of rows) {\n try {\n const bubble = parseBubbleRow(row.value);\n // type 1 = user, type 2 = assistant\n if (bubble?.type === 1 || bubble?.type === 2) {\n count++;\n }\n } catch {\n // skip malformed bubbles\n }\n }\n return count;\n } catch {\n return 0;\n }\n }\n\n /** Load one composer's bubbles, for the detail path that only needs a single session. */\n private loadMessagesFromBubbles(\n db: SQLiteDatabase,\n composerId: string,\n _sessionId: string,\n initialModelName: string | null,\n ): Message[] {\n try {\n const rows = db\n .prepare(\"SELECT rowid AS row_id, key, value FROM cursorDiskKV WHERE key LIKE ?\")\n .all(`bubbleId:${composerId}:%`) as BubbleRow[];\n return this.messagesFromBubbles(groupBubbleRows(rows), initialModelName);\n } catch {\n return [];\n }\n }\n\n /** Build messages from bubbles already parsed once, in insertion order. */\n private messagesFromBubbles(\n bubbles: ComposerBubbles,\n initialModelName: string | null,\n ): Message[] {\n const messages: Message[] = [];\n\n {\n let activeModelName: string | null = initialModelName;\n let messageIndex = 0;\n\n for (const entry of bubbles.byRowId) {\n {\n const bubble = entry.bubble;\n if (isInternalBubble(bubble)) continue;\n const bubbleId = entry.key.split(\":\").pop() || String(messageIndex);\n\n // Determine role: type 2 = assistant, otherwise user\n const role = bubble.type === 2 ? \"assistant\" : \"user\";\n\n // Extract timestamp\n let timestampMs = 0;\n if (bubble.timingInfo?.clientRpcSendTime) {\n timestampMs = Math.floor(bubble.timingInfo.clientRpcSendTime);\n } else if (bubble.createdAt) {\n timestampMs = bubble.createdAt;\n } else if (bubble.timestamp) {\n timestampMs = bubble.timestamp;\n }\n\n // Track model from user turn\n if (bubble.modelInfo?.modelName) {\n activeModelName = bubble.modelInfo.modelName;\n }\n\n // Extract tokens\n const inputTokens = bubble.tokenCount?.inputTokens ?? 0;\n const outputTokens = bubble.tokenCount?.outputTokens ?? 0;\n\n // Build message parts\n const parts: MessagePart[] = [];\n\n // Text content\n const text = cleanInternalText(bubble.text ?? \"\");\n if (text) {\n parts.push({ type: \"text\", text, time_created: timestampMs });\n }\n\n // Tool calls from toolFormerData\n if (bubble.toolFormerData) {\n const toolPart = this.convertToolFormerData(bubble.toolFormerData, timestampMs);\n if (toolPart) {\n parts.push(toolPart);\n }\n }\n\n // Skip empty messages\n if (parts.length === 0) continue;\n\n const modelName = bubble.modelInfo?.modelName ?? activeModelName;\n const tokens = { input: inputTokens, output: outputTokens };\n const cost = estimateTokenCost(modelName, tokens);\n\n messages.push({\n id: `cursor-${bubbles.composerId}-${bubbleId}`,\n role: role as Message[\"role\"],\n agent: \"cursor\",\n time_created: timestampMs,\n time_completed: null,\n mode: role === \"assistant\" && parts.some((p) => p.type === \"tool\") ? \"tool\" : null,\n model: modelName,\n provider: null,\n tokens,\n cost: cost ?? 0,\n cost_source: cost !== null ? \"estimated\" : undefined,\n parts,\n });\n\n messageIndex++;\n }\n }\n }\n\n return messages;\n }\n\n /** Convert toolFormerData to MessagePart */\n private convertToolFormerData(\n toolData: BubbleData[\"toolFormerData\"],\n timestampMs: number,\n ): MessagePart | null {\n if (!toolData || !toolData.name) return null;\n\n const toolName = toolData.name;\n const normalizedName = toolName === \"create_plan\" ? \"plan\" : mapToolTitle(toolName);\n\n // Build state\n const state: ToolPartState = {\n status: toolData.status === \"completed\" ? \"completed\" : \"running\",\n };\n\n // Parse input params\n if (toolData.params) {\n if (typeof toolData.params === \"string\") {\n try {\n state.input = JSON.parse(toolData.params);\n } catch {\n state.input = { _raw: toolData.params };\n }\n } else {\n state.input = toolData.params;\n }\n }\n\n // Parse result/output\n if (toolData.result !== undefined) {\n if (typeof toolData.result === \"string\") {\n try {\n const parsed = JSON.parse(toolData.result);\n state.output = parsed;\n if (parsed.error || parsed.message || parsed.stderr) {\n state.error = parsed.error || parsed.message || parsed.stderr;\n state.status = \"error\";\n }\n } catch {\n state.output = toolData.result;\n }\n } else {\n state.output = toolData.result;\n }\n }\n\n // Handle plan tool specially\n if (toolName === \"create_plan\") {\n const planText = String(asRecord(state.input)?.plan ?? \"\").trim();\n if (planText) {\n return {\n type: \"plan\",\n text: planText,\n approval_status: state.status === \"completed\" ? \"success\" : \"fail\",\n time_created: timestampMs,\n };\n }\n }\n\n return {\n type: \"tool\",\n tool: normalizedName,\n callID: toolData.toolCallId || \"\",\n title: `Tool: ${normalizedName}`,\n state,\n time_created: timestampMs,\n };\n }\n\n private loadComposer(db: SQLiteDatabase, sessionId: string): ComposerData | null {\n const row = db\n .prepare(\"SELECT value FROM cursorDiskKV WHERE key = ?\")\n .get(`composerData:${sessionId}`) as { value: string } | undefined;\n\n if (!row) return null;\n\n return parseComposerRow(row.value);\n }\n\n private loadBubble(db: SQLiteDatabase, sessionId: string): BubbleData | null {\n const row = db\n .prepare(\"SELECT value FROM cursorDiskKV WHERE key = ?\")\n .get(`bubble:${sessionId}`) as { value: string } | undefined;\n\n if (!row) return null;\n\n return parseBubbleRow(row.value);\n }\n\n private appendSubagentMessages(\n db: SQLiteDatabase,\n composer: ComposerData,\n messages: Message[],\n ): void {\n const subagentInfos = composer.subagentInfos;\n if (!Array.isArray(subagentInfos) || subagentInfos.length === 0) return;\n\n for (const subInfo of subagentInfos) {\n if (!subInfo.id) continue;\n\n const bubble = this.loadBubble(db, subInfo.id);\n if (!bubble || !Array.isArray(bubble.chatMessages)) continue;\n\n for (const chatMsg of bubble.chatMessages) {\n const role = chatMsg.role?.trim().toLowerCase();\n if (role !== \"user\" && role !== \"assistant\") continue;\n\n const timestampMs = extractTimestamp(chatMsg);\n const parts: MessagePart[] = [];\n\n const text = cleanInternalText(chatMsg.text ?? \"\");\n if (text) {\n parts.push({ type: \"text\", text, time_created: timestampMs });\n }\n\n if (role === \"assistant\" && Array.isArray(chatMsg.actions)) {\n for (const action of chatMsg.actions) {\n if (isInternalEventType(action.type) || isInternalEventType(action.tool)) continue;\n const part = convertActionToPart(action, timestampMs);\n if (part) parts.push(part);\n }\n }\n\n if (parts.length === 0) continue;\n\n messages.push({\n id: `cursor-sub-${subInfo.id}`,\n role: role as Message[\"role\"],\n agent: \"cursor\",\n time_created: timestampMs,\n time_completed: null,\n mode: null,\n model: null,\n provider: null,\n tokens: undefined,\n cost: 0,\n subagent_id: subInfo.id,\n nickname: subInfo.nickname ?? subInfo.title,\n parts,\n });\n }\n }\n }\n}\n","/**\n * 性能追踪工具 - 用于测量启动过程中的各个阶段耗时\n */\n\nexport interface PerfMarker {\n name: string;\n startTime: number;\n endTime?: number;\n duration?: number;\n children: PerfMarker[];\n parent?: PerfMarker;\n}\n\nclass PerfTracer {\n private rootMarkers: PerfMarker[] = [];\n private activeStack: PerfMarker[] = [];\n private enabled = false;\n\n enable() {\n this.enabled = true;\n }\n\n start(name: string): PerfMarker {\n const marker: PerfMarker = {\n name,\n startTime: performance.now(),\n children: [],\n };\n\n if (!this.enabled) return marker;\n\n const parent = this.activeStack[this.activeStack.length - 1];\n if (parent) {\n marker.parent = parent;\n parent.children.push(marker);\n } else {\n this.rootMarkers.push(marker);\n }\n\n this.activeStack.push(marker);\n return marker;\n }\n\n end(marker?: PerfMarker): void {\n if (!this.enabled) return;\n\n const target = marker ?? this.activeStack[this.activeStack.length - 1];\n if (!target) return;\n\n target.endTime = performance.now();\n target.duration = target.endTime - target.startTime;\n\n // Pop until we remove the target\n while (this.activeStack.length > 0) {\n const popped = this.activeStack.pop();\n if (popped === target) break;\n }\n }\n\n measure<T>(name: string, fn: () => T): T {\n const marker = this.start(name);\n try {\n return fn();\n } finally {\n this.end(marker);\n }\n }\n\n async measureAsync<T>(name: string, fn: () => Promise<T>): Promise<T> {\n const marker = this.start(name);\n try {\n return await fn();\n } finally {\n this.end(marker);\n }\n }\n\n getReport(): string {\n if (!this.enabled) return \"Performance tracing disabled\";\n\n const lines: string[] = [];\n lines.push(\"\\n=== Performance Report ===\\n\");\n\n for (const marker of this.rootMarkers) {\n this.formatMarker(marker, 0, lines);\n }\n\n return lines.join(\"\\n\");\n }\n\n private formatMarker(marker: PerfMarker, depth: number, lines: string[]): void {\n const indent = \" \".repeat(depth);\n const duration = marker.duration?.toFixed(2) ?? \"?\";\n lines.push(`${indent}${marker.name}: ${duration}ms`);\n\n for (const child of marker.children) {\n this.formatMarker(child, depth + 1, lines);\n }\n }\n\n reset(): void {\n this.rootMarkers = [];\n this.activeStack = [];\n }\n}\n\nexport const perf = new PerfTracer();\n","import { existsSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport {\n SingleFileSessionSource,\n filteredSession,\n getParsedSession,\n parsedSession,\n} from \"./base.js\";\nimport type {\n AgentScanOptions,\n FileSessionMeta,\n ParseSessionResult,\n SessionSourceFile,\n SessionSourceRef,\n} from \"./base.js\";\nimport type { Message, MessagePart, SessionDetail, SessionHead } from \"../types/index.js\";\nimport { firstExisting, resolveHomePath } from \"../discovery/paths.js\";\nimport { readJsonlFile } from \"../utils/jsonl.js\";\nimport { estimateTokenCost } from \"../utils/cost.js\";\nimport { asNumber, asRecord, asString, narrowField } from \"../utils/narrow.js\";\nimport { cleanInternalText } from \"../utils/session-normalization.js\";\nimport { basenameTitle, normalizeTitleText, resolveSessionTitle } from \"../utils/title-fallback.js\";\nimport { TranscriptBuilder, type TranscriptMessageInput } from \"./transcript-builder.js\";\n\nconst HEAD_INDEX_VERSION = \"pi-head-v1\";\nconst PARSER_VERSION = \"pi-parser-v1\";\n\nexport function resolvePiDataRoot(): string {\n return resolveHomePath(\"PI_HOME\", \".pi\");\n}\n\ninterface SessionMeta extends FileSessionMeta {\n headIndexVersion: string;\n parserVersion: string;\n}\n\ninterface ParsedPiFile {\n sessionId: string;\n directory: string;\n createdAt: number;\n updatedAt: number;\n title: string;\n pathEntries: Record<string, unknown>[];\n}\n\nfunction parseTimestampMs(value: unknown): number {\n if (typeof value === \"number\") return Number.isFinite(value) ? value : 0;\n const text = String(value ?? \"\").trim();\n if (!text) return 0;\n const ts = Date.parse(text);\n return Number.isNaN(ts) ? 0 : ts;\n}\n\nfunction narrowPiField<T>(\n field: string,\n value: unknown,\n narrow: (v: unknown) => T | undefined,\n): T | undefined {\n return narrowField(\"pi\", field, value, narrow);\n}\n\n/**\n * Reports drift only when the timestamp is present but neither a number nor\n * a string (e.g. an object) — actual date parsing (and its silent-0\n * fallback for unparseable text) is unchanged, via `parseTimestampMs`.\n */\nfunction narrowTimestampMs(field: string, value: unknown): number {\n const shaped = narrowPiField(field, value, (v) =>\n typeof v === \"number\" || typeof v === \"string\" ? v : undefined,\n );\n return shaped === undefined ? 0 : parseTimestampMs(shaped);\n}\n\nfunction extractSessionIdFromFilename(filePath: string): string {\n const stem = basename(filePath, \".jsonl\");\n const underscore = stem.indexOf(\"_\");\n return underscore >= 0 ? stem.slice(underscore + 1) || stem : stem;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction contentToText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n return content\n .map((item) => {\n if (!isObject(item)) return \"\";\n if (item[\"type\"] === \"text\") return String(item[\"text\"] ?? \"\");\n if (item[\"type\"] === \"image\") return \"[image]\";\n return \"\";\n })\n .filter(Boolean)\n .join(\"\\n\");\n}\n\nfunction normalizeTextParts(content: unknown, timestampMs: number): MessagePart[] {\n const text = cleanInternalText(contentToText(content));\n return text ? [{ type: \"text\", text, time_created: timestampMs }] : [];\n}\n\nfunction getEntryTimestamp(entry: Record<string, unknown>): number {\n return narrowTimestampMs(\"entry.timestamp\", entry[\"timestamp\"]);\n}\n\nfunction chooseLeafEntry(entries: Record<string, unknown>[]): Record<string, unknown> | null {\n for (let index = entries.length - 1; index >= 0; index -= 1) {\n if (typeof entries[index]?.[\"id\"] === \"string\") return entries[index]!;\n }\n return null;\n}\n\nfunction buildCurrentPathEntries(entries: Record<string, unknown>[]): Record<string, unknown>[] {\n const byId = new Map<string, Record<string, unknown>>();\n for (const entry of entries) {\n const id = entry[\"id\"];\n if (typeof id === \"string\" && id) byId.set(id, entry);\n }\n\n const leaf = chooseLeafEntry(entries);\n if (!leaf) return [];\n\n const path: Record<string, unknown>[] = [];\n const seen = new Set<string>();\n let current: Record<string, unknown> | undefined = leaf;\n while (current) {\n const id = String(current[\"id\"] ?? \"\");\n if (!id || seen.has(id)) break;\n seen.add(id);\n path.push(current);\n const parentId: unknown = current[\"parentId\"];\n current = typeof parentId === \"string\" ? byId.get(parentId) : undefined;\n }\n\n return path.reverse();\n}\n\nexport class PiAgent extends SingleFileSessionSource<SessionMeta> {\n readonly name = \"pi\";\n readonly displayName = \"Pi\";\n\n private basePath: string | null = null;\n\n private findBasePath(): string | null {\n return firstExisting(join(resolvePiDataRoot(), \"agent\", \"sessions\"), \"data/pi\");\n }\n\n getSessionWatchPlan() {\n const dataRoot = resolvePiDataRoot();\n return {\n status: \"supported\" as const,\n targets: [\n { root: dataRoot, path: join(dataRoot, \"agent\", \"sessions\") },\n { root: \"data/pi\", path: \"data/pi\" },\n ],\n };\n }\n\n isAvailable(): boolean {\n this.basePath = this.findBasePath();\n if (!this.basePath) return false;\n return this.listSessionFiles().length > 0;\n }\n\n listSessionSources(options?: AgentScanOptions): SessionSourceRef[] {\n if (!this.basePath) return [];\n return this.listSessionFiles(options).map(({ file, stat }) => ({\n sessionId: extractSessionIdFromFilename(file),\n sourcePath: file,\n fingerprint: this.sourceFingerprint(stat),\n }));\n }\n\n getSessionData(sessionId: string): SessionDetail {\n const meta = this.sessionMetaMap.get(sessionId);\n if (!meta) throw new Error(`Session not found: ${sessionId}`);\n if (!existsSync(meta.sourcePath)) throw new Error(`Session file missing: ${meta.sourcePath}`);\n\n const parsed = this.parsePiFile(meta.sourcePath);\n const state = this.convertEntries(parsed.pathEntries);\n\n return {\n reference: { agentName: this.name, sessionId: meta.id },\n id: meta.id,\n title: meta.title,\n slug: `pi/${meta.id}`,\n directory: meta.directory,\n time_created: meta.createdAt,\n time_updated: meta.updatedAt,\n stats: {\n message_count: state.messages.length,\n total_input_tokens: state.totalInputTokens,\n total_output_tokens: state.totalOutputTokens,\n total_cache_read_tokens: state.totalCacheReadTokens || undefined,\n total_cache_create_tokens: state.totalCacheCreateTokens || undefined,\n total_cost: state.totalCost,\n cost_source: state.totalCost > 0 ? \"recorded\" : undefined,\n },\n messages: state.messages,\n };\n }\n\n private listSessionFiles(options?: AgentScanOptions): SessionSourceFile[] {\n if (!this.basePath) return [];\n return this.walkFiles(\n this.basePath,\n (entry) => entry.isFile() && entry.name.endsWith(\".jsonl\"),\n { scanWindow: options },\n );\n }\n\n protected createFileSessionMeta(head: SessionHead, source: SessionSourceFile): SessionMeta {\n return this.buildFileSessionMeta({\n head,\n source,\n fingerprint: this.sourceFingerprint(source.stat),\n extras: {\n headIndexVersion: HEAD_INDEX_VERSION,\n parserVersion: PARSER_VERSION,\n },\n });\n }\n\n /** Fingerprint depends on an already-fetched stat to avoid re-statting the same file. */\n private sourceFingerprint(stat: { mtimeMs: number; size: number }): string {\n return JSON.stringify([HEAD_INDEX_VERSION, PARSER_VERSION, stat.mtimeMs, stat.size]);\n }\n\n protected parseFileSessionHead(filePath: string): SessionHead | null {\n return getParsedSession(this.parseSessionHeadResult(filePath));\n }\n\n private parseSessionHeadResult(filePath: string): ParseSessionResult<SessionHead> {\n const parsed = this.parsePiFile(filePath);\n const state = this.convertEntries(parsed.pathEntries);\n const messageCount = state.messages.length;\n if (messageCount === 0) return filteredSession(\"no visible messages\");\n\n const modelUsage = Object.keys(state.modelUsage).length > 0 ? state.modelUsage : undefined;\n return parsedSession({\n id: parsed.sessionId,\n slug: `pi/${parsed.sessionId}`,\n title: parsed.title,\n directory: parsed.directory,\n time_created: parsed.createdAt,\n time_updated: parsed.updatedAt,\n stats: {\n message_count: messageCount,\n total_input_tokens: state.totalInputTokens,\n total_output_tokens: state.totalOutputTokens,\n total_cache_read_tokens: state.totalCacheReadTokens || undefined,\n total_cache_create_tokens: state.totalCacheCreateTokens || undefined,\n total_cost: state.totalCost,\n cost_source: state.totalCost > 0 ? \"recorded\" : undefined,\n },\n model_usage: modelUsage,\n });\n }\n\n private parsePiFile(filePath: string): ParsedPiFile {\n // Single streaming pass: the file is never held as a string, and header\n // selection happens inline instead of scanning a materialized record array.\n let header: Record<string, unknown> | null = null;\n let recordCount = 0;\n const entries: Record<string, unknown>[] = [];\n\n for (const record of readJsonlFile(filePath)) {\n recordCount += 1;\n if (record[\"type\"] === \"session\") {\n header ??= record;\n continue;\n }\n entries.push(record);\n }\n\n if (recordCount === 0) throw new Error(\"empty file\");\n if (!header) throw new Error(\"missing session header\");\n\n const pathEntries = buildCurrentPathEntries(entries);\n if (pathEntries.length === 0) throw new Error(\"empty session tree\");\n\n const sessionId = String(header[\"id\"] ?? extractSessionIdFromFilename(filePath)).trim();\n if (!sessionId) throw new Error(\"missing session id\");\n\n const stat = this.sessionSourceFile(filePath).stat;\n const directory = String(header[\"cwd\"] ?? \"\").trim() || basename(filePath, \".jsonl\");\n const createdAt = narrowTimestampMs(\"session.timestamp\", header[\"timestamp\"]) || stat.mtimeMs;\n const updatedAt = pathEntries.reduce(\n (max, entry) => Math.max(max, getEntryTimestamp(entry)),\n createdAt,\n );\n const explicitTitle = this.extractSessionName(pathEntries);\n const messageTitle = this.extractTitle(pathEntries);\n const directoryTitle = basenameTitle(directory);\n\n return {\n sessionId,\n directory,\n createdAt,\n updatedAt,\n title: resolveSessionTitle(explicitTitle, messageTitle, directoryTitle),\n pathEntries,\n };\n }\n\n private extractSessionName(entries: Record<string, unknown>[]): string | null {\n for (let index = entries.length - 1; index >= 0; index -= 1) {\n const entry = entries[index]!;\n if (entry[\"type\"] !== \"session_info\") continue;\n const name = normalizeTitleText(String(entry[\"name\"] ?? \"\"));\n if (name) return name;\n }\n return null;\n }\n\n private extractTitle(entries: Record<string, unknown>[]): string | null {\n for (const entry of entries) {\n if (entry[\"type\"] !== \"message\") continue;\n const message = entry[\"message\"];\n if (!isObject(message) || message[\"role\"] !== \"user\") continue;\n const title = normalizeTitleText(contentToText(message[\"content\"]));\n if (title) return title;\n }\n return null;\n }\n\n private convertEntries(entries: Record<string, unknown>[]): {\n messages: Message[];\n totalInputTokens: number;\n totalOutputTokens: number;\n totalCacheReadTokens: number;\n totalCacheCreateTokens: number;\n totalCost: number;\n modelUsage: Record<string, number>;\n } {\n const builder = new TranscriptBuilder({ messageDefaults: \"sparse\" });\n const modelUsage: Record<string, number> = {};\n\n for (const entry of entries) {\n const timestampMs = getEntryTimestamp(entry);\n const type = String(entry[\"type\"] ?? \"\");\n\n if (type === \"message\") {\n const message = narrowPiField(\"entry.message\", entry[\"message\"], asRecord);\n if (!message) continue;\n const result = this.convertAgentMessage(entry, message, timestampMs, builder);\n if (!result) continue;\n if (result.message) builder.appendMessage(result.message);\n if (result.model && result.totalTokens > 0) {\n modelUsage[result.model] = (modelUsage[result.model] ?? 0) + result.totalTokens;\n }\n continue;\n }\n\n const summary = this.convertSummaryEntry(entry, timestampMs);\n if (summary) builder.appendMessage(summary);\n }\n\n const result = builder.finish();\n\n return {\n messages: result.messages,\n totalInputTokens: result.stats.total_input_tokens,\n totalOutputTokens: result.stats.total_output_tokens,\n totalCacheReadTokens: result.stats.total_cache_read_tokens ?? 0,\n totalCacheCreateTokens: result.stats.total_cache_create_tokens ?? 0,\n totalCost: result.stats.total_cost,\n modelUsage,\n };\n }\n\n private convertAgentMessage(\n entry: Record<string, unknown>,\n message: Record<string, unknown>,\n timestampMs: number,\n builder: TranscriptBuilder,\n ): {\n message?: TranscriptMessageInput;\n totalTokens: number;\n model: string | null;\n } | null {\n const id = narrowPiField(\"message.id\", entry[\"id\"], asString) ?? \"\";\n const role = narrowPiField(\"message.role\", message[\"role\"], asString) ?? \"\";\n\n if (role === \"user\") {\n const parts = normalizeTextParts(message[\"content\"], timestampMs);\n if (parts.length === 0) return null;\n return this.emptyUsageResult({ id, role: \"user\", timestampMs, parts });\n }\n\n if (role === \"assistant\") {\n const parts = this.normalizeAssistantParts(message[\"content\"], timestampMs);\n if (parts.length === 0) return null;\n const usage = this.normalizeUsage(message[\"usage\"]);\n const model = typeof message[\"model\"] === \"string\" ? message[\"model\"].trim() : null;\n const cost = usage.cost ?? estimateTokenCost(model, usage.tokens) ?? 0;\n return {\n message: {\n id,\n role: \"assistant\",\n agent: \"pi\",\n timestampMs,\n parts,\n provider: typeof message[\"provider\"] === \"string\" ? message[\"provider\"] : null,\n model,\n tokens: usage.tokens,\n cost: cost || undefined,\n costSource: cost > 0 ? \"recorded\" : undefined,\n },\n totalTokens: usage.totalTokens,\n model,\n };\n }\n\n if (role === \"toolResult\") {\n this.attachToolResult(message, timestampMs, builder);\n return this.emptyUsageResult();\n }\n\n if (role === \"bashExecution\") {\n return this.emptyUsageResult(this.convertBashExecution(id, message, timestampMs));\n }\n\n if (role === \"custom\" && message[\"display\"] === true) {\n const parts = normalizeTextParts(message[\"content\"], timestampMs);\n if (parts.length === 0) return null;\n return this.emptyUsageResult({ id, role: \"user\", timestampMs, parts });\n }\n\n if (role === \"branchSummary\" || role === \"compactionSummary\") {\n const summary = String(message[\"summary\"] ?? \"\").trim();\n if (!summary) return null;\n return this.emptyUsageResult({\n id,\n role: \"assistant\",\n agent: \"pi\",\n timestampMs,\n parts: [{ type: \"text\", text: summary, time_created: timestampMs }],\n });\n }\n\n return null;\n }\n\n private normalizeAssistantParts(content: unknown, timestampMs: number): MessagePart[] {\n if (!Array.isArray(content)) return [];\n\n const parts: MessagePart[] = [];\n for (const item of content) {\n if (!isObject(item)) continue;\n const type = item[\"type\"];\n\n if (type === \"text\") {\n const text = cleanInternalText(String(item[\"text\"] ?? \"\"));\n if (text) parts.push({ type: \"text\", text, time_created: timestampMs });\n continue;\n }\n\n if (type === \"thinking\") {\n const text = cleanInternalText(String(item[\"thinking\"] ?? \"\"));\n if (text) parts.push({ type: \"reasoning\", text, time_created: timestampMs });\n continue;\n }\n\n if (type === \"toolCall\") {\n const callId = String(item[\"id\"] ?? \"\").trim();\n const toolName = String(item[\"name\"] ?? \"\").trim() || \"tool\";\n const toolPart: MessagePart = {\n type: \"tool\",\n tool: toolName,\n title: `Tool: ${toolName}`,\n callID: callId || undefined,\n time_created: timestampMs,\n state: {\n status: \"running\",\n input: item[\"arguments\"] ?? {},\n },\n };\n parts.push(toolPart);\n }\n }\n\n return parts;\n }\n\n private attachToolResult(\n message: Record<string, unknown>,\n timestampMs: number,\n builder: TranscriptBuilder,\n ): void {\n const callId = String(message[\"toolCallId\"] ?? \"\").trim();\n const output = normalizeTextParts(message[\"content\"], timestampMs);\n if (!callId) return;\n builder.resolveToolCall(callId, {\n output,\n status: message[\"isError\"] === true ? \"error\" : \"completed\",\n metadata: message[\"details\"],\n consume: true,\n });\n }\n\n private convertBashExecution(\n id: string,\n message: Record<string, unknown>,\n timestampMs: number,\n ): TranscriptMessageInput {\n const command = String(message[\"command\"] ?? \"\");\n const output = String(message[\"output\"] ?? \"\");\n const isError = Number(message[\"exitCode\"] ?? 0) !== 0 || message[\"cancelled\"] === true;\n return {\n id,\n role: \"tool\",\n timestampMs,\n parts: [\n {\n type: \"tool\",\n tool: \"bash\",\n title: \"Tool: bash\",\n time_created: timestampMs,\n state: {\n status: isError ? \"error\" : \"completed\",\n input: { command },\n output: output ? [{ type: \"text\", text: output, time_created: timestampMs }] : [],\n metadata: {\n exitCode: message[\"exitCode\"],\n cancelled: message[\"cancelled\"],\n truncated: message[\"truncated\"],\n fullOutputPath: message[\"fullOutputPath\"],\n },\n },\n },\n ],\n };\n }\n\n private convertSummaryEntry(\n entry: Record<string, unknown>,\n timestampMs: number,\n ): TranscriptMessageInput | null {\n const type = entry[\"type\"];\n if (type !== \"compaction\" && type !== \"branch_summary\" && type !== \"custom_message\") {\n return null;\n }\n\n if (type === \"custom_message\" && entry[\"display\"] !== true) return null;\n\n const rawText =\n type === \"custom_message\" ? contentToText(entry[\"content\"]) : String(entry[\"summary\"] ?? \"\");\n const text = cleanInternalText(rawText);\n if (!text) return null;\n\n return {\n id: narrowPiField(\"summary.id\", entry[\"id\"], asString) ?? \"\",\n role: type === \"custom_message\" ? \"user\" : \"assistant\",\n agent: type === \"custom_message\" ? undefined : \"pi\",\n timestampMs,\n parts: [{ type: \"text\", text, time_created: timestampMs }],\n };\n }\n\n private normalizeUsage(raw: unknown): {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheCreateTokens: number;\n totalTokens: number;\n cost: number | null;\n tokens: Message[\"tokens\"];\n } {\n const usage = narrowPiField(\"message.usage\", raw, asRecord) ?? {};\n const inputTokens = narrowPiField(\"message.usage.input\", usage[\"input\"], asNumber) ?? 0;\n const outputTokens = narrowPiField(\"message.usage.output\", usage[\"output\"], asNumber) ?? 0;\n const cacheReadTokens =\n narrowPiField(\"message.usage.cacheRead\", usage[\"cacheRead\"], asNumber) ?? 0;\n const cacheCreateTokens =\n narrowPiField(\"message.usage.cacheWrite\", usage[\"cacheWrite\"], asNumber) ?? 0;\n const totalTokens =\n narrowPiField(\"message.usage.totalTokens\", usage[\"totalTokens\"], asNumber) ??\n inputTokens + outputTokens + cacheReadTokens + cacheCreateTokens;\n const cost = isObject(usage[\"cost\"]) ? Number(usage[\"cost\"][\"total\"] ?? 0) : null;\n\n return {\n inputTokens: inputTokens + cacheReadTokens + cacheCreateTokens,\n outputTokens,\n cacheReadTokens,\n cacheCreateTokens,\n totalTokens,\n cost: cost && Number.isFinite(cost) ? cost : null,\n tokens: {\n input: inputTokens + cacheReadTokens + cacheCreateTokens,\n output: outputTokens,\n cache_read: cacheReadTokens || undefined,\n cache_create: cacheCreateTokens || undefined,\n },\n };\n }\n\n private emptyUsageResult(message?: TranscriptMessageInput): {\n message?: TranscriptMessageInput;\n totalTokens: number;\n model: string | null;\n } {\n return {\n message,\n totalTokens: 0,\n model: null,\n };\n }\n}\n","import { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\nimport { firstExisting } from \"../discovery/paths.js\";\nimport { isSqliteAvailable } from \"../utils/sqlite.js\";\nimport { OpenCodeSqliteAgent } from \"./opencode-sqlite.js\";\n\nexport function resolveZCodeDataRoot(): string | null {\n const currentPlatform = platform();\n if (currentPlatform !== \"darwin\" && currentPlatform !== \"win32\") return null;\n return join(homedir(), \".zcode\");\n}\n\nfunction findZCodeDbPath(): string | null {\n if (!isSqliteAvailable()) return null;\n const dataRoot = resolveZCodeDataRoot();\n if (!dataRoot) return null;\n return firstExisting(join(dataRoot, \"cli\", \"db\", \"db.sqlite\"));\n}\n\nfunction getZCodeSessionWatchPlan() {\n const dataRoot = resolveZCodeDataRoot();\n return {\n status: \"supported\" as const,\n targets: dataRoot ? [{ root: dataRoot, path: join(dataRoot, \"cli\", \"db\", \"db.sqlite\") }] : [],\n };\n}\n\nexport class ZCodeAgent extends OpenCodeSqliteAgent {\n constructor() {\n super({\n name: \"zcode\",\n displayName: \"ZCode\",\n findDbPath: findZCodeDbPath,\n getSessionWatchPlan: getZCodeSessionWatchPlan,\n });\n }\n}\n","import { registerAgent } from \"./registry.js\";\nimport { ClaudeCodeAgent, resolveClaudeCodeDataRoot } from \"./claudecode.js\";\nimport { OpenCodeAgent, resolveOpenCodeDataRoot } from \"./opencode.js\";\nimport { KimiAgent, resolveKimiDataRoot } from \"./kimi.js\";\nimport { KimiCodeAgent, resolveKimiCodeDataRoot } from \"./kimi-code.js\";\nimport { CodexAgent, resolveCodexDataRoot } from \"./codex.js\";\nimport { CursorAgent, resolveCursorDataRoot } from \"./cursor.js\";\nimport { PiAgent, resolvePiDataRoot } from \"./pi.js\";\nimport { ZCodeAgent, resolveZCodeDataRoot } from \"./zcode.js\";\n\nregisterAgent({\n icon: \"/icon/agent/claudecode.svg\",\n iconColored: true,\n resolveDataRoot: resolveClaudeCodeDataRoot,\n resumeCommandPrefix: \"claude --resume\",\n toolStrategy: \"custom\",\n create: () => new ClaudeCodeAgent(),\n});\n\nregisterAgent({\n icon: \"/icon/agent/opencode.svg\",\n resolveDataRoot: resolveOpenCodeDataRoot,\n resumeCommandPrefix: \"opencode -s\",\n toolStrategy: \"custom\",\n create: () => new OpenCodeAgent(),\n});\n\nregisterAgent({\n icon: \"/icon/agent/zcode.svg\",\n resolveDataRoot: resolveZCodeDataRoot,\n resumeCommandPrefix: null,\n toolStrategy: \"custom\",\n create: () => new ZCodeAgent(),\n});\n\nregisterAgent({\n icon: \"/icon/agent/kimi.svg\",\n resolveDataRoot: resolveKimiDataRoot,\n resumeCommandPrefix: \"kimi -r\",\n toolStrategy: \"custom\",\n create: () => new KimiAgent(),\n});\n\nregisterAgent({\n icon: \"/icon/agent/kimi.svg\",\n resolveDataRoot: resolveKimiCodeDataRoot,\n resumeCommandPrefix: \"kimi -r\",\n toolStrategy: \"custom\",\n create: () => new KimiCodeAgent(),\n});\n\nregisterAgent({\n icon: \"/icon/agent/codex.svg\",\n resolveDataRoot: resolveCodexDataRoot,\n resumeCommandPrefix: \"codex resume\",\n toolStrategy: \"custom\",\n create: () => new CodexAgent(),\n});\n\nregisterAgent({\n icon: \"/icon/agent/pi.svg\",\n resolveDataRoot: resolvePiDataRoot,\n resumeCommandPrefix: \"pi --session\",\n toolStrategy: \"custom\",\n create: () => new PiAgent(),\n});\n\nregisterAgent({\n icon: \"/icon/agent/cursor.svg\",\n resolveDataRoot: resolveCursorDataRoot,\n resumeCommandPrefix: null,\n toolStrategy: \"custom\",\n create: () => new CursorAgent(),\n});\n","import { availableParallelism } from \"node:os\";\nimport { Worker } from \"node:worker_threads\";\nimport type { SessionDetail, SessionHead, SmartTag } from \"../types/index.js\";\nimport { filterSessionTreeByActivityWindow } from \"../contract/session-tree.js\";\nimport type { BaseAgent, SessionCacheMeta } from \"../agents/index.js\";\nimport { createRegisteredAgents } from \"../agents/index.js\";\nimport { filterSessionsByProjectScope } from \"../projects/index.js\";\nimport { classifySessionTags, getSmartTagSourceTimestamp, perf } from \"../utils/index.js\";\nimport { getCoreDiagnostics } from \"../utils/diagnostics.js\";\nimport {\n loadCachedSessions,\n markAgentCacheInitialized,\n markAgentFullSyncCompleted,\n saveCachedSessionChanges,\n saveCachedSessions,\n type CachedResult,\n} from \"./cache/sessions.js\";\nimport {\n attachMissingProjectIdentities,\n buildAgentCacheMeta,\n computeSessionDiff,\n sessionSignature,\n} from \"./orchestrate.js\";\n\nexport interface ScanOptions {\n /** Filter to specific agent name(s) */\n agents?: string[];\n /** Filter to sessions from a specific project identity or directory scope */\n cwd?: string;\n /** Only include sessions active after this timestamp (ms) */\n from?: number;\n /** Only include sessions active before this timestamp (ms) */\n to?: number;\n /** Use cached scan results if available */\n useCache?: boolean;\n /** Enable smart refresh (fast cache + background incremental scan) */\n smartRefresh?: boolean;\n /** Return cached session heads without validating the filesystem */\n cacheOnly?: boolean;\n /** Persist scan results to the SQLite cache */\n writeCache?: boolean;\n /** Classify sessions by reading full conversation content */\n includeSmartTags?: boolean;\n /** Prefer lightweight metadata over complete statistics when the UI needs a fast first paint */\n fast?: boolean;\n /** URL to the compiled smart-tag worker file; omit to use synchronous fallback */\n smartTagWorkerUrl?: URL | string;\n}\n\nexport interface LiveSnapshot {\n sessions: SessionHead[];\n byAgent: Record<string, SessionHead[]>;\n agents: BaseAgent[];\n timings?: Record<string, AgentScanTiming>;\n cacheTimestamps?: Record<string, number>;\n}\n\n/** 扫描状态更新回调 */\nexport interface ScanProgress {\n agent: string;\n phase: \"cache\" | \"checking\" | \"incremental\" | \"complete\";\n cachedCount?: number;\n newCount?: number;\n changedCount?: number;\n}\n\nexport function filterSessions(sessions: SessionHead[], options: ScanOptions): SessionHead[] {\n let result = sessions;\n\n if (options.cwd) {\n result = filterSessionsByProjectScope(result, options.cwd);\n }\n\n return filterSessionTreeByActivityWindow(result, options.from, options.to);\n}\n\nexport interface AgentScanTiming {\n cacheLoad?: number;\n checkChanges?: number;\n scan?: number;\n identity?: number;\n tags?: number;\n total: number;\n}\n\nexport interface SessionTagTiming {\n sessions: number;\n cacheHits: number;\n staleSessions: number;\n failedSessions: number;\n getSessionDataCalls: number;\n getSessionDataMs: number;\n classifySessionTagsCalls: number;\n classifySessionTagsMs: number;\n}\n\ninterface AgentScanResult {\n agent: BaseAgent;\n heads: SessionHead[];\n fromCache?: boolean;\n refreshed?: boolean;\n timing?: AgentScanTiming;\n cacheTimestamp?: number;\n}\n\ntype AgentScanFinalization =\n | { kind: \"cache-only\"; cached: CachedResult }\n | { kind: \"unchanged\"; cached: CachedResult }\n | {\n kind: \"incremental\";\n cached: CachedResult;\n changedIds: string[];\n cacheTimestamp: number;\n };\n\ninterface FinalizeAgentScanContext {\n finalization: AgentScanFinalization;\n options: ScanOptions;\n timing: AgentScanTiming;\n agentStart: number;\n onProgress?: (progress: ScanProgress) => void;\n}\n\ninterface SmartTagWorkerResult {\n id: string;\n tags?: SmartTag[];\n sourceUpdatedAt?: number;\n error?: string;\n}\n\nfunction saveCachedSessionDiff(\n agent: BaseAgent,\n cachedSessions: SessionHead[],\n updatedSessions: SessionHead[],\n changedIds: string[] = [],\n): void {\n const diff = computeSessionDiff(cachedSessions, updatedSessions, changedIds, sessionSignature);\n saveCachedSessionChanges(\n agent.name,\n diff.changes,\n diff.removedSessionIds,\n buildAgentCacheMeta(agent),\n );\n}\n\nfunction getSmartTagWorkerCount(sessionCount: number): number {\n if (sessionCount < 50) return 1;\n return Math.min(sessionCount, Math.max(1, Math.min(4, availableParallelism() - 1)));\n}\n\nfunction chunkSessions<T>(items: T[], chunkCount: number): T[][] {\n const chunks = Array.from({ length: chunkCount }, () => [] as T[]);\n items.forEach((item, index) => {\n chunks[index % chunkCount]!.push(item);\n });\n return chunks.filter((chunk) => chunk.length > 0);\n}\n\nexport function ensureSessionTagsSync(\n agent: BaseAgent,\n sessions: SessionHead[],\n onProgress?: (processed: number, total: number) => void,\n): { sessions: SessionHead[]; changed: boolean; timing: SessionTagTiming } {\n let changed = false;\n let processed = 0;\n const total = sessions.length;\n const timing: SessionTagTiming = {\n sessions: total,\n cacheHits: 0,\n staleSessions: 0,\n failedSessions: 0,\n getSessionDataCalls: 0,\n getSessionDataMs: 0,\n classifySessionTagsCalls: 0,\n classifySessionTagsMs: 0,\n };\n\n const tagged = sessions.map((session) => {\n const sourceUpdatedAt = session.time_updated ?? session.time_created;\n const currentTags = Array.isArray(session.smart_tags) ? session.smart_tags : null;\n if (currentTags && session.smart_tags_source_updated_at === sourceUpdatedAt) {\n timing.cacheHits += 1;\n processed += 1;\n onProgress?.(processed, total);\n return session;\n }\n\n timing.staleSessions += 1;\n try {\n timing.getSessionDataCalls += 1;\n const getSessionDataStartedAt = performance.now();\n let data: SessionDetail;\n try {\n data = agent.getSessionData(session.id);\n } finally {\n timing.getSessionDataMs += performance.now() - getSessionDataStartedAt;\n }\n\n timing.classifySessionTagsCalls += 1;\n const classifySessionTagsStartedAt = performance.now();\n let tags: SmartTag[];\n try {\n tags = classifySessionTags(data);\n } finally {\n timing.classifySessionTagsMs += performance.now() - classifySessionTagsStartedAt;\n }\n\n changed = true;\n return {\n ...session,\n smart_tags: tags,\n smart_tags_source_updated_at: getSmartTagSourceTimestamp(data),\n };\n } catch {\n timing.failedSessions += 1;\n return session;\n } finally {\n processed += 1;\n onProgress?.(processed, total);\n }\n });\n\n return { sessions: tagged, changed, timing };\n}\n\nasync function classifySessionTagsInWorker(\n workerUrl: URL | string,\n agentName: string,\n sessionIds: string[],\n meta: Record<string, SessionCacheMeta>,\n): Promise<SmartTagWorkerResult[]> {\n return new Promise((resolveWorker, rejectWorker) => {\n const worker = new Worker(workerUrl, {\n workerData: { agentName, sessionIds, meta },\n });\n worker.once(\"message\", (results: SmartTagWorkerResult[]) => resolveWorker(results));\n worker.once(\"error\", rejectWorker);\n worker.once(\"exit\", (code) => {\n if (code !== 0) {\n rejectWorker(new Error(`Smart tag worker exited with code ${code}`));\n }\n });\n });\n}\n\nasync function ensureSessionTags(\n agent: BaseAgent,\n sessions: SessionHead[],\n workerUrl?: URL | string,\n): Promise<{ sessions: SessionHead[]; changed: boolean }> {\n const staleSessions = sessions.filter((session) => {\n const sourceUpdatedAt = session.time_updated ?? session.time_created;\n const currentTags = Array.isArray(session.smart_tags) ? session.smart_tags : null;\n return !currentTags || session.smart_tags_source_updated_at !== sourceUpdatedAt;\n });\n\n if (staleSessions.length === 0) {\n return { sessions, changed: false };\n }\n\n const workerCount = workerUrl ? getSmartTagWorkerCount(staleSessions.length) : 1;\n if (workerCount <= 1) {\n return ensureSessionTagsSync(agent, sessions);\n }\n\n const meta = buildAgentCacheMeta(agent);\n try {\n const results = (\n await Promise.all(\n chunkSessions(\n staleSessions.map((session) => session.id),\n workerCount,\n ).map((sessionIds) =>\n classifySessionTagsInWorker(workerUrl!, agent.name, sessionIds, meta),\n ),\n )\n ).flat();\n const resultMap = new Map(results.filter((item) => item.tags).map((item) => [item.id, item]));\n\n return {\n changed: resultMap.size > 0,\n sessions: sessions.map((session) => {\n const result = resultMap.get(session.id);\n if (!result?.tags || result.sourceUpdatedAt == null) return session;\n return {\n ...session,\n smart_tags: result.tags,\n smart_tags_source_updated_at: result.sourceUpdatedAt,\n };\n }),\n };\n } catch {\n return ensureSessionTagsSync(agent, sessions);\n }\n}\n\nexport async function finalizeAgentScan(\n agent: BaseAgent,\n sessions: SessionHead[],\n context: FinalizeAgentScanContext,\n): Promise<AgentScanResult> {\n const { finalization, options, timing, agentStart, onProgress } = context;\n const isIncremental = finalization.kind === \"incremental\";\n\n if (!isIncremental) {\n onProgress?.({ agent: agent.name, phase: \"complete\", newCount: sessions.length });\n }\n\n const identityStart = performance.now();\n const sessionsWithIdentity = attachMissingProjectIdentities(sessions);\n timing.identity = performance.now() - identityStart;\n\n let tagged = { sessions: sessionsWithIdentity, changed: false };\n if (finalization.kind !== \"cache-only\") {\n const tagsStart = performance.now();\n tagged =\n options.includeSmartTags === false\n ? tagged\n : await ensureSessionTags(agent, sessionsWithIdentity, options.smartTagWorkerUrl);\n timing.tags = performance.now() - tagsStart;\n }\n\n if (options.writeCache !== false) {\n if (finalization.kind === \"incremental\") {\n saveCachedSessionDiff(\n agent,\n finalization.cached.sessions,\n tagged.sessions,\n finalization.changedIds,\n );\n } else if (finalization.kind === \"unchanged\" && tagged.changed) {\n saveCachedSessionDiff(agent, finalization.cached.sessions, tagged.sessions);\n }\n }\n\n if (isIncremental) {\n onProgress?.({ agent: agent.name, phase: \"complete\", newCount: tagged.sessions.length });\n }\n\n const heads = filterSessions(tagged.sessions, options);\n timing.total = performance.now() - agentStart;\n return {\n agent,\n heads,\n fromCache: true,\n ...(isIncremental ? { refreshed: true } : {}),\n timing,\n cacheTimestamp: isIncremental ? finalization.cacheTimestamp : finalization.cached.timestamp,\n };\n}\n\n/**\n * 智能扫描单个 Agent\n * 1. 优先使用缓存立即返回\n * 2. 后台检测变更\n * 3. 增量刷新(仅更新变更的部分)\n */\nasync function scanAgentSmart(\n agent: BaseAgent,\n options: ScanOptions,\n onProgress?: (progress: ScanProgress) => void,\n): Promise<AgentScanResult | null> {\n const agentStart = performance.now();\n const timing: AgentScanTiming = { total: 0 };\n const useCache = options.useCache ?? true;\n\n // 1. 尝试加载缓存\n if (useCache) {\n const t0 = performance.now();\n const cached = loadCachedSessions(agent.name);\n timing.cacheLoad = performance.now() - t0;\n\n if (cached !== null) {\n // 恢复元数据\n const metaMap = new Map<string, SessionCacheMeta>();\n for (const [id, meta] of Object.entries(cached.meta)) {\n metaMap.set(id, meta);\n }\n agent.setSessionMetaMap(metaMap);\n\n if (options.cacheOnly) {\n const visibleSessions = agent.filterCachedSessions(cached.sessions);\n onProgress?.({\n agent: agent.name,\n phase: \"cache\",\n cachedCount: visibleSessions.length,\n });\n return finalizeAgentScan(agent, visibleSessions, {\n finalization: { kind: \"cache-only\", cached },\n options,\n timing,\n agentStart,\n onProgress,\n });\n }\n\n const isAvail = agent.isAvailable();\n if (!isAvail) {\n return null;\n }\n\n // 通知缓存已加载\n onProgress?.({\n agent: agent.name,\n phase: \"cache\",\n cachedCount: cached.sessions.length,\n });\n\n onProgress?.({ agent: agent.name, phase: \"checking\" });\n\n const t1 = performance.now();\n const checkResult = await Promise.resolve(\n agent.checkForChanges(cached.timestamp, cached.sessions),\n );\n timing.checkChanges = performance.now() - t1;\n\n if (checkResult.hasChanges) {\n onProgress?.({\n agent: agent.name,\n phase: \"incremental\",\n changedCount: checkResult.changedIds?.length,\n });\n\n const t2 = performance.now();\n const updatedSessions = await Promise.resolve(\n agent.incrementalScan(cached.sessions, checkResult.changedIds || [], checkResult.refs),\n );\n timing.scan = performance.now() - t2;\n\n return finalizeAgentScan(agent, updatedSessions, {\n finalization: {\n kind: \"incremental\",\n cached,\n changedIds: checkResult.changedIds ?? [],\n cacheTimestamp: checkResult.timestamp,\n },\n options,\n timing,\n agentStart,\n onProgress,\n });\n }\n\n return finalizeAgentScan(agent, cached.sessions, {\n finalization: { kind: \"unchanged\", cached },\n options,\n timing,\n agentStart,\n onProgress,\n });\n }\n }\n\n if (options.cacheOnly) {\n timing.total = performance.now() - agentStart;\n return null;\n }\n\n // 无缓存或缓存失效,执行完整扫描\n return scanAgentFull(agent, options, onProgress, timing, agentStart);\n}\n\n/**\n * 完整扫描 Agent(无缓存时使用)\n */\nasync function scanAgentFull(\n agent: BaseAgent,\n options: ScanOptions,\n onProgress?: (progress: ScanProgress) => void,\n timing: AgentScanTiming = { total: 0 },\n agentStart = performance.now(),\n): Promise<AgentScanResult | null> {\n const availMarker = perf.start(`agent:${agent.name}:isAvailable`);\n const isAvail = agent.isAvailable();\n perf.end(availMarker);\n\n if (!isAvail) {\n return null;\n }\n\n try {\n const scanMarker = perf.start(`agent:${agent.name}:scan`);\n const t0 = performance.now();\n const heads = agent.scan({\n from: options.from,\n to: options.to,\n fast: options.fast,\n includeRelatedSessions: true,\n onProgress: (progress) => {\n onProgress?.({\n agent: agent.name,\n phase: \"incremental\",\n cachedCount: progress.total,\n newCount: progress.sessions,\n changedCount: progress.processed,\n });\n },\n });\n perf.end(scanMarker);\n timing.scan = performance.now() - t0;\n\n const t1 = performance.now();\n const headsWithIdentity = attachMissingProjectIdentities(heads);\n timing.identity = performance.now() - t1;\n\n const t2 = performance.now();\n const tagged =\n options.includeSmartTags === false\n ? { sessions: headsWithIdentity, changed: false }\n : await ensureSessionTags(agent, headsWithIdentity, options.smartTagWorkerUrl);\n timing.tags = performance.now() - t2;\n\n // 收集元数据\n const meta = buildAgentCacheMeta(agent);\n\n if (options.writeCache !== false) {\n // 全量(无时间窗)扫描才落盘完整会话列表并记录一次全量同步,用于 backfill 节流判断\n const isFullWindow = options.from == null && options.to == null;\n // 落盘失败时不得标记缓存已建立,否则后续刷新会基于不存在的缓存走增量路径\n const persisted = isFullWindow ? saveCachedSessions(agent.name, tagged.sessions, meta) : true;\n if (persisted) {\n if (isFullWindow) markAgentFullSyncCompleted(agent.name);\n // head 缓存是否建立与搜索索引是否完整是两回事,带时间窗的扫描同样应当标记\n markAgentCacheInitialized(agent.name);\n } else {\n getCoreDiagnostics()?.warn(\"cache.save_failed\", {\n agent: agent.name,\n sessions: tagged.sessions.length,\n });\n }\n }\n\n onProgress?.({ agent: agent.name, phase: \"complete\", newCount: tagged.sessions.length });\n\n const filtered = filterSessions(tagged.sessions, options);\n timing.total = performance.now() - agentStart;\n return { agent, heads: filtered, fromCache: false, timing };\n } catch (err) {\n console.error(`Error scanning ${agent.name}:`, err);\n return { agent, heads: [], fromCache: false };\n }\n}\n\n/**\n * 主扫描函数 - 并行扫描所有 Agent\n */\nexport async function scanSessions(\n options: ScanOptions = {},\n onProgress?: (progress: ScanProgress) => void,\n): Promise<LiveSnapshot> {\n const scanMarker = perf.start(\"scanSessions\");\n const agents = createRegisteredAgents();\n const byAgent: Record<string, SessionHead[]> = {};\n const allSessions: SessionHead[] = [];\n const availableAgents: BaseAgent[] = [];\n const cacheTimestamps: Record<string, number> = {};\n\n const agentFilter = options.agents?.length\n ? new Set(options.agents.map((a) => a.toLowerCase()))\n : null;\n\n // 过滤需要扫描的 Agent\n const agentsToScan = agents.filter((agent) => {\n if (agentFilter && !agentFilter.has(agent.name.toLowerCase())) {\n return false;\n }\n return true;\n });\n\n // 并行扫描所有 Agent\n const scanPromises = agentsToScan.map((agent) => scanAgentSmart(agent, options, onProgress));\n\n const results = await Promise.all(scanPromises);\n\n // 处理结果\n const timings: Record<string, AgentScanTiming> = {};\n for (const result of results) {\n if (result) {\n availableAgents.push(result.agent);\n byAgent[result.agent.name] = result.heads;\n allSessions.push(...result.heads);\n if (result.timing) {\n timings[result.agent.name] = result.timing;\n }\n if (result.cacheTimestamp != null) {\n cacheTimestamps[result.agent.name] = result.cacheTimestamp;\n }\n }\n }\n\n perf.end(scanMarker);\n return {\n sessions: allSessions,\n byAgent,\n agents: availableAgents,\n timings,\n cacheTimestamps: Object.keys(cacheTimestamps).length > 0 ? cacheTimestamps : undefined,\n };\n}\n","export function fallbackDisplayName(input: string): string {\n if (input === \"/\") return \"(root)\";\n const trimmed = input.replace(/[/\\\\]+$/, \"\");\n const parts = trimmed.split(/[/\\\\]+/).filter(Boolean);\n return parts.at(-1) ?? trimmed;\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { spawnSync } from \"node:child_process\";\nimport type { IdentityFs } from \"./identity.js\";\n\nexport const realFs: IdentityFs = {\n exists(path) {\n return existsSync(path);\n },\n readText(path) {\n try {\n return readFileSync(path, \"utf8\");\n } catch {\n return null;\n }\n },\n spawn(cmd, args, opts) {\n const result = spawnSync(cmd, args, { cwd: opts.cwd, encoding: \"utf8\", timeout: 1000 });\n return {\n stdout: typeof result.stdout === \"string\" ? result.stdout : \"\",\n exitCode: result.status ?? 1,\n };\n },\n};\n","import * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { ProjectIdentity, ProjectIdentityKind } from \"../types/index.js\";\nimport { fallbackDisplayName } from \"./display-name.js\";\nimport { realFs } from \"./fs.js\";\n\nexport interface IdentityFs {\n exists(path: string): boolean;\n readText(path: string): string | null;\n spawn(cmd: string, args: string[], opts: { cwd: string }): { stdout: string; exitCode: number };\n}\n\nconst MANIFESTS = [\n \"package.json\",\n \"Cargo.toml\",\n \"pyproject.toml\",\n \"go.mod\",\n \"Gemfile\",\n \"pom.xml\",\n \"build.gradle\",\n] as const;\n\nconst PARSEABLE_MANIFESTS = [\"package.json\", \"Cargo.toml\", \"pyproject.toml\"] as const;\n\nconst LOOSE_DIRS = new Set([\"/tmp\", \"/private/tmp\"]);\nconst LOOSE_HOME_DIRS = [\"Desktop\", \"Downloads\", \"Documents\"];\ntype PathOps = Pick<\n typeof path.posix,\n \"dirname\" | \"isAbsolute\" | \"join\" | \"relative\" | \"resolve\" | \"sep\"\n>;\n\n// Identity semantics live in the contract; this module only discovers them\n// from the filesystem and git.\nexport {\n getProjectIdentityKey,\n isProjectIdentityKind,\n matchesProjectIdentity,\n} from \"../contract/project-identity.js\";\n\nexport function normalizeGitRemote(url: string): string | null {\n if (!url) return null;\n let value = url.trim().replace(/\\.git$/, \"\");\n const sshMatch = value.match(/^[^@]+@([^:]+):(.+)$/);\n if (sshMatch) value = `${sshMatch[1]}/${sshMatch[2]}`;\n value = value.replace(/^[a-z]+:\\/\\/(?:[^@/]*@)?/i, \"\");\n if (!value.includes(\"/\")) return null;\n return value.toLowerCase();\n}\n\n// Process-lifetime identity cache, keyed by directory. Only used for the real\n// filesystem (fs === realFs); tests inject fake IdentityFs implementations and\n// must bypass the cache to stay isolated from each other. git remotes change\n// rarely, so a coarse TTL is enough — no file-watch invalidation needed.\nconst IDENTITY_CACHE_TTL_MS = 10 * 60 * 1000;\n\ninterface IdentityCacheEntry {\n identity: ProjectIdentity;\n resolvedAt: number;\n}\n\nconst identityCache = new Map<string, IdentityCacheEntry>();\n\n/** Clears the process-lifetime identity cache. For tests and explicit invalidation. */\nexport function clearIdentityCache(): void {\n identityCache.clear();\n}\n\nexport function computeIdentity(cwd: string | null | undefined, fs: IdentityFs): ProjectIdentity {\n if (fs !== realFs) return resolveIdentity(cwd, fs);\n\n const key = cwd ?? \"\";\n const cached = identityCache.get(key);\n if (cached && Date.now() - cached.resolvedAt < IDENTITY_CACHE_TTL_MS) {\n return cached.identity;\n }\n const identity = resolveIdentity(cwd, fs);\n identityCache.set(key, { identity, resolvedAt: Date.now() });\n return identity;\n}\n\nfunction resolveIdentity(cwd: string | null | undefined, fs: IdentityFs): ProjectIdentity {\n if (!cwd) return loose();\n\n const pathOps = getPathOps(cwd);\n const absoluteCwd = pathOps.resolve(cwd);\n const homeDir = os.homedir();\n const homePathOps = getPathOps(homeDir);\n const home = homePathOps === pathOps ? pathOps.resolve(homeDir) : homeDir;\n if (absoluteCwd === home || LOOSE_DIRS.has(absoluteCwd)) return loose();\n if (\n homePathOps === pathOps &&\n LOOSE_HOME_DIRS.some((dir) => absoluteCwd === pathOps.join(home, dir))\n ) {\n return loose();\n }\n\n const gitRoot = findGitRoot(absoluteCwd, fs, pathOps);\n if (gitRoot) {\n const remote = fs.spawn(\"git\", [\"config\", \"--get\", \"remote.origin.url\"], { cwd: gitRoot });\n if (remote.exitCode === 0) {\n const normalized = normalizeGitRemote(remote.stdout.trim());\n if (normalized) {\n return {\n kind: \"git_remote\",\n key: normalized,\n displayName: deriveDisplayName({ kind: \"git_remote\", key: normalized, gitRoot, fs }),\n };\n }\n }\n\n const common = fs.spawn(\"git\", [\"rev-parse\", \"--git-common-dir\"], { cwd: gitRoot });\n if (common.exitCode === 0) {\n const raw = common.stdout.trim();\n if (raw) {\n const key = pathOps.isAbsolute(raw) ? raw : pathOps.resolve(gitRoot, raw);\n return {\n kind: \"git_common_dir\",\n key,\n displayName: deriveDisplayName({ kind: \"git_common_dir\", key, gitRoot, fs }),\n };\n }\n }\n }\n\n const manifestDir = findManifestDir(absoluteCwd, fs, pathOps);\n if (manifestDir) {\n return {\n kind: \"manifest_path\",\n key: manifestDir,\n displayName: deriveDisplayName({ kind: \"manifest_path\", key: manifestDir, fs }),\n };\n }\n\n if (homePathOps === pathOps) {\n const synthetic = synthesizeCodexScratchIdentity(absoluteCwd, home, pathOps);\n if (synthetic) return synthetic;\n }\n\n return {\n kind: \"path\",\n key: absoluteCwd,\n displayName: fallbackDisplayName(absoluteCwd),\n };\n}\n\nfunction loose(): ProjectIdentity {\n return { kind: \"loose\", key: \"loose\", displayName: \"Loose\" };\n}\n\nfunction synthesizeCodexScratchIdentity(\n absoluteCwd: string,\n home: string,\n pathOps: PathOps,\n): ProjectIdentity | null {\n const root = pathOps.resolve(pathOps.join(home, \"Documents\", \"Codex\"));\n const child = pathOps.relative(root, absoluteCwd);\n if (\n !child ||\n child === \"..\" ||\n child.startsWith(`..${pathOps.sep}`) ||\n pathOps.isAbsolute(child)\n ) {\n return null;\n }\n return { kind: \"synthetic\", key: \"codex:scratch\", displayName: \"Chats\" };\n}\n\nfunction getPathOps(input: string): PathOps {\n if (/^[a-zA-Z]:[\\\\/]/.test(input) || input.startsWith(\"\\\\\\\\\") || input.includes(\"\\\\\")) {\n return path.win32;\n }\n if (input.startsWith(\"/\")) return path.posix;\n return path;\n}\n\nfunction findGitRoot(start: string, fs: IdentityFs, pathOps: PathOps): string | null {\n let current = start;\n while (current) {\n if (fs.exists(pathOps.join(current, \".git\"))) return current;\n const parent = pathOps.dirname(current);\n if (parent === current) break;\n current = parent;\n }\n return null;\n}\n\nfunction findManifestDir(start: string, fs: IdentityFs, pathOps: PathOps): string | null {\n let current = start;\n while (current) {\n for (const manifest of MANIFESTS) {\n if (fs.exists(pathOps.join(current, manifest))) return current;\n }\n const parent = pathOps.dirname(current);\n if (parent === current) break;\n current = parent;\n }\n return null;\n}\n\ninterface DisplayNameInput {\n kind: ProjectIdentityKind;\n key: string;\n gitRoot?: string;\n fs: IdentityFs;\n}\n\nfunction deriveDisplayName(input: DisplayNameInput): string {\n const pathOps = getPathOps(input.gitRoot ?? input.key);\n const dir = input.gitRoot ?? (input.kind === \"manifest_path\" ? input.key : null);\n if (dir) {\n for (const manifest of PARSEABLE_MANIFESTS) {\n const manifestPath = pathOps.join(dir, manifest);\n if (input.fs.exists(manifestPath)) {\n const name = parseManifestName(manifest, input.fs.readText(manifestPath) ?? \"\");\n if (name) return name;\n }\n }\n }\n\n if (input.kind === \"git_remote\") {\n return input.key.split(\"/\").at(-1) || input.key;\n }\n if (input.gitRoot) return fallbackDisplayName(input.gitRoot);\n return fallbackDisplayName(input.key);\n}\n\nfunction parseManifestName(file: string, text: string): string | null {\n if (!text) return null;\n if (file === \"package.json\" || file === \"Cargo.toml\" || file === \"pyproject.toml\") {\n const match = text.match(/\"name\"\\s*:\\s*\"([^\"]+)\"/) || text.match(/^\\s*name\\s*=\\s*\"([^\"]+)\"/m);\n if (match?.[1]) return match[1];\n }\n return null;\n}\n","import type { ProjectGroup, ProjectIdentity, SessionHead } from \"../types/index.js\";\nimport { getSessionAgentKey, isChildSession } from \"../contract/index.js\";\nimport { getProjectIdentityKey } from \"./identity.js\";\n\nexport function buildProjectGroups(sessions: SessionHead[]): ProjectGroup[] {\n const groups = new Map<\n string,\n { identity: ProjectIdentity; sources: Set<string>; sessionCount: number; lastActivity: number }\n >();\n\n for (const session of sessions) {\n if (isChildSession(session)) continue;\n const identity = session.project_identity;\n if (!identity) continue;\n const activity = session.time_updated ?? session.time_created;\n const groupKey = getProjectIdentityKey(identity);\n const current = groups.get(groupKey);\n if (current) {\n current.sources.add(getSessionAgentKey(session));\n current.sessionCount += 1;\n current.lastActivity = Math.max(current.lastActivity, activity);\n } else {\n groups.set(groupKey, {\n identity,\n sources: new Set([getSessionAgentKey(session)]),\n sessionCount: 1,\n lastActivity: activity,\n });\n }\n }\n\n return [...groups.values()]\n .map((group) => ({\n identityKind: group.identity.kind,\n identityKey: group.identity.key,\n displayName: group.identity.displayName,\n sources: [...group.sources].sort(),\n sessionCount: group.sessionCount,\n lastActivity: group.lastActivity || null,\n }))\n .sort((a, b) => {\n if (a.identityKind === \"loose\" && b.identityKind !== \"loose\") return 1;\n if (b.identityKind === \"loose\" && a.identityKind !== \"loose\") return -1;\n return (b.lastActivity ?? 0) - (a.lastActivity ?? 0);\n });\n}\n","import { resolve, sep } from \"node:path\";\nimport type { ProjectIdentityRef, SessionHead } from \"../types/index.js\";\nimport { computeIdentity, matchesProjectIdentity, type IdentityFs } from \"./identity.js\";\nimport { realFs } from \"./fs.js\";\n\nexport interface ProjectScopeMatcher {\n identity: ProjectIdentityRef;\n path: string;\n}\n\nexport function createProjectScopeMatcher(\n queryPath: string,\n fs: IdentityFs = realFs,\n): ProjectScopeMatcher {\n const identity = computeIdentity(queryPath, fs);\n return {\n identity: { kind: identity.kind, key: identity.key },\n path: normalizeScopePath(queryPath),\n };\n}\n\nexport function matchesProjectScope(session: SessionHead, scope: ProjectScopeMatcher): boolean {\n if (!session.directory) return false;\n if (matchesProjectIdentity(session.project_identity, scope.identity)) return true;\n return isPathScopeMatch(scope.path, session.directory);\n}\n\nexport function filterSessionsByProjectScope(\n sessions: SessionHead[],\n queryPath: string,\n fs?: IdentityFs,\n): SessionHead[] {\n const scope = createProjectScopeMatcher(queryPath, fs);\n return sessions.filter((session) => matchesProjectScope(session, scope));\n}\n\nfunction isPathScopeMatch(queryPath: string, sessionPath: string): boolean {\n const session = normalizeScopePath(sessionPath);\n return (\n session === queryPath ||\n session.startsWith(queryPath + \"/\") ||\n queryPath.startsWith(session + \"/\")\n );\n}\n\nfunction normalizeScopePath(path: string): string {\n return resolve(path).replaceAll(sep, \"/\");\n}\n","import type { MessagePart, SessionDetail, SmartTag, ToolPart } from \"../types/index.js\";\n\nconst TAG_ORDER: SmartTag[] = [\n \"bugfix\",\n \"refactoring\",\n \"feature-dev\",\n \"testing\",\n \"docs\",\n \"git-ops\",\n \"build-deploy\",\n \"exploration\",\n \"planning\",\n];\n\nconst USER_RULES: Array<[SmartTag, RegExp]> = [\n [\"bugfix\", /\\b(fix|bug|error|crash|exception|fail(?:ed|ure)?)\\b|修复|错误|报错|崩溃|异常/i],\n [\"refactoring\", /\\b(refactor|rename|simplify|clean up|cleanup)\\b|重构|重命名|简化|清理/i],\n [\"feature-dev\", /\\b(add|create|implement|new|support|build)\\b|新增|创建|实现|增加|开发|支持/i],\n [\"docs\", /\\b(document|documentation|readme|docs?)\\b|文档|说明/i],\n];\n\nconst TESTING_COMMAND_RE = /\\b(pytest|vitest|jest|mocha|pnpm\\s+test|npm\\s+test|yarn\\s+test)\\b/i;\nconst GIT_COMMAND_RE = /\\bgit\\s+(push|commit|merge|branch|checkout|switch|rebase|tag)\\b/i;\nconst BUILD_DEPLOY_COMMAND_RE =\n /\\b((npm|pnpm|yarn|bun)\\s+(run\\s+)?build|docker|pm2|deploy|vercel|netlify)\\b/i;\nconst DOC_PATH_RE = /\\.(md|mdx|txt|rst|adoc)$/i;\nconst READ_TOOL_RE = /\\b(read|grep|glob|websearch|web_search|search|find|rg)\\b/i;\nconst EDIT_TOOL_RE = /\\b(edit|write|apply_patch|patch|multiedit|notebookedit)\\b/i;\nconst PLAN_TOOL_RE = /\\b(enterplanmode|taskcreate|update_plan|plan)\\b/i;\n\nexport function getSmartTagSourceTimestamp(\n session: Pick<SessionDetail, \"time_created\" | \"time_updated\">,\n): number {\n return session.time_updated ?? session.time_created;\n}\n\nexport function classifySessionTags(session: Pick<SessionDetail, \"messages\">): SmartTag[] {\n const tags = new Set<SmartTag>();\n let readToolCount = 0;\n let editToolCount = 0;\n\n for (const message of session.messages) {\n if (message.role === \"user\") {\n const text = message.parts.map(partText).join(\"\\n\");\n for (const [tag, pattern] of USER_RULES) {\n if (pattern.test(text)) tags.add(tag);\n }\n }\n\n for (const part of message.parts) {\n if (part.type === \"plan\") tags.add(\"planning\");\n if (part.type !== \"tool\") continue;\n\n const toolName = `${part.tool} ${part.title ?? \"\"}`;\n const toolPayload = stringifyToolPayload(part);\n\n if (PLAN_TOOL_RE.test(toolName)) tags.add(\"planning\");\n if (READ_TOOL_RE.test(toolName)) readToolCount += 1;\n if (EDIT_TOOL_RE.test(toolName)) editToolCount += 1;\n\n if (TESTING_COMMAND_RE.test(toolPayload)) tags.add(\"testing\");\n if (GIT_COMMAND_RE.test(toolPayload)) tags.add(\"git-ops\");\n if (BUILD_DEPLOY_COMMAND_RE.test(toolPayload)) tags.add(\"build-deploy\");\n if (hasEditedDocPath(part.state.input)) {\n tags.add(\"docs\");\n }\n }\n }\n\n if (readToolCount >= 3 && editToolCount <= 1) {\n tags.add(\"exploration\");\n }\n\n return TAG_ORDER.filter((tag) => tags.has(tag));\n}\n\nfunction partText(part: MessagePart): string {\n return part.type === \"text\" || part.type === \"reasoning\" || part.type === \"plan\" ? part.text : \"\";\n}\n\nfunction stringifyToolPayload(part: ToolPart): string {\n return [part.tool, part.title, valueToText(part.state)].filter(Boolean).join(\"\\n\");\n}\n\nfunction valueToText(value: unknown): string {\n if (value == null) return \"\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n try {\n return JSON.stringify(value);\n } catch {\n return \"\";\n }\n}\n\nfunction hasEditedDocPath(value: unknown): boolean {\n if (value == null) return false;\n if (typeof value === \"string\") return DOC_PATH_RE.test(value);\n if (Array.isArray(value)) return value.some(hasEditedDocPath);\n if (typeof value !== \"object\") return false;\n\n const record = value as Record<string, unknown>;\n for (const key of [\"path\", \"file\", \"filePath\", \"file_path\", \"targetPath\", \"target_path\"]) {\n const raw = record[key];\n if (typeof raw === \"string\" && DOC_PATH_RE.test(raw)) return true;\n }\n\n return Object.values(record).some(hasEditedDocPath);\n}\n","import type {\n FileActivityKind,\n Message,\n SessionFileActivity,\n SessionFileActivityOccurrence,\n ToolPart,\n} from \"../types/index.js\";\n\ninterface CodexPatchEntry {\n type: string;\n path: string;\n oldPath: string;\n}\n\nfunction toRecord(value: unknown) {\n if (value && typeof value === \"object\" && !Array.isArray(value)) {\n return value as Record<string, unknown>;\n }\n return {};\n}\n\nfunction toStringValue(value: unknown) {\n return typeof value === \"string\" ? value : \"\";\n}\n\nfunction normalizeToolLabel(part: ToolPart) {\n if (part.title?.trim()) {\n return part.title.trim().replace(/^tool:\\s*/i, \"\");\n }\n if (part.tool.trim()) return part.tool.trim();\n return \"tool\";\n}\n\nfunction normalizeToolName(part: ToolPart) {\n return normalizeToolLabel(part).trim().toLowerCase();\n}\n\nfunction looksLikeFilePath(value: string) {\n const text = value.trim();\n if (!text || text.length > 300) return false;\n if (text.includes(\"\\n\")) return false;\n if (/^[a-z]+:\\/\\//i.test(text)) return false;\n if (/[<>{}]/.test(text)) return false;\n if (text.startsWith(\"/\")) return true;\n if (text.startsWith(\"./\") || text.startsWith(\"../\") || text.startsWith(\"~/\")) return true;\n if (text.includes(\"/\") || text.includes(\"\\\\\")) return true;\n return /^[A-Za-z0-9_.@-]+\\.[A-Za-z0-9_-]+$/.test(text);\n}\n\nfunction shouldTreatAsPathKey(key: string) {\n const normalized = key.trim().toLowerCase();\n if (!normalized) return false;\n if (\n normalized.includes(\"command\") ||\n normalized.includes(\"content\") ||\n normalized.includes(\"text\") ||\n normalized.includes(\"prompt\") ||\n normalized.includes(\"url\") ||\n normalized.includes(\"body\") ||\n normalized.includes(\"title\") ||\n normalized.includes(\"description\") ||\n normalized === \"cwd\" ||\n normalized === \"workdir\" ||\n normalized === \"directory\"\n ) {\n return false;\n }\n return (\n normalized === \"path\" ||\n normalized === \"paths\" ||\n normalized.includes(\"file\") ||\n normalized.includes(\"path\")\n );\n}\n\nfunction collectPathsFromValue(\n value: unknown,\n keyHint: string,\n paths: Set<string>,\n depth = 0,\n): void {\n if (value == null || depth > 4) return;\n\n if (typeof value === \"string\") {\n if (shouldTreatAsPathKey(keyHint) && looksLikeFilePath(value)) {\n paths.add(value.trim());\n }\n return;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n collectPathsFromValue(item, keyHint, paths, depth + 1);\n }\n return;\n }\n\n if (typeof value === \"object\") {\n for (const [key, nested] of Object.entries(value as Record<string, unknown>)) {\n collectPathsFromValue(nested, key, paths, depth + 1);\n }\n }\n}\n\nfunction extractPathsFromToolInput(inputValue: unknown) {\n const paths = new Set<string>();\n collectPathsFromValue(inputValue, \"\", paths);\n return [...paths];\n}\n\nfunction getToolInputValue(part: ToolPart) {\n return part.state.input ?? null;\n}\n\nfunction classifyToolKind(part: ToolPart): FileActivityKind | null {\n const toolName = normalizeToolName(part);\n if (toolName === \"read\" || toolName === \"readfile\" || toolName === \"read_file\") return \"read\";\n if (\n toolName === \"edit\" ||\n toolName === \"multiedit\" ||\n toolName === \"apply_patch\" ||\n toolName === \"notebookedit\"\n ) {\n return \"edit\";\n }\n if (\n toolName === \"write\" ||\n toolName === \"writefile\" ||\n toolName === \"write_file\" ||\n toolName === \"create_file\"\n ) {\n return \"write\";\n }\n if (toolName === \"delete\" || toolName === \"delete_file\") {\n return \"delete\";\n }\n return null;\n}\n\nfunction normalizeCodexPatchEntry(entry: unknown): CodexPatchEntry | null {\n const record = toRecord(entry);\n const type = toStringValue(record.type);\n if (!type) return null;\n return {\n type,\n path: toStringValue(record.path),\n oldPath: toStringValue(record.old_path),\n };\n}\n\nfunction getCodexPatchEntries(inputValue: unknown): CodexPatchEntry[] {\n const input = toRecord(inputValue);\n const rawContent: unknown[] = Array.isArray(inputValue)\n ? inputValue\n : Array.isArray(input.content)\n ? (input.content as unknown[])\n : [];\n\n return rawContent\n .map((entry) => normalizeCodexPatchEntry(entry))\n .filter((entry): entry is CodexPatchEntry => entry != null);\n}\n\nfunction patchEntryKind(type: string): FileActivityKind {\n if (type === \"write_file\") return \"write\";\n if (type === \"delete_file\") return \"delete\";\n return \"edit\";\n}\n\nexport function extractFileActivityOccurrences(\n messages: Message[],\n): SessionFileActivityOccurrence[] {\n const occurrences: SessionFileActivityOccurrence[] = [];\n\n messages.forEach((message, messageIndex) => {\n let toolIndex = 0;\n\n for (const part of message.parts) {\n if (part.type !== \"tool\") continue;\n\n const inputValue = getToolInputValue(part);\n const toolLabel = normalizeToolLabel(part);\n const time = part.time_created ?? message.time_created;\n const currentToolIndex = toolIndex;\n toolIndex += 1;\n\n const patchEntries = getCodexPatchEntries(inputValue);\n if (patchEntries.length > 0) {\n for (const entry of patchEntries) {\n const path = (entry.path || entry.oldPath).trim();\n if (!path) continue;\n occurrences.push({\n path,\n kind: patchEntryKind(entry.type),\n time,\n tool_label: toolLabel,\n message_index: messageIndex,\n tool_index: currentToolIndex,\n });\n }\n continue;\n }\n\n const kind = classifyToolKind(part);\n if (!kind) continue;\n\n for (const path of extractPathsFromToolInput(inputValue)) {\n occurrences.push({\n path,\n kind,\n time,\n tool_label: toolLabel,\n message_index: messageIndex,\n tool_index: currentToolIndex,\n });\n }\n }\n });\n\n return occurrences;\n}\n\nexport function summarizeFileActivity(\n agentName: string,\n sessionId: string,\n projectIdentityKey: string,\n occurrences: SessionFileActivityOccurrence[],\n): SessionFileActivity[] {\n const grouped = new Map<string, SessionFileActivity>();\n\n for (const occurrence of occurrences) {\n const key = `${occurrence.kind}\\0${occurrence.path}`;\n const current = grouped.get(key);\n if (current) {\n current.count += 1;\n current.latestTime = Math.max(current.latestTime, occurrence.time);\n continue;\n }\n\n grouped.set(key, {\n reference: { agentName, sessionId },\n projectIdentityKey,\n path: occurrence.path,\n kind: occurrence.kind,\n count: 1,\n latestTime: occurrence.time,\n });\n }\n\n return [...grouped.values()].sort((a, b) => {\n if (b.latestTime !== a.latestTime) return b.latestTime - a.latestTime;\n return a.path.localeCompare(b.path);\n });\n}\n\nexport function extractSessionFileActivity(\n agentName: string,\n sessionId: string,\n projectIdentityKey: string,\n messages: Message[],\n): SessionFileActivity[] {\n return summarizeFileActivity(\n agentName,\n sessionId,\n projectIdentityKey,\n extractFileActivityOccurrences(messages),\n );\n}\n","/**\n * Cache persistence: load / save / clear / info / initialization tracking.\n */\nimport { existsSync, rmSync, unlinkSync } from \"node:fs\";\nimport type { SessionCacheMeta } from \"../../agents/base.js\";\nimport type { SessionDetail, SessionHead } from \"../../types/index.js\";\nimport { tableExists } from \"../../utils/sqlite.js\";\nimport {\n getCachePath,\n getLegacyCachePath,\n hasCacheStorage,\n setSchemaEnsuredPath,\n type ScalarRow,\n type SessionHeadChange,\n} from \"./db.js\";\nimport { withCacheDb, withCacheDbReadOnly } from \"./schema.js\";\nimport {\n messageFromCachedRow,\n prepareUpsertSession,\n sessionFromRow,\n sourcePathFromMeta,\n upsertSessionRow,\n type CachedMessageRow,\n type SessionRow,\n} from \"./messages.js\";\nimport { fileActivityFromRow, type FileActivityRow } from \"./file-activity.js\";\n\nexport const CACHE_INITIALIZATION_VERSION = \"session-cache-v2\";\nconst FULL_SYNC_CURSOR_PREFIX = \"full_sync_cursor:\";\nexport interface CachedResult {\n sessions: SessionHead[];\n meta: Record<string, SessionCacheMeta>;\n timestamp: number;\n}\n\nexport interface CachedSessionDataEntry {\n data: SessionDetail;\n meta: SessionCacheMeta | null;\n}\n\nexport interface CachedSessionRawEntry {\n data: Omit<SessionDetail, \"messages\">;\n messageRows: CachedMessageRow[];\n meta: SessionCacheMeta | null;\n}\n\nfunction parseCachedSessionMeta(value: string | null | undefined): SessionCacheMeta | null {\n if (!value) return null;\n try {\n return JSON.parse(value) as SessionCacheMeta;\n } catch {\n return null;\n }\n}\n\nexport function deleteLegacyCacheFile(): void {\n const legacyPath = getLegacyCachePath();\n if (!existsSync(legacyPath)) {\n return;\n }\n\n try {\n unlinkSync(legacyPath);\n } catch {\n // Ignore legacy cleanup errors\n }\n}\n\nexport function loadCachedSessions(agentName: string): CachedResult | null {\n if (!hasCacheStorage()) {\n return null;\n }\n\n return withCacheDb((db) => {\n const timestampRow = db\n .prepare(\"SELECT timestamp AS value FROM agent_cache WHERE agent_name = ?\")\n .get(agentName) as ScalarRow | undefined;\n const timestamp = Number(timestampRow?.value ?? 0);\n\n if (!timestamp) {\n return null;\n }\n\n const rows = db\n .prepare(\n `\n SELECT\n session_id,\n sort_index,\n slug,\n title,\n source_path,\n directory,\n parent_agent_name,\n parent_session_id,\n project_identity_kind,\n project_identity_key,\n project_display_name,\n time_created,\n time_updated,\n message_count,\n total_input_tokens,\n total_output_tokens,\n total_cache_read_tokens,\n total_cache_create_tokens,\n total_cost,\n cost_source,\n total_tokens,\n model_usage_json,\n smart_tags_json,\n smart_tags_source_updated_at,\n meta_json\n FROM sessions\n WHERE agent_name = ?\n ORDER BY sort_index, activity_time DESC\n `,\n )\n .all(agentName) as SessionRow[];\n\n const sessions: SessionHead[] = [];\n const meta: Record<string, SessionCacheMeta> = {};\n\n for (const row of rows) {\n const session = sessionFromRow(row);\n sessions.push(session);\n\n if (row.meta_json) {\n meta[session.id] = JSON.parse(row.meta_json) as SessionCacheMeta;\n }\n }\n\n return { sessions, meta, timestamp };\n });\n}\n\nexport function isAgentCacheInitialized(\n agentName: string,\n indexVersion = CACHE_INITIALIZATION_VERSION,\n): boolean {\n if (!hasCacheStorage()) {\n return false;\n }\n\n return (\n withCacheDbReadOnly((db) => {\n if (!tableExists(db, \"cache_initialization\")) return false;\n const row = db\n .prepare(\n `\n SELECT index_version\n FROM cache_initialization\n WHERE agent_name = ?\n `,\n )\n .get(agentName) as { index_version?: string } | undefined;\n return row?.index_version === indexVersion;\n }) ?? false\n );\n}\n\n/**\n * Marks the cache as warm/usable so refreshes can rely on incremental checks\n * instead of a raw full scan. This is deliberately independent of full-history\n * reconciliation: a first scan may be bounded to a display window, so\n * last_sync_at defaults to 0 (never synced) here and is only advanced by\n * markAgentFullSyncCompleted once a genuine unbounded pass completes.\n */\nexport function markAgentCacheInitialized(\n agentName: string,\n indexVersion = CACHE_INITIALIZATION_VERSION,\n): void {\n withCacheDb((db) => {\n db.prepare(\n `\n INSERT INTO cache_initialization(agent_name, initialized_at, index_version, last_sync_at)\n VALUES (?, ?, ?, 0)\n ON CONFLICT(agent_name) DO UPDATE SET\n index_version = excluded.index_version\n `,\n ).run(agentName, Date.now(), indexVersion);\n });\n}\n\n/** Mark a full-history reconciliation as incomplete until it commits. */\nexport function markAgentFullSyncStarted(agentName: string): void {\n withCacheDb((db) => {\n db.prepare(\n `\n UPDATE cache_initialization\n SET last_sync_at = 0\n WHERE agent_name = ?\n `,\n ).run(agentName);\n });\n}\n\n/** Return the last durable source position reached by an incomplete full sync. */\nexport function getAgentFullSyncCursor(agentName: string): string | null {\n if (!hasCacheStorage()) return null;\n\n return (\n withCacheDbReadOnly((db) => {\n const row = db\n .prepare(\"SELECT value FROM cache_meta WHERE key = ?\")\n .get(`${FULL_SYNC_CURSOR_PREFIX}${agentName}`) as { value?: string } | undefined;\n return row?.value || null;\n }) ?? null\n );\n}\n\n/** Persist a full-sync cursor only after the corresponding checkpoint is durable. */\nexport function markAgentFullSyncProgress(agentName: string, cursor: string): void {\n if (!cursor) return;\n\n withCacheDb((db) => {\n db.prepare(\n `\n INSERT INTO cache_meta(key, value)\n VALUES (?, ?)\n ON CONFLICT(key) DO UPDATE SET value = excluded.value\n `,\n ).run(`${FULL_SYNC_CURSOR_PREFIX}${agentName}`, cursor);\n });\n}\n\n/** Remove the cursor after the complete unbounded reconciliation commits. */\nfunction clearAgentFullSyncCursor(agentName: string): void {\n withCacheDb((db) => {\n db.prepare(\"DELETE FROM cache_meta WHERE key = ?\").run(\n `${FULL_SYNC_CURSOR_PREFIX}${agentName}`,\n );\n });\n}\n\n/** Timestamp of the agent's last full (unbounded) history reconciliation, or null if none yet. */\nexport function getAgentLastFullSyncAt(agentName: string): number | null {\n if (!hasCacheStorage()) {\n return null;\n }\n\n return (\n withCacheDbReadOnly((db) => {\n if (!tableExists(db, \"cache_initialization\")) return null;\n const row = db\n .prepare(\n `\n SELECT last_sync_at\n FROM cache_initialization\n WHERE agent_name = ?\n `,\n )\n .get(agentName) as { last_sync_at?: number } | undefined;\n return row?.last_sync_at || null;\n }) ?? null\n );\n}\n\n/** Record that a full (unbounded) history reconciliation just completed for this agent. */\nexport function markAgentFullSyncCompleted(agentName: string): void {\n withCacheDb((db) => {\n db.prepare(\n `\n UPDATE cache_initialization\n SET last_sync_at = ?\n WHERE agent_name = ?\n `,\n ).run(Date.now(), agentName);\n });\n clearAgentFullSyncCursor(agentName);\n}\n\nexport function loadCachedSessionRawEntry(\n agentName: string,\n sessionId: string,\n): CachedSessionRawEntry | null {\n if (!hasCacheStorage()) {\n return null;\n }\n\n return withCacheDbReadOnly((db) => {\n const row = db\n .prepare(\n `\n SELECT\n session_id,\n sort_index,\n slug,\n title,\n source_path,\n directory,\n parent_agent_name,\n parent_session_id,\n project_identity_kind,\n project_identity_key,\n project_display_name,\n time_created,\n time_updated,\n message_count,\n total_input_tokens,\n total_output_tokens,\n total_cache_read_tokens,\n total_cache_create_tokens,\n total_cost,\n cost_source,\n total_tokens,\n model_usage_json,\n smart_tags_json,\n smart_tags_source_updated_at,\n meta_json\n FROM sessions\n WHERE agent_name = ? AND session_id = ?\n `,\n )\n .get(agentName, sessionId) as SessionRow | undefined;\n\n if (!row) {\n return null;\n }\n\n // A pending_reindex marker means the cached detail predates a parser change\n // (e.g. the code-mode exec decode migration). Report no cached messages so\n // the API re-parses it fresh rather than serving the stale cache; the search\n // index drops the marker as it repopulates the session.\n const pendingReindex =\n db\n .prepare(\"SELECT 1 FROM pending_reindex WHERE agent_name = ? AND session_id = ?\")\n .get(agentName, sessionId) != null;\n\n const messageRows = pendingReindex\n ? []\n : (db\n .prepare(\n `\n SELECT\n message_id,\n role,\n time_created,\n time_completed,\n agent,\n mode,\n model,\n provider,\n tokens_json,\n cost,\n cost_source,\n parts_json,\n parts_format_version,\n subagent_id,\n nickname\n FROM messages\n WHERE agent_name = ? AND session_id = ?\n ORDER BY message_index\n `,\n )\n .all(agentName, sessionId) as CachedMessageRow[]);\n\n const head = sessionFromRow(row);\n const fileActivityRows = db\n .prepare(\n `\n SELECT agent_name, session_id, project_identity_key, path, kind, count, latest_time\n FROM session_file_activity\n WHERE agent_name = ? AND session_id = ?\n ORDER BY latest_time DESC, count DESC, path\n LIMIT 500\n `,\n )\n .all(agentName, sessionId) as FileActivityRow[];\n\n return {\n data: {\n ...head,\n reference: { agentName, sessionId },\n file_activity: fileActivityRows.map((activityRow) => fileActivityFromRow(activityRow)),\n },\n messageRows,\n meta: parseCachedSessionMeta(row.meta_json),\n };\n });\n}\n\nexport function loadCachedSessionDataEntry(\n agentName: string,\n sessionId: string,\n): CachedSessionDataEntry | null {\n const entry = loadCachedSessionRawEntry(agentName, sessionId);\n if (!entry) return null;\n return {\n data: {\n ...entry.data,\n messages: entry.messageRows.map((messageRow) => messageFromCachedRow(messageRow)),\n },\n meta: entry.meta,\n };\n}\n\nexport function loadCachedSessionData(agentName: string, sessionId: string): SessionDetail | null {\n return loadCachedSessionDataEntry(agentName, sessionId)?.data ?? null;\n}\n\n/** Returns whether the write reached disk; callers must not publish on `false`. */\nexport function saveCachedSessions(\n agentName: string,\n sessions: SessionHead[],\n meta: Record<string, SessionCacheMeta> = {},\n): boolean {\n const persisted = withCacheDb((db) => {\n const deleteSession = db.prepare(\n \"DELETE FROM sessions WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteSearchDocument = db.prepare(\n \"DELETE FROM session_documents WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteMessages = db.prepare(\n \"DELETE FROM messages WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteMessageTools = db.prepare(\n \"DELETE FROM message_tools WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteFileActivity = db.prepare(\n \"DELETE FROM session_file_activity WHERE agent_name = ? AND session_id = ?\",\n );\n const upsertAgent = db.prepare(`\n INSERT INTO agent_cache(agent_name, timestamp)\n VALUES (?, ?)\n ON CONFLICT(agent_name) DO UPDATE SET timestamp = excluded.timestamp\n `);\n const upsertSession = prepareUpsertSession(db);\n\n const write = db.transaction(() => {\n const timestamp = Date.now();\n const sessionIds = new Set(sessions.map((session) => session.id));\n const existingSessionIds = db\n .prepare(\"SELECT session_id FROM sessions WHERE agent_name = ?\")\n .all(agentName) as SessionRow[];\n upsertAgent.run(agentName, timestamp);\n\n for (const row of existingSessionIds) {\n const sessionId = String(row.session_id);\n if (!sessionIds.has(sessionId)) {\n deleteSearchDocument.run(agentName, sessionId);\n deleteMessageTools.run(agentName, sessionId);\n deleteMessages.run(agentName, sessionId);\n deleteFileActivity.run(agentName, sessionId);\n deleteSession.run(agentName, sessionId);\n }\n }\n\n sessions.forEach((session, index) => {\n const sessionMeta = meta[session.id];\n const metaJson = sessionMeta ? JSON.stringify(sessionMeta) : null;\n upsertSessionRow(\n upsertSession,\n agentName,\n session,\n metaJson,\n index,\n sourcePathFromMeta(sessionMeta),\n );\n });\n });\n\n write();\n deleteLegacyCacheFile();\n return true;\n });\n\n return persisted ?? false;\n}\n\n/** Returns whether the write reached disk; callers must not publish on `false`. */\nexport function saveCachedSessionChanges(\n agentName: string,\n changes: SessionHeadChange[],\n removedSessionIds: string[],\n meta: Record<string, SessionCacheMeta> = {},\n): boolean {\n const persisted = withCacheDb((db) => {\n const deleteSession = db.prepare(\n \"DELETE FROM sessions WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteSearchDocument = db.prepare(\n \"DELETE FROM session_documents WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteMessages = db.prepare(\n \"DELETE FROM messages WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteMessageTools = db.prepare(\n \"DELETE FROM message_tools WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteFileActivity = db.prepare(\n \"DELETE FROM session_file_activity WHERE agent_name = ? AND session_id = ?\",\n );\n const upsertAgent = db.prepare(`\n INSERT INTO agent_cache(agent_name, timestamp)\n VALUES (?, ?)\n ON CONFLICT(agent_name) DO UPDATE SET timestamp = excluded.timestamp\n `);\n const upsertSession = prepareUpsertSession(db);\n\n const write = db.transaction(() => {\n upsertAgent.run(agentName, Date.now());\n\n for (const sessionId of new Set(removedSessionIds)) {\n deleteSearchDocument.run(agentName, sessionId);\n deleteMessageTools.run(agentName, sessionId);\n deleteMessages.run(agentName, sessionId);\n deleteFileActivity.run(agentName, sessionId);\n deleteSession.run(agentName, sessionId);\n }\n\n for (const { session, sortIndex } of changes) {\n const sessionMeta = meta[session.id];\n const metaJson = sessionMeta ? JSON.stringify(sessionMeta) : null;\n upsertSessionRow(\n upsertSession,\n agentName,\n session,\n metaJson,\n sortIndex,\n sourcePathFromMeta(sessionMeta),\n );\n }\n });\n\n write();\n deleteLegacyCacheFile();\n return true;\n });\n\n return persisted ?? false;\n}\n\nexport function clearCache(): void {\n setSchemaEnsuredPath(null);\n if (!hasCacheStorage()) {\n deleteLegacyCacheFile();\n return;\n }\n\n withCacheDb((db) => {\n db.exec(`\n DELETE FROM agent_cache;\n DELETE FROM cache_initialization;\n DELETE FROM cached_sessions;\n DELETE FROM session_documents;\n DELETE FROM session_file_activity;\n DELETE FROM message_tools;\n DELETE FROM messages;\n DELETE FROM sessions;\n DELETE FROM project_sessions;\n `);\n });\n\n deleteLegacyCacheFile();\n\n const cachePath = getCachePath();\n const walPath = `${cachePath}-wal`;\n const shmPath = `${cachePath}-shm`;\n\n for (const filePath of [walPath, shmPath]) {\n if (!existsSync(filePath)) {\n continue;\n }\n try {\n rmSync(filePath, { force: true });\n } catch {\n // Ignore sidecar cleanup errors\n }\n }\n}\n\nexport function getCacheInfo(): { lastScanTime: number | null; size: number } {\n if (!hasCacheStorage()) {\n return { lastScanTime: null, size: 0 };\n }\n\n const info = withCacheDb((db) => {\n const timestampRow = db.prepare(\"SELECT MAX(timestamp) AS value FROM agent_cache\").get() as\n | ScalarRow\n | undefined;\n const sizeRow = db.prepare(\"SELECT COUNT(*) AS value FROM sessions\").get() as\n | ScalarRow\n | undefined;\n\n const lastScanTime = Number(timestampRow?.value ?? 0) || null;\n const size = Number(sizeRow?.value ?? 0);\n\n return { lastScanTime, size };\n });\n\n return info ?? { lastScanTime: null, size: 0 };\n}\n","/**\n * Cache infrastructure: cache paths and shared query helpers.\n * Lower-level than schema.ts — no DB handles here.\n */\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport type { DatabaseRow, SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport type { SessionHead } from \"../../types/index.js\";\n\nconst CACHE_FILENAME = \"codesesh.db\";\nconst LEGACY_CACHE_FILENAME = \"scan-cache.json\";\nexport const SEARCH_INDEX_BULK_SYNC_THRESHOLD = 100;\n\nexport interface SessionHeadChange {\n session: SessionHead;\n sortIndex: number;\n}\n\nexport interface ScalarRow extends DatabaseRow {\n value?: number;\n}\n\nexport interface CacheRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n session_json?: string;\n meta_json?: string | null;\n sort_index?: number;\n}\n\nexport type SQLiteStatement = ReturnType<SQLiteDatabase[\"prepare\"]>;\n\n// One-shot per-process ensureSchema guard; reset by clearCache. Once a path\n// has been schema-checked, withCacheDb skips ensureSchema's DDL exec (which\n// otherwise runs unconditionally on every open) so read-heavy callers stop\n// contending for the write lock.\nlet schemaEnsuredPath: string | null = null;\n\nexport function getSchemaEnsuredPath(): string | null {\n return schemaEnsuredPath;\n}\n\nexport function setSchemaEnsuredPath(path: string | null): void {\n schemaEnsuredPath = path;\n}\n\nexport function getCacheDir(): string {\n return join(homedir(), \".cache\", \"codesesh\");\n}\n\nexport function getCachePath(): string {\n return join(getCacheDir(), CACHE_FILENAME);\n}\n\nexport function getLegacyCachePath(): string {\n return join(getCacheDir(), LEGACY_CACHE_FILENAME);\n}\n\nexport function hasCacheStorage(): boolean {\n return existsSync(getCachePath());\n}\n\nexport function likePattern(value: string): string {\n return `%${value\n .trim()\n .toLowerCase()\n .replace(/[\\\\%_]/g, \"\\\\$&\")}%`;\n}\n\nexport function filePathFtsQuery(value: string): string | null {\n const path = normalizeFilePathSearch(value);\n if (path.length < 3) return null;\n return `\"${path.replaceAll('\"', '\"\"')}\"`;\n}\n\nexport function escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nexport function normalizeFilePathSearch(value: string): string {\n return value.trim().replace(/^\"|\"$/g, \"\");\n}\n","/**\n * Structured message storage: row ↔ domain mapping, prepared-statement\n * binders, and message-text builders shared by sessions/search/file-activity.\n */\nimport type { SessionCacheMeta } from \"../../agents/base.js\";\nimport type {\n Message,\n MessagePart,\n ProjectIdentityKind,\n SessionDetail,\n SessionFileActivity,\n SessionHead,\n ToolPart,\n} from \"../../types/index.js\";\nimport { normalizeMessageParts } from \"../../contract/message-part.js\";\nimport { computeIdentity, realFs } from \"../../projects/index.js\";\nimport type { DatabaseRow, SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport type { SQLiteStatement } from \"./db.js\";\n\nexport const MESSAGE_PARTS_FORMAT_VERSION = 1;\n\nexport interface SessionRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n sort_index?: number;\n slug?: string;\n title?: string;\n source_path?: string | null;\n directory?: string;\n parent_agent_name?: string | null;\n parent_session_id?: string | null;\n project_identity_kind?: ProjectIdentityKind;\n project_identity_key?: string;\n project_display_name?: string;\n time_created?: number;\n time_updated?: number | null;\n activity_time?: number;\n message_count?: number;\n total_input_tokens?: number;\n total_output_tokens?: number;\n total_cache_read_tokens?: number | null;\n total_cache_create_tokens?: number | null;\n total_cost?: number;\n cost_source?: SessionHead[\"stats\"][\"cost_source\"] | null;\n total_tokens?: number | null;\n model_usage_json?: string | null;\n smart_tags_json?: string | null;\n smart_tags_source_updated_at?: number | null;\n meta_json?: string | null;\n}\n\nexport interface MessageBackfillRow extends DatabaseRow {\n message_id?: string;\n role?: Message[\"role\"];\n time_created?: number;\n time_completed?: number | null;\n agent?: string | null;\n mode?: string | null;\n model?: string | null;\n provider?: string | null;\n parts_json?: string;\n subagent_id?: string | null;\n nickname?: string | null;\n}\n\nexport interface CachedMessageRow extends MessageBackfillRow {\n parts_format_version?: number | string;\n tokens_json?: string | null;\n cost?: number | null;\n cost_source?: SessionHead[\"stats\"][\"cost_source\"] | null;\n}\n\nexport interface StructuredMessageRecord {\n index: number;\n id: string;\n role: Message[\"role\"];\n timeCreated: number;\n timeCompleted?: number | null;\n agent?: string | null;\n mode?: string | null;\n model?: string | null;\n provider?: string | null;\n tokensJson?: string | null;\n cost?: number | null;\n costSource?: string | null;\n partsJson: string;\n subagentId?: string | null;\n nickname?: string | null;\n contentText: string;\n toolMetadataJson?: string | null;\n toolNames: string[];\n}\n\nexport function stringifyOptionalJson(value: unknown): string | null {\n return value == null ? null : JSON.stringify(value);\n}\n\nexport function parseOptionalJson<T>(value: unknown): T | undefined {\n return value == null ? undefined : (JSON.parse(String(value)) as T);\n}\n\nexport function sourcePathFromMeta(meta: SessionCacheMeta | undefined): string | null {\n return typeof meta?.sourcePath === \"string\" ? meta.sourcePath : null;\n}\n\nexport function sourcePathFromMetaJson(metaJson: string | null | undefined): string | null {\n if (!metaJson) return null;\n const meta = JSON.parse(metaJson) as SessionCacheMeta;\n return sourcePathFromMeta(meta);\n}\n\nexport function prepareUpsertSession(db: SQLiteDatabase): SQLiteStatement {\n return db.prepare(`\n INSERT INTO sessions(\n agent_name,\n session_id,\n sort_index,\n slug,\n title,\n source_path,\n directory,\n parent_agent_name,\n parent_session_id,\n project_identity_kind,\n project_identity_key,\n project_display_name,\n time_created,\n time_updated,\n activity_time,\n message_count,\n total_input_tokens,\n total_output_tokens,\n total_cache_read_tokens,\n total_cache_create_tokens,\n total_cost,\n cost_source,\n total_tokens,\n model_usage_json,\n smart_tags_json,\n smart_tags_source_updated_at,\n meta_json\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n sort_index = excluded.sort_index,\n slug = excluded.slug,\n title = excluded.title,\n source_path = excluded.source_path,\n directory = excluded.directory,\n parent_agent_name = excluded.parent_agent_name,\n parent_session_id = excluded.parent_session_id,\n project_identity_kind = excluded.project_identity_kind,\n project_identity_key = excluded.project_identity_key,\n project_display_name = excluded.project_display_name,\n time_created = excluded.time_created,\n time_updated = excluded.time_updated,\n activity_time = excluded.activity_time,\n message_count = excluded.message_count,\n total_input_tokens = excluded.total_input_tokens,\n total_output_tokens = excluded.total_output_tokens,\n total_cache_read_tokens = excluded.total_cache_read_tokens,\n total_cache_create_tokens = excluded.total_cache_create_tokens,\n total_cost = excluded.total_cost,\n cost_source = excluded.cost_source,\n total_tokens = excluded.total_tokens,\n model_usage_json = excluded.model_usage_json,\n smart_tags_json = excluded.smart_tags_json,\n smart_tags_source_updated_at = excluded.smart_tags_source_updated_at,\n meta_json = excluded.meta_json\n `);\n}\n\nexport function prepareUpsertIndexedSession(db: SQLiteDatabase): SQLiteStatement {\n return db.prepare(`\n INSERT INTO sessions(\n agent_name,\n session_id,\n sort_index,\n slug,\n title,\n source_path,\n directory,\n parent_agent_name,\n parent_session_id,\n project_identity_kind,\n project_identity_key,\n project_display_name,\n time_created,\n time_updated,\n activity_time,\n message_count,\n total_input_tokens,\n total_output_tokens,\n total_cache_read_tokens,\n total_cache_create_tokens,\n total_cost,\n cost_source,\n total_tokens,\n model_usage_json,\n smart_tags_json,\n smart_tags_source_updated_at,\n meta_json\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n slug = excluded.slug,\n title = excluded.title,\n directory = excluded.directory,\n parent_agent_name = excluded.parent_agent_name,\n parent_session_id = excluded.parent_session_id,\n project_identity_kind = excluded.project_identity_kind,\n project_identity_key = excluded.project_identity_key,\n project_display_name = excluded.project_display_name,\n time_created = excluded.time_created,\n time_updated = excluded.time_updated,\n activity_time = excluded.activity_time,\n message_count = excluded.message_count,\n total_input_tokens = excluded.total_input_tokens,\n total_output_tokens = excluded.total_output_tokens,\n total_cache_read_tokens = excluded.total_cache_read_tokens,\n total_cache_create_tokens = excluded.total_cache_create_tokens,\n total_cost = excluded.total_cost,\n cost_source = excluded.cost_source,\n total_tokens = excluded.total_tokens,\n model_usage_json = excluded.model_usage_json,\n smart_tags_json = excluded.smart_tags_json,\n smart_tags_source_updated_at = excluded.smart_tags_source_updated_at\n `);\n}\n\nexport function upsertSessionRow(\n statement: SQLiteStatement,\n agentName: string,\n session: SessionHead,\n metaJson: string | null,\n sortIndex: number,\n sourcePath: string | null,\n): void {\n const identity = session.project_identity ?? computeIdentity(session.directory, realFs);\n const activityTime = session.time_updated ?? session.time_created;\n statement.run(\n agentName,\n session.id,\n sortIndex,\n session.slug,\n session.title,\n sourcePath,\n session.directory,\n session.parent_reference?.agentName ?? null,\n session.parent_reference?.sessionId ?? null,\n identity.kind,\n identity.key,\n identity.displayName,\n session.time_created,\n session.time_updated ?? null,\n activityTime,\n session.stats.message_count,\n session.stats.total_input_tokens,\n session.stats.total_output_tokens,\n session.stats.total_cache_read_tokens ?? null,\n session.stats.total_cache_create_tokens ?? null,\n session.stats.total_cost,\n session.stats.cost_source ?? null,\n session.stats.total_tokens ?? null,\n stringifyOptionalJson(session.model_usage),\n stringifyOptionalJson(session.smart_tags),\n session.smart_tags_source_updated_at ?? null,\n metaJson,\n );\n}\n\nexport function prepareInsertFileActivity(db: SQLiteDatabase): SQLiteStatement {\n return db.prepare(`\n INSERT INTO session_file_activity(\n agent_name,\n session_id,\n project_identity_key,\n path,\n kind,\n count,\n latest_time\n ) VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n}\n\nexport function prepareInsertMessageTool(db: SQLiteDatabase): SQLiteStatement {\n return db.prepare(`\n INSERT OR IGNORE INTO message_tools(\n agent_name,\n session_id,\n message_index,\n tool_name\n ) VALUES (?, ?, ?, ?)\n `);\n}\n\nexport function writeFileActivityRows(\n statement: SQLiteStatement,\n activities: SessionFileActivity[],\n): void {\n for (const activity of activities) {\n statement.run(\n activity.reference.agentName,\n activity.reference.sessionId,\n activity.projectIdentityKey,\n activity.path,\n activity.kind,\n activity.count,\n activity.latestTime,\n );\n }\n}\n\nexport function sessionFromRow(row: SessionRow): SessionHead {\n const session: SessionHead = {\n id: String(row.session_id),\n slug: String(row.slug),\n title: String(row.title),\n directory: String(row.directory),\n time_created: Number(row.time_created),\n stats: {\n message_count: Number(row.message_count ?? 0),\n total_input_tokens: Number(row.total_input_tokens ?? 0),\n total_output_tokens: Number(row.total_output_tokens ?? 0),\n total_cost: Number(row.total_cost ?? 0),\n },\n };\n\n if (row.project_identity_key) {\n session.project_identity = {\n kind: row.project_identity_kind ?? \"path\",\n key: String(row.project_identity_key),\n displayName: String(row.project_display_name ?? \"\"),\n };\n }\n if (row.parent_agent_name && row.parent_session_id) {\n session.parent_reference = {\n agentName: String(row.parent_agent_name),\n sessionId: String(row.parent_session_id),\n };\n }\n if (row.time_updated != null) {\n session.time_updated = Number(row.time_updated);\n }\n if (row.total_cache_read_tokens != null) {\n session.stats.total_cache_read_tokens = Number(row.total_cache_read_tokens);\n }\n if (row.total_cache_create_tokens != null) {\n session.stats.total_cache_create_tokens = Number(row.total_cache_create_tokens);\n }\n if (row.cost_source) {\n session.stats.cost_source = row.cost_source;\n }\n if (row.total_tokens != null) {\n session.stats.total_tokens = Number(row.total_tokens);\n }\n\n const modelUsage = parseOptionalJson<Record<string, number>>(row.model_usage_json);\n if (modelUsage) {\n session.model_usage = modelUsage;\n }\n\n const smartTags = parseOptionalJson<SessionHead[\"smart_tags\"]>(row.smart_tags_json);\n if (smartTags) {\n session.smart_tags = smartTags;\n }\n if (row.smart_tags_source_updated_at != null) {\n session.smart_tags_source_updated_at = Number(row.smart_tags_source_updated_at);\n }\n\n return session;\n}\n\nfunction messageMetadataFromBackfillRow(row: MessageBackfillRow): Omit<Message, \"parts\"> {\n const role = row.role === \"assistant\" || row.role === \"tool\" ? row.role : \"user\";\n return {\n id: String(row.message_id ?? \"\"),\n role,\n agent: row.agent ?? null,\n time_created: Number(row.time_created ?? 0),\n time_completed: row.time_completed == null ? null : Number(row.time_completed),\n mode: row.mode ?? null,\n model: row.model ?? null,\n provider: row.provider ?? null,\n subagent_id: row.subagent_id ?? undefined,\n nickname: row.nickname ?? undefined,\n };\n}\n\nfunction messageMetadataFromCachedRow(row: CachedMessageRow): Omit<Message, \"parts\"> {\n const message = messageMetadataFromBackfillRow(row);\n const tokens = parseOptionalJson<Message[\"tokens\"]>(row.tokens_json);\n if (tokens) {\n message.tokens = tokens;\n }\n if (row.cost != null) {\n message.cost = Number(row.cost);\n }\n if (row.cost_source) {\n message.cost_source = row.cost_source;\n }\n return message;\n}\n\nexport function messageFromBackfillRow(row: MessageBackfillRow): Message {\n return {\n ...messageMetadataFromBackfillRow(row),\n parts: messagePartsFromJson(row.parts_json),\n };\n}\n\nexport function messageFromCachedRow(row: CachedMessageRow): Message {\n return {\n ...messageMetadataFromCachedRow(row),\n parts: messagePartsFromJson(row.parts_json),\n };\n}\n\nfunction messagePartsFromJson(value: unknown): MessagePart[] {\n try {\n return normalizeMessageParts(JSON.parse(String(value ?? \"[]\")));\n } catch {\n return [];\n }\n}\n\nexport function normalizeMessagePartsJson(value: unknown): string {\n return JSON.stringify(messagePartsFromJson(value));\n}\n\nexport function messageJsonFromCachedRow(row: CachedMessageRow): string {\n const metadataJson = JSON.stringify(messageMetadataFromBackfillRow(row));\n const fields: string[] = [];\n if (row.tokens_json != null) {\n fields.push(`\"tokens\":${String(row.tokens_json)}`);\n }\n if (row.cost != null) {\n fields.push(`\"cost\":${JSON.stringify(Number(row.cost))}`);\n }\n if (row.cost_source) {\n fields.push(`\"cost_source\":${JSON.stringify(row.cost_source)}`);\n }\n const partsJson =\n Number(row.parts_format_version) >= MESSAGE_PARTS_FORMAT_VERSION\n ? String(row.parts_json ?? \"[]\")\n : normalizeMessagePartsJson(row.parts_json);\n fields.push(`\"parts\":${partsJson}`);\n return `${metadataJson.slice(0, -1)},${fields.join(\",\")}}`;\n}\n\nexport function appendPlainText(value: unknown, chunks: string[]): void {\n if (value == null) return;\n\n if (typeof value === \"string\") {\n const normalized = value.trim();\n if (normalized) {\n chunks.push(normalized);\n }\n return;\n }\n\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n chunks.push(String(value));\n return;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n appendPlainText(item, chunks);\n }\n return;\n }\n\n if (typeof value === \"object\") {\n for (const nested of Object.values(value as Record<string, unknown>)) {\n appendPlainText(nested, chunks);\n }\n }\n}\n\nexport function compactRecord(record: Record<string, unknown>): Record<string, unknown> {\n return Object.fromEntries(Object.entries(record).filter(([, value]) => value != null));\n}\n\nexport function normalizeToolName(value: unknown): string | null {\n if (typeof value !== \"string\") return null;\n const name = value.trim().toLowerCase();\n return name || null;\n}\n\nexport function toolNamesFromMetadataJson(value: unknown): string[] {\n if (!value) return [];\n\n try {\n const metadata = JSON.parse(String(value));\n if (!Array.isArray(metadata)) return [];\n const tools = new Set<string>();\n for (const item of metadata) {\n if (item == null || typeof item !== \"object\") continue;\n const toolName = normalizeToolName((item as Record<string, unknown>).tool);\n if (toolName) tools.add(toolName);\n }\n return [...tools];\n } catch {\n return [];\n }\n}\n\nexport function toolNamesFromMessage(message: Message): string[] {\n const tools = new Set<string>();\n for (const part of message.parts) {\n if (part.type !== \"tool\") continue;\n const toolName = normalizeToolName(part.tool);\n if (toolName) tools.add(toolName);\n }\n return [...tools];\n}\n\nexport function summarizeToolPart(part: ToolPart): Record<string, unknown> {\n const state = compactRecord({\n status: part.state.status,\n error: part.state.error,\n metadata: part.state.metadata,\n });\n return compactRecord({\n type: part.type,\n tool: part.tool,\n title: part.title,\n callID: part.callID,\n state,\n });\n}\n\nexport function buildMessageText(message: Message): string {\n const chunks: string[] = [];\n\n chunks.push(message.role);\n appendPlainText(message.agent, chunks);\n appendPlainText(message.model, chunks);\n\n for (const part of message.parts) {\n appendPlainText(part.type, chunks);\n if (part.type === \"text\" || part.type === \"reasoning\" || part.type === \"plan\") {\n appendPlainText(part.text, chunks);\n } else if (part.type === \"tool\") {\n appendPlainText(part.title, chunks);\n appendPlainText(part.tool, chunks);\n appendPlainText(part.state, chunks);\n }\n }\n\n return chunks.join(\"\\n\");\n}\n\nexport function normalizeMessages(session: SessionDetail): StructuredMessageRecord[] {\n return session.messages.map((message, index) => {\n const toolMetadata = message.parts\n .filter((part): part is ToolPart => part.type === \"tool\")\n .map((part) => summarizeToolPart(part));\n\n return {\n index,\n id: message.id || `${session.id}:${index}`,\n role: message.role,\n timeCreated: message.time_created,\n timeCompleted: message.time_completed ?? null,\n agent: message.agent ?? null,\n mode: message.mode ?? null,\n model: message.model ?? null,\n provider: message.provider ?? null,\n tokensJson: stringifyOptionalJson(message.tokens),\n cost: message.cost ?? null,\n costSource: message.cost_source ?? null,\n partsJson: JSON.stringify(message.parts),\n subagentId: message.subagent_id ?? null,\n nickname: message.nickname ?? null,\n contentText: buildMessageText(message),\n toolMetadataJson: toolMetadata.length > 0 ? JSON.stringify(toolMetadata) : null,\n toolNames: toolNamesFromMessage(message),\n };\n });\n}\n\nexport function buildSessionContentFromMessages(\n title: string | null | undefined,\n messages: StructuredMessageRecord[],\n): string {\n const chunks: string[] = [];\n appendPlainText(title, chunks);\n for (const message of messages) {\n appendPlainText(message.contentText, chunks);\n }\n return chunks.join(\"\\n\");\n}\n","/**\n * Cache storage boundary. Callers request a ready database capability while\n * schema creation, migrations, and search-index maintenance stay internal.\n */\nimport type { ProjectIdentityKind, SessionHead } from \"../../types/index.js\";\nimport { computeIdentity, realFs } from \"../../projects/index.js\";\nimport { extractSessionFileActivity } from \"../../utils/file-activity.js\";\nimport { getCoreDiagnostics } from \"../../utils/diagnostics.js\";\nimport {\n columnExists,\n getUserVersion,\n openDb,\n openDbReadOnly,\n runSchemaMigrations,\n setUserVersion,\n tableExists,\n type DatabaseRow,\n type SQLiteDatabase,\n} from \"../../utils/sqlite.js\";\nimport { getCachePath, getSchemaEnsuredPath, setSchemaEnsuredPath, type CacheRow } from \"./db.js\";\nimport {\n messageFromBackfillRow,\n prepareInsertFileActivity,\n prepareInsertMessageTool,\n prepareUpsertSession,\n sourcePathFromMetaJson,\n toolNamesFromMetadataJson,\n upsertSessionRow,\n writeFileActivityRows,\n type MessageBackfillRow,\n type SessionRow,\n} from \"./messages.js\";\n\nconst CACHE_SCHEMA_VERSION = 18;\ninterface MessageToolBackfillRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n message_index?: number;\n tool_metadata_json?: string | null;\n}\n\ninterface ProjectBackfillSessionRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n session_json?: string;\n meta_json?: string | null;\n sort_index?: number;\n}\n\ninterface ProjectBackfillDocumentRow extends DatabaseRow {\n id?: number;\n agent_name?: string;\n session_id?: string;\n slug?: string;\n title?: string;\n directory?: string;\n project_identity_kind?: ProjectIdentityKind;\n project_identity_key?: string;\n project_display_name?: string;\n time_created?: number;\n time_updated?: number | null;\n activity_time?: number;\n}\n\ninterface ProjectIdentityRefreshRow extends DatabaseRow {\n id?: number;\n agent_name?: string;\n session_id?: string;\n directory?: string;\n}\n\nexport function withCacheDb<T>(fn: (db: SQLiteDatabase) => T): T | null {\n const cachePath = getCachePath();\n const db = openDb(cachePath);\n if (!db) return null;\n\n try {\n if (getSchemaEnsuredPath() !== cachePath) {\n ensureSchema(db, cachePath);\n setSchemaEnsuredPath(cachePath);\n }\n return fn(db);\n } catch (error) {\n getCoreDiagnostics()?.warn(\"cache.write_failed\", {\n message: error instanceof Error ? error.message : String(error),\n });\n return null;\n } finally {\n db.close();\n }\n}\n\nexport function withCacheDbReadOnly<T>(fn: (db: SQLiteDatabase) => T): T | null {\n const db = openDbReadOnly(getCachePath());\n if (!db) return null;\n\n try {\n return fn(db);\n } catch {\n return null;\n } finally {\n db.close();\n }\n}\n\nexport function withSearchDb<T>(fn: (db: SQLiteDatabase) => T): T | null {\n return withCacheDb((db) => runWithFtsRecovery(db, fn));\n}\n\nexport function withSearchIndexDb<T>(fn: (db: SQLiteDatabase) => T): T | null {\n return withCacheDb((db) => runWithFtsRecovery(db, fn));\n}\n\ninterface SearchIndexWriteResult<T> {\n value: T;\n rebuildDurationMs?: number;\n}\n\nexport function runSearchIndexWrite<T>(\n db: SQLiteDatabase,\n rebuild: boolean,\n write: () => T,\n): SearchIndexWriteResult<T> {\n return db.transaction(() => {\n if (rebuild) {\n dropSearchTriggers(db);\n dropMessageSearchTriggers(db);\n }\n\n const value = write();\n let rebuildDurationMs: number | undefined;\n\n if (rebuild) {\n const rebuildStartedAt = performance.now();\n rebuildSearchIndex(db);\n rebuildMessageSearchIndex(db);\n rebuildDurationMs = performance.now() - rebuildStartedAt;\n createSearchTriggers(db);\n createMessageSearchTriggers(db);\n }\n\n return { value, rebuildDurationMs };\n })();\n}\n\nfunction createCacheTables(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS cache_meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS agent_cache (\n agent_name TEXT PRIMARY KEY,\n timestamp INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS cached_sessions (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n session_json TEXT NOT NULL,\n meta_json TEXT,\n PRIMARY KEY (agent_name, session_id)\n );\n\n CREATE TABLE IF NOT EXISTS cache_initialization (\n agent_name TEXT PRIMARY KEY,\n initialized_at INTEGER NOT NULL,\n index_version TEXT NOT NULL,\n last_sync_at INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS pending_reindex (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n PRIMARY KEY (agent_name, session_id)\n );\n `);\n}\n\nfunction createSessionTables(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS sessions (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n sort_index INTEGER NOT NULL DEFAULT 0,\n slug TEXT NOT NULL,\n title TEXT NOT NULL,\n source_path TEXT,\n directory TEXT NOT NULL,\n parent_agent_name TEXT,\n parent_session_id TEXT,\n project_identity_kind TEXT NOT NULL,\n project_identity_key TEXT NOT NULL,\n project_display_name TEXT NOT NULL,\n time_created INTEGER NOT NULL,\n time_updated INTEGER,\n activity_time INTEGER NOT NULL,\n message_count INTEGER NOT NULL,\n total_input_tokens INTEGER NOT NULL,\n total_output_tokens INTEGER NOT NULL,\n total_cache_read_tokens INTEGER,\n total_cache_create_tokens INTEGER,\n total_cost REAL NOT NULL,\n cost_source TEXT,\n total_tokens INTEGER,\n model_usage_json TEXT,\n smart_tags_json TEXT,\n smart_tags_source_updated_at INTEGER,\n meta_json TEXT,\n PRIMARY KEY (agent_name, session_id)\n );\n\n CREATE INDEX IF NOT EXISTS idx_sessions_agent_activity\n ON sessions(agent_name, activity_time);\n\n CREATE INDEX IF NOT EXISTS idx_sessions_project\n ON sessions(project_identity_kind, project_identity_key, activity_time);\n\n CREATE INDEX IF NOT EXISTS idx_sessions_parent\n ON sessions(parent_agent_name, parent_session_id);\n\n CREATE TABLE IF NOT EXISTS messages (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n message_index INTEGER NOT NULL,\n message_id TEXT NOT NULL,\n role TEXT NOT NULL,\n time_created INTEGER NOT NULL,\n time_completed INTEGER,\n agent TEXT,\n mode TEXT,\n model TEXT,\n provider TEXT,\n tokens_json TEXT,\n cost REAL,\n cost_source TEXT,\n parts_json TEXT NOT NULL,\n parts_format_version INTEGER NOT NULL DEFAULT 0,\n subagent_id TEXT,\n nickname TEXT,\n content_text TEXT NOT NULL,\n tool_metadata_json TEXT,\n PRIMARY KEY (agent_name, session_id, message_index),\n FOREIGN KEY (agent_name, session_id)\n REFERENCES sessions(agent_name, session_id)\n ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_messages_session\n ON messages(agent_name, session_id, message_index);\n `);\n\n createMessageToolTables(db);\n}\n\nfunction createMessageToolTables(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS message_tools (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n message_index INTEGER NOT NULL,\n tool_name TEXT NOT NULL,\n PRIMARY KEY (agent_name, session_id, message_index, tool_name),\n FOREIGN KEY (agent_name, session_id, message_index)\n REFERENCES messages(agent_name, session_id, message_index)\n ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_message_tools_filter\n ON message_tools(tool_name, agent_name, session_id);\n `);\n}\n\nfunction createMessageSearchTables(db: SQLiteDatabase): void {\n if (!tableExists(db, \"messages\")) {\n createSessionTables(db);\n }\n\n db.exec(`\n CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts USING fts5(\n content_text,\n content='messages',\n content_rowid='rowid'\n );\n `);\n\n createMessageSearchTriggers(db);\n}\n\nfunction createMessageSearchTriggers(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TRIGGER IF NOT EXISTS messages_ai AFTER INSERT ON messages BEGIN\n INSERT INTO messages_fts(rowid, content_text)\n VALUES (new.rowid, new.content_text);\n END;\n\n CREATE TRIGGER IF NOT EXISTS messages_ad AFTER DELETE ON messages BEGIN\n INSERT INTO messages_fts(messages_fts, rowid, content_text)\n VALUES ('delete', old.rowid, old.content_text);\n END;\n\n CREATE TRIGGER IF NOT EXISTS messages_au AFTER UPDATE ON messages BEGIN\n INSERT INTO messages_fts(messages_fts, rowid, content_text)\n VALUES ('delete', old.rowid, old.content_text);\n INSERT INTO messages_fts(rowid, content_text)\n VALUES (new.rowid, new.content_text);\n END;\n `);\n}\n\nfunction dropMessageSearchTriggers(db: SQLiteDatabase): void {\n db.exec(`\n DROP TRIGGER IF EXISTS messages_ai;\n DROP TRIGGER IF EXISTS messages_ad;\n DROP TRIGGER IF EXISTS messages_au;\n `);\n}\n\nfunction createFileActivityTables(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS session_file_activity (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n project_identity_key TEXT NOT NULL,\n path TEXT NOT NULL,\n kind TEXT NOT NULL,\n count INTEGER NOT NULL,\n latest_time INTEGER NOT NULL,\n PRIMARY KEY (agent_name, session_id, project_identity_key, path, kind),\n FOREIGN KEY (agent_name, session_id)\n REFERENCES sessions(agent_name, session_id)\n ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_file_activity_project_latest\n ON session_file_activity(project_identity_key, latest_time);\n\n CREATE INDEX IF NOT EXISTS idx_file_activity_latest\n ON session_file_activity(latest_time DESC, count DESC, path);\n\n CREATE INDEX IF NOT EXISTS idx_file_activity_agent_latest\n ON session_file_activity(agent_name, latest_time DESC, count DESC, path);\n\n CREATE INDEX IF NOT EXISTS idx_file_activity_project_latest_ordered\n ON session_file_activity(project_identity_key, latest_time DESC, count DESC, path);\n\n CREATE INDEX IF NOT EXISTS idx_file_activity_path\n ON session_file_activity(path);\n\n CREATE INDEX IF NOT EXISTS idx_file_activity_kind\n ON session_file_activity(kind);\n `);\n\n createFileActivityPathSearchTables(db);\n}\n\nfunction createFileActivityPathSearchTables(db: SQLiteDatabase): void {\n db.exec(`\n CREATE VIRTUAL TABLE IF NOT EXISTS session_file_activity_path_fts USING fts5(\n path,\n content='session_file_activity',\n content_rowid='rowid',\n tokenize='trigram'\n );\n `);\n\n createFileActivityPathSearchTriggers(db);\n}\n\nfunction createFileActivityPathSearchTriggers(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TRIGGER IF NOT EXISTS session_file_activity_path_ai\n AFTER INSERT ON session_file_activity BEGIN\n INSERT INTO session_file_activity_path_fts(rowid, path)\n VALUES (new.rowid, new.path);\n END;\n\n CREATE TRIGGER IF NOT EXISTS session_file_activity_path_ad\n AFTER DELETE ON session_file_activity BEGIN\n INSERT INTO session_file_activity_path_fts(session_file_activity_path_fts, rowid, path)\n VALUES ('delete', old.rowid, old.path);\n END;\n\n CREATE TRIGGER IF NOT EXISTS session_file_activity_path_au\n AFTER UPDATE ON session_file_activity BEGIN\n INSERT INTO session_file_activity_path_fts(session_file_activity_path_fts, rowid, path)\n VALUES ('delete', old.rowid, old.path);\n INSERT INTO session_file_activity_path_fts(rowid, path)\n VALUES (new.rowid, new.path);\n END;\n `);\n}\n\nfunction rebuildFileActivityPathIndex(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_file_activity_path_fts\")) {\n return;\n }\n db.exec(\n \"INSERT INTO session_file_activity_path_fts(session_file_activity_path_fts) VALUES ('rebuild')\",\n );\n}\n\nfunction createSearchTables(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS session_documents (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n title TEXT NOT NULL,\n content_text TEXT NOT NULL,\n content_hash TEXT NOT NULL,\n indexed_message_count INTEGER NOT NULL,\n indexed_at INTEGER NOT NULL,\n UNIQUE(agent_name, session_id)\n );\n\n CREATE VIRTUAL TABLE IF NOT EXISTS session_documents_fts USING fts5(\n title,\n content_text,\n content='session_documents',\n content_rowid='id'\n );\n `);\n\n createSearchTriggers(db);\n}\n\nfunction createSearchTriggers(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TRIGGER IF NOT EXISTS session_documents_ai AFTER INSERT ON session_documents BEGIN\n INSERT INTO session_documents_fts(rowid, title, content_text)\n VALUES (new.id, new.title, new.content_text);\n END;\n\n CREATE TRIGGER IF NOT EXISTS session_documents_ad AFTER DELETE ON session_documents BEGIN\n INSERT INTO session_documents_fts(session_documents_fts, rowid, title, content_text)\n VALUES ('delete', old.id, old.title, old.content_text);\n END;\n\n CREATE TRIGGER IF NOT EXISTS session_documents_au AFTER UPDATE ON session_documents BEGIN\n INSERT INTO session_documents_fts(session_documents_fts, rowid, title, content_text)\n VALUES ('delete', old.id, old.title, old.content_text);\n INSERT INTO session_documents_fts(rowid, title, content_text)\n VALUES (new.id, new.title, new.content_text);\n END;\n `);\n}\n\nfunction addIndexedMessageCount(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_documents\")) return;\n\n if (!columnExists(db, \"session_documents\", \"indexed_message_count\")) {\n db.exec(\n \"ALTER TABLE session_documents ADD COLUMN indexed_message_count INTEGER NOT NULL DEFAULT 0\",\n );\n }\n if (!tableExists(db, \"messages\")) return;\n\n db.exec(`\n UPDATE session_documents\n SET indexed_message_count = (\n SELECT COUNT(*)\n FROM messages\n WHERE messages.agent_name = session_documents.agent_name\n AND messages.session_id = session_documents.session_id\n )\n `);\n}\n\nfunction dropSearchTriggers(db: SQLiteDatabase): void {\n db.exec(`\n DROP TRIGGER IF EXISTS session_documents_ai;\n DROP TRIGGER IF EXISTS session_documents_ad;\n DROP TRIGGER IF EXISTS session_documents_au;\n `);\n}\n\nconst LEGACY_SESSION_DOCUMENT_COLUMNS = [\n [\"slug\", \"TEXT NOT NULL DEFAULT ''\"],\n [\"directory\", \"TEXT NOT NULL DEFAULT ''\"],\n [\"time_created\", \"INTEGER NOT NULL DEFAULT 0\"],\n [\"time_updated\", \"INTEGER\"],\n [\"activity_time\", \"INTEGER NOT NULL DEFAULT 0\"],\n [\"project_identity_kind\", \"TEXT NOT NULL DEFAULT 'path'\"],\n [\"project_identity_key\", \"TEXT NOT NULL DEFAULT ''\"],\n [\"project_display_name\", \"TEXT NOT NULL DEFAULT ''\"],\n] as const;\n\nfunction ensureLegacySessionDocumentColumns(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_documents\")) {\n return;\n }\n\n for (const [name, definition] of LEGACY_SESSION_DOCUMENT_COLUMNS) {\n if (!columnExists(db, \"session_documents\", name)) {\n db.exec(`ALTER TABLE session_documents ADD COLUMN ${name} ${definition}`);\n }\n }\n}\n\nfunction createProjectTables(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS project_sessions (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n identity_kind TEXT NOT NULL,\n identity_key TEXT NOT NULL,\n display_name TEXT NOT NULL,\n directory TEXT NOT NULL,\n activity_time INTEGER NOT NULL,\n PRIMARY KEY (agent_name, session_id)\n );\n\n CREATE INDEX IF NOT EXISTS idx_project_sessions_identity\n ON project_sessions(identity_kind, identity_key);\n `);\n createProjectGroupsView(db);\n}\n\nfunction createProjectGroupsView(db: SQLiteDatabase): void {\n if (!tableExists(db, \"sessions\")) {\n db.exec(`\n CREATE VIEW IF NOT EXISTS project_groups_v AS\n SELECT\n identity_kind,\n identity_key,\n MIN(display_name) AS display_name,\n GROUP_CONCAT(DISTINCT agent_name) AS sources_csv,\n COUNT(*) AS session_count,\n MAX(activity_time) AS last_activity\n FROM project_sessions\n GROUP BY identity_kind, identity_key;\n `);\n return;\n }\n\n const hasParentReference =\n columnExists(db, \"sessions\", \"parent_agent_name\") &&\n columnExists(db, \"sessions\", \"parent_session_id\");\n db.exec(`\n CREATE VIEW IF NOT EXISTS project_groups_v AS\n SELECT\n project_identity_kind AS identity_kind,\n project_identity_key AS identity_key,\n MIN(project_display_name) AS display_name,\n GROUP_CONCAT(DISTINCT agent_name) AS sources_csv,\n COUNT(*) AS session_count,\n MAX(activity_time) AS last_activity\n FROM sessions\n ${hasParentReference ? \"WHERE parent_agent_name IS NULL OR parent_session_id IS NULL\" : \"\"}\n GROUP BY project_identity_kind, project_identity_key;\n `);\n}\n\nfunction recreateProjectGroupsView(db: SQLiteDatabase): void {\n db.exec(\"DROP VIEW IF EXISTS project_groups_v\");\n createProjectGroupsView(db);\n}\n\nfunction createLatestCacheSchema(db: SQLiteDatabase): void {\n createCacheTables(db);\n createSessionTables(db);\n createFileActivityTables(db);\n createProjectTables(db);\n ensureFtsReady(db);\n}\n\nfunction recreateSearchIndexSchema(db: SQLiteDatabase): void {\n db.exec(`\n DROP TRIGGER IF EXISTS session_documents_ai;\n DROP TRIGGER IF EXISTS session_documents_ad;\n DROP TRIGGER IF EXISTS session_documents_au;\n DROP TABLE IF EXISTS session_documents_fts;\n `);\n createSearchTables(db);\n rebuildSearchIndex(db);\n}\n\nfunction readLegacyCacheVersion(db: SQLiteDatabase): number {\n if (\n !tableExists(db, \"cache_meta\") ||\n !columnExists(db, \"cache_meta\", \"key\") ||\n !columnExists(db, \"cache_meta\", \"value\")\n ) {\n return 0;\n }\n\n const versionRow = db.prepare(\"SELECT value FROM cache_meta WHERE key = 'version'\").get() as\n | DatabaseRow\n | undefined;\n return Number(versionRow?.value ?? 0);\n}\n\nfunction inferCacheSchemaVersion(db: SQLiteDatabase): number {\n if (columnExists(db, \"session_documents\", \"indexed_message_count\")) {\n return columnExists(db, \"session_documents\", \"slug\") ? 14 : 15;\n }\n if (tableExists(db, \"message_tools\")) {\n return 11;\n }\n if (tableExists(db, \"session_file_activity_path_fts\")) {\n return 10;\n }\n if (tableExists(db, \"messages_fts\")) {\n return 9;\n }\n if (tableExists(db, \"session_file_activity\")) {\n return 8;\n }\n if (tableExists(db, \"sessions\") || tableExists(db, \"messages\")) {\n return 7;\n }\n if (\n tableExists(db, \"project_sessions\") ||\n columnExists(db, \"session_documents\", \"project_identity_key\")\n ) {\n return 5;\n }\n if (tableExists(db, \"session_documents\")) {\n return 4;\n }\n if (tableExists(db, \"cached_sessions\") || tableExists(db, \"agent_cache\")) {\n return 3;\n }\n return 0;\n}\n\nfunction getCurrentCacheSchemaVersion(db: SQLiteDatabase): number {\n const userVersion = getUserVersion(db);\n if (userVersion > 0) {\n return userVersion;\n }\n\n const legacyVersion = readLegacyCacheVersion(db);\n return Math.max(legacyVersion, inferCacheSchemaVersion(db));\n}\n\nfunction hasAnyCacheSchema(db: SQLiteDatabase): boolean {\n return [\n \"cache_meta\",\n \"agent_cache\",\n \"cached_sessions\",\n \"sessions\",\n \"messages\",\n \"message_tools\",\n \"session_file_activity\",\n \"session_file_activity_path_fts\",\n \"session_documents\",\n \"session_documents_fts\",\n \"project_sessions\",\n ].some((table) => tableExists(db, table));\n}\n\nfunction backfillProjectSessions(db: SQLiteDatabase): void {\n if (!tableExists(db, \"cached_sessions\") || !tableExists(db, \"project_sessions\")) {\n return;\n }\n\n const rows = db\n .prepare(\"SELECT agent_name, session_id, session_json FROM cached_sessions\")\n .all() as ProjectBackfillSessionRow[];\n const upsert = db.prepare(`\n INSERT INTO project_sessions(\n agent_name,\n session_id,\n identity_kind,\n identity_key,\n display_name,\n directory,\n activity_time\n ) VALUES (?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n identity_kind = excluded.identity_kind,\n identity_key = excluded.identity_key,\n display_name = excluded.display_name,\n directory = excluded.directory,\n activity_time = excluded.activity_time\n `);\n\n for (const row of rows) {\n if (!row.session_json || !row.agent_name || !row.session_id) {\n continue;\n }\n\n try {\n const session = JSON.parse(row.session_json) as SessionHead;\n const identity = session.project_identity ?? computeIdentity(session.directory, realFs);\n upsert.run(\n row.agent_name,\n row.session_id,\n identity.kind,\n identity.key,\n identity.displayName,\n session.directory,\n session.time_updated ?? session.time_created,\n );\n } catch {\n continue;\n }\n }\n}\n\nfunction backfillSessionDocumentProjects(db: SQLiteDatabase): void {\n if (\n !tableExists(db, \"session_documents\") ||\n !columnExists(db, \"session_documents\", \"project_identity_key\")\n ) {\n return;\n }\n\n const rows = db\n .prepare(\"SELECT id, directory FROM session_documents\")\n .all() as ProjectBackfillDocumentRow[];\n const update = db.prepare(`\n UPDATE session_documents\n SET\n project_identity_kind = ?,\n project_identity_key = ?,\n project_display_name = ?\n WHERE id = ?\n `);\n\n for (const row of rows) {\n const identity = computeIdentity(String(row.directory ?? \"\"), realFs);\n update.run(identity.kind, identity.key, identity.displayName, Number(row.id));\n }\n}\n\nfunction migrateProjectIdentity(db: SQLiteDatabase): void {\n ensureLegacySessionDocumentColumns(db);\n createProjectTables(db);\n backfillProjectSessions(db);\n backfillSessionDocumentProjects(db);\n}\n\nfunction refreshProjectIdentities(db: SQLiteDatabase): void {\n if (\n tableExists(db, \"sessions\") &&\n columnExists(db, \"sessions\", \"project_identity_key\") &&\n columnExists(db, \"sessions\", \"directory\")\n ) {\n const rows = db\n .prepare(\"SELECT agent_name, session_id, directory FROM sessions\")\n .all() as ProjectIdentityRefreshRow[];\n const update = db.prepare(`\n UPDATE sessions\n SET\n project_identity_kind = ?,\n project_identity_key = ?,\n project_display_name = ?\n WHERE agent_name = ? AND session_id = ?\n `);\n const updateFileActivity =\n tableExists(db, \"session_file_activity\") &&\n columnExists(db, \"session_file_activity\", \"project_identity_key\")\n ? db.prepare(`\n UPDATE session_file_activity\n SET project_identity_key = ?\n WHERE agent_name = ? AND session_id = ?\n `)\n : null;\n\n for (const row of rows) {\n const identity = computeIdentity(String(row.directory ?? \"\"), realFs);\n update.run(identity.kind, identity.key, identity.displayName, row.agent_name, row.session_id);\n updateFileActivity?.run(identity.key, row.agent_name, row.session_id);\n }\n }\n\n if (\n tableExists(db, \"project_sessions\") &&\n columnExists(db, \"project_sessions\", \"identity_key\") &&\n columnExists(db, \"project_sessions\", \"directory\")\n ) {\n const rows = db\n .prepare(\"SELECT agent_name, session_id, directory FROM project_sessions\")\n .all() as ProjectIdentityRefreshRow[];\n const update = db.prepare(`\n UPDATE project_sessions\n SET\n identity_kind = ?,\n identity_key = ?,\n display_name = ?\n WHERE agent_name = ? AND session_id = ?\n `);\n\n for (const row of rows) {\n const identity = computeIdentity(String(row.directory ?? \"\"), realFs);\n update.run(identity.kind, identity.key, identity.displayName, row.agent_name, row.session_id);\n }\n }\n\n backfillSessionDocumentProjects(db);\n recreateProjectGroupsView(db);\n}\n\nfunction backfillStructuredSessions(db: SQLiteDatabase): void {\n createSessionTables(db);\n recreateProjectGroupsView(db);\n const upsertSession = prepareUpsertSession(db);\n\n if (tableExists(db, \"cached_sessions\")) {\n const rows = db\n .prepare(\n \"SELECT agent_name, session_id, session_json, meta_json, rowid AS sort_index FROM cached_sessions ORDER BY agent_name, rowid\",\n )\n .all() as CacheRow[];\n\n for (const row of rows) {\n if (!row.agent_name || !row.session_json) {\n continue;\n }\n\n try {\n const session = JSON.parse(row.session_json) as SessionHead;\n upsertSessionRow(\n upsertSession,\n String(row.agent_name),\n session,\n row.meta_json ?? null,\n Number(row.sort_index ?? 0),\n sourcePathFromMetaJson(row.meta_json),\n );\n } catch {\n continue;\n }\n }\n }\n\n if (!tableExists(db, \"session_documents\")) {\n return;\n }\n\n const documentRows = db\n .prepare(\n `\n SELECT\n d.agent_name,\n d.session_id,\n d.slug,\n d.title,\n d.directory,\n d.project_identity_kind,\n d.project_identity_key,\n d.project_display_name,\n d.time_created,\n d.time_updated,\n d.activity_time,\n d.id\n FROM session_documents d\n LEFT JOIN sessions s ON s.agent_name = d.agent_name AND s.session_id = d.session_id\n WHERE s.session_id IS NULL\n ORDER BY d.id\n `,\n )\n .all() as ProjectBackfillDocumentRow[];\n\n for (const row of documentRows) {\n const directory = String(row.directory ?? \"\");\n const identity =\n row.project_identity_key && row.project_identity_kind && row.project_display_name\n ? {\n kind: row.project_identity_kind,\n key: String(row.project_identity_key),\n displayName: String(row.project_display_name),\n }\n : computeIdentity(directory, realFs);\n\n upsertSessionRow(\n upsertSession,\n String(row.agent_name),\n {\n id: String(row.session_id),\n slug: String(row.slug),\n title: String(row.title),\n directory,\n project_identity: identity,\n time_created: Number(row.time_created ?? row.activity_time ?? 0),\n time_updated: row.time_updated == null ? undefined : Number(row.time_updated),\n stats: {\n message_count: 0,\n total_input_tokens: 0,\n total_output_tokens: 0,\n total_cost: 0,\n },\n },\n null,\n Number(row.id ?? 0),\n null,\n );\n }\n}\n\nfunction backfillMessageTools(db: SQLiteDatabase): void {\n createMessageToolTables(db);\n if (!tableExists(db, \"messages\")) {\n return;\n }\n\n db.exec(\"DELETE FROM message_tools\");\n const rows = db\n .prepare(\n `\n SELECT agent_name, session_id, message_index, tool_metadata_json\n FROM messages\n WHERE tool_metadata_json IS NOT NULL\n `,\n )\n .all() as MessageToolBackfillRow[];\n const insertTool = prepareInsertMessageTool(db);\n\n for (const row of rows) {\n if (!row.agent_name || !row.session_id || row.message_index == null) {\n continue;\n }\n\n for (const toolName of toolNamesFromMetadataJson(row.tool_metadata_json)) {\n insertTool.run(row.agent_name, row.session_id, row.message_index, toolName);\n }\n }\n}\n\nfunction backfillFileActivity(db: SQLiteDatabase): void {\n createFileActivityTables(db);\n if (!tableExists(db, \"sessions\") || !tableExists(db, \"messages\")) {\n return;\n }\n\n const sessions = db\n .prepare(\n `\n SELECT agent_name, session_id, project_identity_key\n FROM sessions\n ORDER BY agent_name, session_id\n `,\n )\n .all() as SessionRow[];\n const loadMessages = db.prepare(`\n SELECT\n message_id,\n role,\n time_created,\n time_completed,\n agent,\n mode,\n model,\n provider,\n parts_json,\n subagent_id,\n nickname\n FROM messages\n WHERE agent_name = ? AND session_id = ?\n ORDER BY message_index\n `);\n const deleteActivity = db.prepare(\n \"DELETE FROM session_file_activity WHERE agent_name = ? AND session_id = ?\",\n );\n const insertActivity = prepareInsertFileActivity(db);\n\n for (const session of sessions) {\n if (!session.agent_name || !session.session_id || !session.project_identity_key) {\n continue;\n }\n\n try {\n const rows = loadMessages.all(session.agent_name, session.session_id) as MessageBackfillRow[];\n const messages = rows.map((row) => messageFromBackfillRow(row));\n const activities = extractSessionFileActivity(\n String(session.agent_name),\n String(session.session_id),\n String(session.project_identity_key),\n messages,\n );\n deleteActivity.run(session.agent_name, session.session_id);\n writeFileActivityRows(insertActivity, activities);\n } catch {\n continue;\n }\n }\n}\n\nfunction invalidateSearchContentHashes(db: SQLiteDatabase): void {\n if (\n tableExists(db, \"session_documents\") &&\n columnExists(db, \"session_documents\", \"content_hash\")\n ) {\n db.exec(\"UPDATE session_documents SET content_hash = ''\");\n }\n}\n\nfunction compactSessionDocuments(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_documents\")) {\n createSearchTables(db);\n return;\n }\n\n dropSearchTriggers(db);\n db.exec(`\n DROP TABLE IF EXISTS session_documents_fts;\n DROP TABLE IF EXISTS session_documents_legacy_v14;\n ALTER TABLE session_documents RENAME TO session_documents_legacy_v14;\n `);\n createSearchTables(db);\n db.exec(`\n INSERT INTO session_documents(\n id,\n agent_name,\n session_id,\n title,\n content_text,\n content_hash,\n indexed_message_count,\n indexed_at\n )\n SELECT\n id,\n agent_name,\n session_id,\n title,\n content_text,\n content_hash,\n indexed_message_count,\n indexed_at\n FROM session_documents_legacy_v14;\n\n DROP TABLE session_documents_legacy_v14;\n `);\n}\n\nfunction addMessagePartsFormatVersion(db: SQLiteDatabase): void {\n if (!tableExists(db, \"messages\") || columnExists(db, \"messages\", \"parts_format_version\")) {\n return;\n }\n db.exec(\"ALTER TABLE messages ADD COLUMN parts_format_version INTEGER NOT NULL DEFAULT 0\");\n}\n\nfunction addSessionParentReference(db: SQLiteDatabase): void {\n if (!tableExists(db, \"sessions\")) return;\n\n if (!columnExists(db, \"sessions\", \"parent_agent_name\")) {\n db.exec(\"ALTER TABLE sessions ADD COLUMN parent_agent_name TEXT\");\n }\n if (!columnExists(db, \"sessions\", \"parent_session_id\")) {\n db.exec(\"ALTER TABLE sessions ADD COLUMN parent_session_id TEXT\");\n }\n db.exec(\n \"CREATE INDEX IF NOT EXISTS idx_sessions_parent ON sessions(parent_agent_name, parent_session_id)\",\n );\n recreateProjectGroupsView(db);\n}\n\nconst CODEX_EXEC_DECODE_MIGRATION_KEY = \"codex_exec_decode_migrated_v3\";\n\n/**\n * One-time: mark every cached Codex detail as pending re-index so code-mode\n * exec decoding takes effect on upgrade. The search content hash derives only\n * from head-level fields, none of which the decoder touches, so nothing would\n * otherwise trigger a refresh. Session rows carry huge content_text, so\n * rewriting them (or clearing a hash) is slow; instead we record just the\n * session ids in the lightweight pending_reindex table. loadCachedSessionData\n * treats a marked session as pending and re-parses its detail fresh on view;\n * the search index clears the marker as it repopulates each one. Gated by a\n * cache_meta flag; a fresh cache just records it.\n */\nfunction migrateCodexExecDecode(db: SQLiteDatabase): void {\n if (!tableExists(db, \"cache_meta\")) return;\n const done = db\n .prepare(\"SELECT value FROM cache_meta WHERE key = ?\")\n .get(CODEX_EXEC_DECODE_MIGRATION_KEY);\n if (done) return;\n\n if (tableExists(db, \"sessions\") && tableExists(db, \"pending_reindex\")) {\n db.exec(\n \"INSERT OR IGNORE INTO pending_reindex(agent_name, session_id) \" +\n \"SELECT agent_name, session_id FROM sessions WHERE agent_name = 'codex'\",\n );\n }\n db.prepare(\n \"INSERT INTO cache_meta(key, value) VALUES (?, '1') ON CONFLICT(key) DO UPDATE SET value = '1'\",\n ).run(CODEX_EXEC_DECODE_MIGRATION_KEY);\n}\n\nconst OPENCODE_SUBAGENT_FOLD_KEY = \"opencode_subagent_fold_v1\";\nconst SUBAGENT_TREE_KEY = \"subagent_tree_v1\";\n\n/**\n * One-time: invalidate cached OpenCode-family (zcode/opencode) heads after the\n * subagent relation format changed. The next scan rebuilds parent references\n * and folded token totals from the source database.\n */\nfunction migrateOpenCodeSubagentFold(db: SQLiteDatabase): void {\n if (!tableExists(db, \"cache_meta\")) return;\n const done = db\n .prepare(\"SELECT value FROM cache_meta WHERE key = ?\")\n .get(OPENCODE_SUBAGENT_FOLD_KEY);\n if (done) return;\n\n if (tableExists(db, \"agent_cache\")) {\n db.prepare(\"DELETE FROM agent_cache WHERE agent_name IN ('zcode', 'opencode')\").run();\n }\n db.prepare(\n \"INSERT INTO cache_meta(key, value) VALUES (?, '1') ON CONFLICT(key) DO UPDATE SET value = '1'\",\n ).run(OPENCODE_SUBAGENT_FOLD_KEY);\n}\n\nfunction migrateSubagentTree(db: SQLiteDatabase): void {\n if (!tableExists(db, \"cache_meta\")) return;\n const done = db.prepare(\"SELECT value FROM cache_meta WHERE key = ?\").get(SUBAGENT_TREE_KEY);\n if (done) return;\n\n if (tableExists(db, \"agent_cache\")) {\n db.prepare(\"DELETE FROM agent_cache WHERE agent_name IN ('codex', 'zcode', 'opencode')\").run();\n }\n db.prepare(\n \"INSERT INTO cache_meta(key, value) VALUES (?, '1') ON CONFLICT(key) DO UPDATE SET value = '1'\",\n ).run(SUBAGENT_TREE_KEY);\n}\n\nfunction rebuildSearchIndex(db: SQLiteDatabase): void {\n if (!tableExists(db, \"session_documents_fts\")) {\n return;\n }\n db.exec(\"INSERT INTO session_documents_fts(session_documents_fts) VALUES ('rebuild')\");\n}\n\nfunction rebuildMessageSearchIndex(db: SQLiteDatabase): void {\n if (!tableExists(db, \"messages_fts\")) {\n return;\n }\n db.exec(\"INSERT INTO messages_fts(messages_fts) VALUES ('rebuild')\");\n}\n\nconst SEARCH_FTS_INDEXES = [\"session_documents_fts\", \"messages_fts\"] as const;\n\ntype SearchFtsIndex = (typeof SEARCH_FTS_INDEXES)[number];\n\nfunction triggerExists(db: SQLiteDatabase, triggerName: string): boolean {\n return (\n db\n .prepare(\"SELECT 1 AS value FROM sqlite_master WHERE name = ? AND type = 'trigger' LIMIT 1\")\n .get(triggerName) !== undefined\n );\n}\n\nfunction hasAllTriggers(db: SQLiteDatabase, triggerNames: string[]): boolean {\n return triggerNames.every((triggerName) => triggerExists(db, triggerName));\n}\n\nfunction rebuildSearchFtsIndexes(\n db: SQLiteDatabase,\n indexes: SearchFtsIndex[],\n reason: \"corruption\" | \"schema_missing\",\n): void {\n if (indexes.length === 0) return;\n\n const startedAt = performance.now();\n getCoreDiagnostics()?.info?.(\"sqlite.fts_rebuild.started\", { indexes, reason });\n try {\n for (const index of indexes) {\n if (index === \"session_documents_fts\") rebuildSearchIndex(db);\n else rebuildMessageSearchIndex(db);\n }\n getCoreDiagnostics()?.info?.(\"sqlite.fts_rebuild.completed\", {\n indexes,\n reason,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n } catch (error) {\n getCoreDiagnostics()?.warn(\"sqlite.fts_rebuild.failed\", {\n indexes,\n reason,\n duration_ms: Math.round(performance.now() - startedAt),\n message: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n}\n\nfunction ensureFtsReady(db: SQLiteDatabase): void {\n const needsSearchRebuild =\n !tableExists(db, \"session_documents_fts\") ||\n !hasAllTriggers(db, [\"session_documents_ai\", \"session_documents_ad\", \"session_documents_au\"]);\n const needsMessageSearchRebuild =\n !tableExists(db, \"messages_fts\") ||\n !hasAllTriggers(db, [\"messages_ai\", \"messages_ad\", \"messages_au\"]);\n\n createSearchTables(db);\n createMessageSearchTables(db);\n\n const indexes: SearchFtsIndex[] = [];\n if (needsSearchRebuild) indexes.push(\"session_documents_fts\");\n if (needsMessageSearchRebuild) indexes.push(\"messages_fts\");\n rebuildSearchFtsIndexes(db, indexes, \"schema_missing\");\n}\n\nfunction ensureFtsConsistency(db: SQLiteDatabase): void {\n const startedAt = performance.now();\n getCoreDiagnostics()?.info?.(\"sqlite.fts_integrity.started\", {\n indexes: 2,\n });\n try {\n db.exec(\n \"INSERT INTO session_documents_fts(session_documents_fts, rank) VALUES ('integrity-check', 1)\",\n );\n db.exec(\"INSERT INTO messages_fts(messages_fts, rank) VALUES ('integrity-check', 1)\");\n getCoreDiagnostics()?.info?.(\"sqlite.fts_integrity.completed\", {\n indexes: 2,\n duration_ms: Math.round(performance.now() - startedAt),\n });\n } catch (error) {\n getCoreDiagnostics()?.warn(\"sqlite.fts_integrity.failed\", {\n indexes: 2,\n duration_ms: Math.round(performance.now() - startedAt),\n message: error instanceof Error ? error.message : String(error),\n });\n rebuildSearchFtsIndexes(db, [...SEARCH_FTS_INDEXES], \"corruption\");\n }\n}\n\nfunction isFtsCorruptionError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n error.code === \"SQLITE_CORRUPT_VTAB\"\n );\n}\n\nfunction runWithFtsRecovery<T>(db: SQLiteDatabase, fn: (db: SQLiteDatabase) => T): T {\n ensureFtsReady(db);\n try {\n return fn(db);\n } catch (error) {\n if (!isFtsCorruptionError(error)) throw error;\n getCoreDiagnostics()?.warn(\"sqlite.fts_corruption.detected\", {\n message: error instanceof Error ? error.message : String(error),\n });\n ensureFtsConsistency(db);\n return fn(db);\n }\n}\n\nfunction setCacheSchemaVersion(db: SQLiteDatabase): void {\n createCacheTables(db);\n setUserVersion(db, CACHE_SCHEMA_VERSION);\n db.prepare(\n `\n INSERT INTO cache_meta(key, value)\n VALUES ('version', ?)\n ON CONFLICT(key) DO UPDATE SET value = excluded.value\n `,\n ).run(String(CACHE_SCHEMA_VERSION));\n}\n\nfunction ensureSchema(db: SQLiteDatabase, dbPath: string): void {\n const currentVersion = getCurrentCacheSchemaVersion(db);\n if (currentVersion === 0 && !hasAnyCacheSchema(db)) {\n createLatestCacheSchema(db);\n setCacheSchemaVersion(db);\n migrateCodexExecDecode(db);\n migrateOpenCodeSubagentFold(db);\n migrateSubagentTree(db);\n return;\n }\n\n runSchemaMigrations(db, {\n dbPath,\n currentVersion,\n targetVersion: CACHE_SCHEMA_VERSION,\n backupLabel: \"cache-migration\",\n backupTables: [\n \"agent_cache\",\n \"cache_initialization\",\n \"cached_sessions\",\n \"sessions\",\n \"messages\",\n \"message_tools\",\n \"session_file_activity\",\n \"session_documents\",\n \"project_sessions\",\n ],\n migrations: [\n { version: 3, migrate: createCacheTables },\n { version: 4, migrate: createSearchTables },\n { version: 5, migrate: migrateProjectIdentity },\n {\n version: 6,\n destructive: true,\n migrate(db) {\n createLatestCacheSchema(db);\n recreateSearchIndexSchema(db);\n invalidateSearchContentHashes(db);\n },\n },\n {\n version: 7,\n migrate(db) {\n addSessionParentReference(db);\n backfillStructuredSessions(db);\n },\n },\n { version: 8, migrate: backfillFileActivity },\n {\n version: 9,\n migrate(db) {\n createMessageSearchTables(db);\n rebuildMessageSearchIndex(db);\n },\n },\n {\n version: 10,\n migrate(db) {\n createFileActivityPathSearchTables(db);\n rebuildFileActivityPathIndex(db);\n },\n },\n {\n version: 11,\n migrate(db) {\n backfillMessageTools(db);\n },\n },\n {\n version: 12,\n migrate(db) {\n refreshProjectIdentities(db);\n },\n },\n { version: 13, migrate: createCacheTables },\n { version: 14, migrate: addIndexedMessageCount },\n { version: 15, destructive: true, migrate: compactSessionDocuments },\n { version: 17, migrate: addMessagePartsFormatVersion },\n { version: 18, migrate: addSessionParentReference },\n ],\n });\n\n createLatestCacheSchema(db);\n\n if (getUserVersion(db) <= CACHE_SCHEMA_VERSION) {\n setCacheSchemaVersion(db);\n }\n\n migrateCodexExecDecode(db);\n migrateOpenCodeSubagentFold(db);\n migrateSubagentTree(db);\n}\n","import type { FileActivityKind, ProjectIdentityKind, SmartTag } from \"../../types/index.js\";\nimport { isProjectIdentityKind } from \"../../projects/index.js\";\n\nexport interface SearchQueryFilters {\n agent?: string;\n project?: string;\n projectKind?: ProjectIdentityKind;\n projectKey?: string;\n cwd?: string;\n tags?: SmartTag[];\n tools?: string[];\n file?: string;\n fileKind?: FileActivityKind;\n costMin?: number;\n costMax?: number;\n costMinExclusive?: boolean;\n costMaxExclusive?: boolean;\n}\n\nexport interface ParsedSearchQuery {\n text: string;\n filters: SearchQueryFilters;\n hasQualifiers: boolean;\n}\n\nfunction escapeFtsTerm(value: string): string {\n return value.replaceAll('\"', '\"\"');\n}\n\nexport function splitSearchTokens(input: string): string[] {\n const tokens: string[] = [];\n let token = \"\";\n let inQuote = false;\n\n for (const char of input) {\n if (char === '\"') {\n inQuote = !inQuote;\n token += char;\n continue;\n }\n if (/\\s/.test(char) && !inQuote) {\n if (token) {\n tokens.push(token);\n token = \"\";\n }\n continue;\n }\n token += char;\n }\n\n if (token) tokens.push(token);\n return tokens;\n}\n\nexport function unwrapSearchValue(value: string): string {\n const trimmed = value.trim();\n if (trimmed.startsWith('\"') && trimmed.endsWith('\"')) {\n return trimmed.slice(1, -1).trim();\n }\n return trimmed;\n}\n\nfunction parseCostQualifier(value: string, filters: SearchQueryFilters): void {\n const raw = unwrapSearchValue(value);\n const range = raw.match(/^(\\d+(?:\\.\\d+)?)\\.\\.(\\d+(?:\\.\\d+)?)$/);\n if (range) {\n filters.costMin = Number(range[1]);\n filters.costMax = Number(range[2]);\n return;\n }\n\n const comparison = raw.match(/^(>=|>|<=|<)(\\d+(?:\\.\\d+)?)$/);\n if (comparison) {\n const amount = Number(comparison[2]);\n if (comparison[1]?.includes(\">\")) {\n filters.costMin = amount;\n filters.costMinExclusive = comparison[1] === \">\";\n } else {\n filters.costMax = amount;\n filters.costMaxExclusive = comparison[1] === \"<\";\n }\n return;\n }\n\n const amount = Number(raw);\n if (!Number.isNaN(amount)) {\n filters.costMin = amount;\n filters.costMax = amount;\n }\n}\n\nfunction appendUnique<T>(values: T[] | undefined, value: T): T[] {\n if (values?.includes(value)) return values;\n return [...(values ?? []), value];\n}\n\nfunction isSmartTag(value: string): value is SmartTag {\n return (\n value === \"bugfix\" ||\n value === \"refactoring\" ||\n value === \"feature-dev\" ||\n value === \"testing\" ||\n value === \"docs\" ||\n value === \"git-ops\" ||\n value === \"build-deploy\" ||\n value === \"exploration\" ||\n value === \"planning\"\n );\n}\n\nexport function parseSearchQuery(input: string): ParsedSearchQuery {\n const filters: SearchQueryFilters = {};\n const textTokens: string[] = [];\n let hasQualifiers = false;\n\n for (const token of splitSearchTokens(input)) {\n const match = token.match(/^([a-zA-Z][a-zA-Z_-]*):(.+)$/);\n if (!match) {\n textTokens.push(token);\n continue;\n }\n\n const key = match[1]!.toLowerCase();\n const value = unwrapSearchValue(match[2]!);\n if (!value) continue;\n\n let consumed = true;\n if (key === \"agent\") filters.agent = value.toLowerCase();\n else if (key === \"project\") filters.project = value;\n else if (key === \"projectkey\" || key === \"project-key\") filters.projectKey = value;\n else if (key === \"projectkind\" || key === \"project-kind\") {\n if (isProjectIdentityKind(value)) filters.projectKind = value;\n else consumed = false;\n } else if (key === \"cwd\") filters.cwd = value;\n else if (key === \"tool\") filters.tools = appendUnique(filters.tools, value.toLowerCase());\n else if (key === \"file\" || key === \"path\") filters.file = value;\n else if (key === \"kind\" || key === \"filekind\" || key === \"file-kind\") {\n if (value === \"read\" || value === \"edit\" || value === \"write\" || value === \"delete\") {\n filters.fileKind = value;\n } else {\n consumed = false;\n }\n } else if (key === \"tag\" || key === \"signal\") {\n const tag = value.toLowerCase();\n if (isSmartTag(tag)) filters.tags = appendUnique(filters.tags, tag);\n else consumed = false;\n } else if (key === \"cost\") {\n parseCostQualifier(value, filters);\n } else {\n consumed = false;\n }\n\n if (consumed) hasQualifiers = true;\n else textTokens.push(token);\n }\n\n return {\n text: textTokens.join(\" \").trim(),\n filters,\n hasQualifiers,\n };\n}\n\nexport function toFtsQuery(input: string): string {\n const tokens = splitSearchTokens(input);\n return tokens\n .map((token) => {\n if (/^OR$/i.test(token)) return \"OR\";\n if (token.startsWith('\"') && token.endsWith('\"')) {\n return `\"${escapeFtsTerm(token.slice(1, -1))}\"`;\n }\n return `\"${escapeFtsTerm(token)}\"`;\n })\n .filter(\n (token, index, values) =>\n token !== \"OR\" ||\n (index > 0 &&\n index < values.length - 1 &&\n values[index - 1] !== \"OR\" &&\n values[index + 1] !== \"OR\"),\n )\n .join(\" \");\n}\n","import type { SessionDetail, SessionFileActivity, SessionHead } from \"../../types/index.js\";\nimport { computeIdentity, realFs } from \"../../projects/index.js\";\nimport { extractSessionFileActivity } from \"../../utils/file-activity.js\";\nimport type { SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { SEARCH_INDEX_BULK_SYNC_THRESHOLD, type SessionHeadChange } from \"./db.js\";\nimport {\n buildSessionContentFromMessages,\n MESSAGE_PARTS_FORMAT_VERSION,\n normalizeMessages,\n prepareInsertFileActivity,\n prepareInsertMessageTool,\n prepareUpsertIndexedSession,\n upsertSessionRow,\n writeFileActivityRows,\n type StructuredMessageRecord,\n} from \"./messages.js\";\nimport { runSearchIndexWrite, withSearchIndexDb } from \"./schema.js\";\n\nexport interface SearchIndexSyncOptions {\n isBulk?: boolean;\n bulkThreshold?: number;\n}\n\nexport interface SearchIndexSyncResult {\n agentName: string;\n mode: \"bulk\" | \"incremental\";\n sessions: number;\n changed: number;\n deleted: number;\n indexed: number;\n skipped: number;\n durationMs: number;\n rebuildDurationMs?: number;\n}\n\ninterface SearchIndexState {\n contentHashBySessionId: Map<string, string>;\n indexedMessageCountBySessionId: Map<string, number>;\n messageCountBySessionId: Map<string, number>;\n pendingReindexSessionIds: Set<string>;\n}\n\ninterface IndexedSearchRow {\n session_id?: string;\n content_hash?: string;\n indexed_message_count?: number;\n}\n\ninterface MessageCountRow {\n session_id?: string;\n value?: number;\n}\n\nfunction readPendingReindexIds(db: SQLiteDatabase, agentName: string): Set<string> {\n const rows = db\n .prepare(\"SELECT session_id FROM pending_reindex WHERE agent_name = ?\")\n .all(agentName) as Array<{ session_id?: string }>;\n return new Set(rows.map((row) => String(row.session_id)));\n}\n\ntype SearchIndexStateRow = IndexedSearchRow & MessageCountRow;\n\nconst SEARCH_INDEX_STATE_BATCH_SIZE = 900;\nconst SEARCH_INDEX_COMMIT_CHUNK_SIZE = 64;\n\ninterface LoadedSearchIndexEntry {\n session: SessionHead;\n messages: StructuredMessageRecord[];\n contentText: string;\n contentHash: string;\n fileActivity: SessionFileActivity[];\n sortIndex: number;\n}\n\nfunction shouldBulkSyncSearchIndex(options: SearchIndexSyncOptions, changedCount: number): boolean {\n if (options.isBulk != null) {\n return options.isBulk;\n }\n\n const threshold = options.bulkThreshold ?? SEARCH_INDEX_BULK_SYNC_THRESHOLD;\n return threshold > 0 && changedCount >= threshold;\n}\n\nfunction sessionContentHash(session: SessionHead): string {\n return JSON.stringify([\n session.slug,\n session.title,\n session.directory,\n session.time_created,\n session.time_updated ?? session.time_created,\n session.stats.message_count,\n session.stats.total_input_tokens,\n session.stats.total_output_tokens,\n session.stats.total_cache_read_tokens ?? 0,\n session.stats.total_cache_create_tokens ?? 0,\n session.stats.total_cost,\n session.stats.cost_source ?? \"\",\n session.stats.total_tokens ?? 0,\n ]);\n}\n\nfunction searchIndexStateFromRows(\n indexedRows: IndexedSearchRow[],\n messageCountRows: MessageCountRow[],\n pendingReindexSessionIds: Set<string> = new Set(),\n): SearchIndexState {\n return {\n contentHashBySessionId: new Map(\n indexedRows.map((row) => [String(row.session_id), String(row.content_hash ?? \"\")]),\n ),\n indexedMessageCountBySessionId: new Map(\n indexedRows.map((row) => [String(row.session_id), Number(row.indexed_message_count ?? 0)]),\n ),\n messageCountBySessionId: new Map(\n messageCountRows.map((row) => [String(row.session_id), Number(row.value ?? 0)]),\n ),\n pendingReindexSessionIds,\n };\n}\n\nfunction readSearchIndexState(\n db: SQLiteDatabase,\n agentName: string,\n sessionIds: string[],\n): SearchIndexState {\n const rows: SearchIndexStateRow[] = [];\n const uniqueSessionIds = [...new Set(sessionIds)];\n\n for (let offset = 0; offset < uniqueSessionIds.length; offset += SEARCH_INDEX_STATE_BATCH_SIZE) {\n const batch = uniqueSessionIds.slice(offset, offset + SEARCH_INDEX_STATE_BATCH_SIZE);\n const requestedRows = batch.map(() => \"(?)\").join(\", \");\n const batchRows = db\n .prepare(\n `\n WITH requested_session_ids(session_id) AS (VALUES ${requestedRows})\n SELECT\n requested.session_id,\n documents.content_hash,\n documents.indexed_message_count,\n COUNT(messages.message_index) AS value\n FROM requested_session_ids AS requested\n LEFT JOIN session_documents AS documents\n ON documents.agent_name = ? AND documents.session_id = requested.session_id\n LEFT JOIN messages\n ON messages.agent_name = ? AND messages.session_id = requested.session_id\n GROUP BY\n requested.session_id,\n documents.content_hash,\n documents.indexed_message_count\n `,\n )\n .all(...batch, agentName, agentName) as SearchIndexStateRow[];\n rows.push(...batchRows);\n }\n\n return searchIndexStateFromRows(rows, rows, readPendingReindexIds(db, agentName));\n}\n\nfunction searchIndexEntryNeedsUpdate(state: SearchIndexState, session: SessionHead): boolean {\n const sessionId = session.id;\n return (\n state.pendingReindexSessionIds.has(sessionId) ||\n state.contentHashBySessionId.get(sessionId) !== sessionContentHash(session) ||\n state.indexedMessageCountBySessionId.get(sessionId) !==\n (state.messageCountBySessionId.get(sessionId) ?? 0)\n );\n}\n\nfunction loadSearchIndexEntry(\n agentName: string,\n change: SessionHeadChange,\n loadSessionData: (sessionId: string) => SessionDetail,\n): LoadedSearchIndexEntry | null {\n try {\n const data = loadSessionData(change.session.id);\n const messages = normalizeMessages(data);\n const identity =\n change.session.project_identity ??\n data.project_identity ??\n computeIdentity(change.session.directory, realFs);\n return {\n session: change.session,\n messages,\n contentText: buildSessionContentFromMessages(data.title ?? change.session.title, messages),\n contentHash: sessionContentHash(change.session),\n fileActivity: extractSessionFileActivity(\n agentName,\n change.session.id,\n identity.key,\n data.messages,\n ),\n sortIndex: change.sortIndex,\n };\n } catch {\n return null;\n }\n}\n\nfunction* loadSearchIndexEntries(\n agentName: string,\n changes: Iterable<SessionHeadChange>,\n loadSessionData: (sessionId: string) => SessionDetail,\n): Generator<LoadedSearchIndexEntry> {\n for (const change of changes) {\n const entry = loadSearchIndexEntry(agentName, change, loadSessionData);\n if (entry) yield entry;\n }\n}\n\nfunction writeSearchIndexRows(\n db: SQLiteDatabase,\n agentName: string,\n removedSessionIds: string[],\n entries: Iterable<LoadedSearchIndexEntry>,\n): number {\n const deleteRow = db.prepare(\n \"DELETE FROM session_documents WHERE agent_name = ? AND session_id = ?\",\n );\n const deleteMessages = db.prepare(\n \"DELETE FROM messages WHERE agent_name = ? AND session_id = ? AND message_index >= ?\",\n );\n const deleteMessageTools = db.prepare(\n \"DELETE FROM message_tools WHERE agent_name = ? AND session_id = ? AND message_index >= ?\",\n );\n const deleteFileActivity = db.prepare(\n \"DELETE FROM session_file_activity WHERE agent_name = ? AND session_id = ?\",\n );\n const upsertIndexedSession = prepareUpsertIndexedSession(db);\n const insertFileActivity = prepareInsertFileActivity(db);\n const insertMessageTool = prepareInsertMessageTool(db);\n const upsertMessage = db.prepare(`\n INSERT INTO messages(\n agent_name,\n session_id,\n message_index,\n message_id,\n role,\n time_created,\n time_completed,\n agent,\n mode,\n model,\n provider,\n tokens_json,\n cost,\n cost_source,\n parts_json,\n parts_format_version,\n subagent_id,\n nickname,\n content_text,\n tool_metadata_json\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id, message_index) DO UPDATE SET\n message_id = excluded.message_id,\n role = excluded.role,\n time_created = excluded.time_created,\n time_completed = excluded.time_completed,\n agent = excluded.agent,\n mode = excluded.mode,\n model = excluded.model,\n provider = excluded.provider,\n tokens_json = excluded.tokens_json,\n cost = excluded.cost,\n cost_source = excluded.cost_source,\n parts_json = excluded.parts_json,\n parts_format_version = excluded.parts_format_version,\n subagent_id = excluded.subagent_id,\n nickname = excluded.nickname,\n content_text = excluded.content_text,\n tool_metadata_json = excluded.tool_metadata_json\n `);\n const upsertRow = db.prepare(`\n INSERT INTO session_documents(\n agent_name,\n session_id,\n title,\n content_text,\n content_hash,\n indexed_message_count,\n indexed_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n title = excluded.title,\n content_text = excluded.content_text,\n content_hash = excluded.content_hash,\n indexed_message_count = excluded.indexed_message_count,\n indexed_at = excluded.indexed_at\n `);\n\n const clearPendingReindex = db.prepare(\n \"DELETE FROM pending_reindex WHERE agent_name = ? AND session_id = ?\",\n );\n\n for (const sessionId of new Set(removedSessionIds)) {\n deleteRow.run(agentName, sessionId);\n deleteFileActivity.run(agentName, sessionId);\n deleteMessageTools.run(agentName, sessionId, 0);\n deleteMessages.run(agentName, sessionId, 0);\n clearPendingReindex.run(agentName, sessionId);\n }\n\n let indexed = 0;\n for (const entry of entries) {\n upsertSessionRow(upsertIndexedSession, agentName, entry.session, null, entry.sortIndex, null);\n deleteFileActivity.run(agentName, entry.session.id);\n deleteMessageTools.run(agentName, entry.session.id, 0);\n clearPendingReindex.run(agentName, entry.session.id);\n writeFileActivityRows(insertFileActivity, entry.fileActivity);\n for (const message of entry.messages) {\n upsertMessage.run(\n agentName,\n entry.session.id,\n message.index,\n message.id,\n message.role,\n message.timeCreated,\n message.timeCompleted ?? null,\n message.agent ?? null,\n message.mode ?? null,\n message.model ?? null,\n message.provider ?? null,\n message.tokensJson ?? null,\n message.cost ?? null,\n message.costSource ?? null,\n message.partsJson,\n MESSAGE_PARTS_FORMAT_VERSION,\n message.subagentId ?? null,\n message.nickname ?? null,\n message.contentText,\n message.toolMetadataJson ?? null,\n );\n for (const toolName of message.toolNames) {\n insertMessageTool.run(agentName, entry.session.id, message.index, toolName);\n }\n }\n deleteMessages.run(agentName, entry.session.id, entry.messages.length);\n upsertRow.run(\n agentName,\n entry.session.id,\n entry.session.title,\n entry.contentText,\n entry.contentHash,\n entry.messages.length,\n Date.now(),\n );\n indexed += 1;\n }\n return indexed;\n}\n\nexport function syncSessionSearchIndex(\n agentName: string,\n sessions: SessionHead[],\n loadSessionData: (sessionId: string) => SessionDetail,\n options: SearchIndexSyncOptions = {},\n): SearchIndexSyncResult | null {\n return withSearchIndexDb((db) => {\n const startedAt = performance.now();\n const existingRows = db\n .prepare(\n \"SELECT session_id, content_hash, indexed_message_count FROM session_documents WHERE agent_name = ? ORDER BY id\",\n )\n .all(agentName) as IndexedSearchRow[];\n const sessionSortIndexMap = new Map(sessions.map((session, index) => [session.id, index]));\n const messageCountRows = db\n .prepare(\n \"SELECT session_id, COUNT(*) AS value FROM messages WHERE agent_name = ? GROUP BY session_id\",\n )\n .all(agentName) as MessageCountRow[];\n const searchIndexState = searchIndexStateFromRows(\n existingRows,\n messageCountRows,\n readPendingReindexIds(db, agentName),\n );\n const sessionMap = new Map(sessions.map((session) => [session.id, session]));\n\n const toDelete = existingRows\n .map((row) => String(row.session_id))\n .filter((sessionId) => !sessionMap.has(sessionId));\n const toUpsert = sessions.filter((session) =>\n searchIndexEntryNeedsUpdate(searchIndexState, session),\n );\n const changedCount = toDelete.length + toUpsert.length;\n const isBulk = shouldBulkSyncSearchIndex(options, changedCount);\n const changes = toUpsert.map((session) => ({\n session,\n sortIndex: sessionSortIndexMap.get(session.id) ?? 0,\n }));\n let indexed = 0;\n\n // A large backlog (e.g. the first full-history backfill) takes minutes to\n // parse; one transaction would roll all of it back on interrupt. Chunked\n // commits keep the FTS triggers active so every chunk is durable, and a\n // restarted sync skips already-indexed sessions via their content hashes.\n if (changes.length > SEARCH_INDEX_COMMIT_CHUNK_SIZE) {\n runSearchIndexWrite(db, false, () => {\n indexed += writeSearchIndexRows(db, agentName, toDelete, []);\n });\n for (let offset = 0; offset < changes.length; offset += SEARCH_INDEX_COMMIT_CHUNK_SIZE) {\n const chunk = changes.slice(offset, offset + SEARCH_INDEX_COMMIT_CHUNK_SIZE);\n runSearchIndexWrite(db, false, () => {\n indexed += writeSearchIndexRows(\n db,\n agentName,\n [],\n loadSearchIndexEntries(agentName, chunk, loadSessionData),\n );\n });\n }\n return {\n agentName,\n mode: \"incremental\",\n sessions: sessions.length,\n changed: toUpsert.length,\n deleted: toDelete.length,\n indexed,\n skipped: toUpsert.length - indexed,\n durationMs: performance.now() - startedAt,\n };\n }\n\n const writeRows = () => {\n indexed = writeSearchIndexRows(\n db,\n agentName,\n toDelete,\n loadSearchIndexEntries(agentName, changes, loadSessionData),\n );\n };\n\n const needsRebuild = isBulk && changedCount > 0;\n const { rebuildDurationMs } = runSearchIndexWrite(db, needsRebuild, writeRows);\n\n return {\n agentName,\n mode: isBulk ? \"bulk\" : \"incremental\",\n sessions: sessions.length,\n changed: toUpsert.length,\n deleted: toDelete.length,\n indexed,\n skipped: toUpsert.length - indexed,\n durationMs: performance.now() - startedAt,\n rebuildDurationMs,\n };\n });\n}\n\nexport function syncSessionSearchIndexChanges(\n agentName: string,\n changes: SessionHeadChange[],\n removedSessionIds: string[],\n loadSessionData: (sessionId: string) => SessionDetail,\n options: SearchIndexSyncOptions = {},\n): SearchIndexSyncResult | null {\n if (changes.length === 0 && removedSessionIds.length === 0) {\n return {\n agentName,\n mode: \"incremental\",\n sessions: 0,\n changed: 0,\n deleted: 0,\n indexed: 0,\n skipped: 0,\n durationMs: 0,\n };\n }\n\n return withSearchIndexDb((db) => {\n const startedAt = performance.now();\n const searchIndexState = readSearchIndexState(\n db,\n agentName,\n changes.map(({ session }) => session.id),\n );\n const toUpsert = changes.filter(({ session }) =>\n searchIndexEntryNeedsUpdate(searchIndexState, session),\n );\n const uniqueRemovedSessionIds = Array.from(new Set(removedSessionIds));\n const changedCount = uniqueRemovedSessionIds.length + toUpsert.length;\n const isBulk = shouldBulkSyncSearchIndex(options, changedCount);\n let indexed = 0;\n const writeRows = () => {\n indexed = writeSearchIndexRows(\n db,\n agentName,\n uniqueRemovedSessionIds,\n loadSearchIndexEntries(agentName, toUpsert, loadSessionData),\n );\n };\n\n const needsRebuild = isBulk && changedCount > 0;\n const { rebuildDurationMs } = runSearchIndexWrite(db, needsRebuild, writeRows);\n\n return {\n agentName,\n mode: isBulk ? \"bulk\" : \"incremental\",\n sessions: changes.length,\n changed: toUpsert.length,\n deleted: uniqueRemovedSessionIds.length,\n indexed,\n skipped: toUpsert.length - indexed,\n durationMs: performance.now() - startedAt,\n rebuildDurationMs,\n };\n });\n}\n","/**\n * Full-text query reader and the stable search cache export surface.\n */\nimport type {\n FileActivityKind,\n Message,\n ProjectIdentityKind,\n SessionHead,\n SmartTag,\n} from \"../../types/index.js\";\nimport type { SearchMatchType, SearchResult } from \"../../contract/index.js\";\nimport { computeIdentity, realFs } from \"../../projects/index.js\";\nimport type { DatabaseRow, SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { escapeRegExp, filePathFtsQuery, hasCacheStorage, likePattern } from \"./db.js\";\nimport { normalizeToolName, sessionFromRow, type SessionRow } from \"./messages.js\";\nimport { withSearchDb } from \"./schema.js\";\nimport {\n parseSearchQuery,\n splitSearchTokens,\n toFtsQuery,\n unwrapSearchValue,\n type ParsedSearchQuery,\n type SearchQueryFilters,\n} from \"./search-query-parser.js\";\n\ninterface MessageSearchRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n message_index?: number;\n role?: Message[\"role\"];\n mode?: string | null;\n content_text?: string;\n tool_metadata_json?: string | null;\n}\n\nexport interface SearchResultRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n slug?: string;\n title?: string;\n directory?: string;\n project_identity_kind?: ProjectIdentityKind;\n project_identity_key?: string;\n project_display_name?: string;\n time_created?: number;\n time_updated?: number | null;\n message_count?: number;\n total_input_tokens?: number;\n total_output_tokens?: number;\n total_cache_read_tokens?: number | null;\n total_cache_create_tokens?: number | null;\n total_cost?: number;\n cost_source?: string | null;\n total_tokens?: number | null;\n model_usage_json?: string | null;\n smart_tags_json?: string | null;\n smart_tags_source_updated_at?: number | null;\n snippet?: string | null;\n}\n\nexport type { SearchMatchType, SearchResult };\n\nexport { parseSearchQuery, type ParsedSearchQuery, type SearchQueryFilters };\n\nexport interface SearchOptions {\n agent?: string;\n project?: string;\n projectKind?: ProjectIdentityKind;\n projectKey?: string;\n cwd?: string;\n tags?: SmartTag[];\n tools?: string[];\n file?: string;\n fileKind?: FileActivityKind;\n costMin?: number;\n costMax?: number;\n costMinExclusive?: boolean;\n costMaxExclusive?: boolean;\n from?: number;\n to?: number;\n limit?: number;\n}\n\nexport {\n syncSessionSearchIndex,\n syncSessionSearchIndexChanges,\n type SearchIndexSyncOptions,\n type SearchIndexSyncResult,\n} from \"./search-index-writer.js\";\n\nexport function sessionHeadFromSearchRow(row: SearchResultRow): SessionHead {\n return sessionFromRow(row as SessionRow);\n}\n\nexport function mergeSearchLists<T>(\n left: T[] | undefined,\n right: T[] | undefined,\n): T[] | undefined {\n const values = [...(left ?? []), ...(right ?? [])];\n return values.length > 0 ? [...new Set(values)] : undefined;\n}\n\nexport function mergeSearchQueryOptions(query: string, options: SearchOptions) {\n const parsed = parseSearchQuery(query);\n return {\n text: parsed.text || (parsed.hasQualifiers ? \"\" : query.trim()),\n options: {\n ...options,\n agent: options.agent ?? parsed.filters.agent,\n project: options.project ?? parsed.filters.project,\n projectKind: options.projectKind ?? parsed.filters.projectKind,\n projectKey: options.projectKey ?? parsed.filters.projectKey,\n cwd: options.cwd ?? parsed.filters.cwd,\n tags: mergeSearchLists(options.tags, parsed.filters.tags),\n tools: mergeSearchLists(options.tools, parsed.filters.tools),\n file: options.file ?? parsed.filters.file,\n fileKind: options.fileKind ?? parsed.filters.fileKind,\n costMin: options.costMin ?? parsed.filters.costMin,\n costMax: options.costMax ?? parsed.filters.costMax,\n costMinExclusive: options.costMinExclusive ?? parsed.filters.costMinExclusive,\n costMaxExclusive: options.costMaxExclusive ?? parsed.filters.costMaxExclusive,\n },\n parsed,\n };\n}\n\nexport function sessionMatchesSearchCost(session: SessionHead, options: SearchOptions): boolean {\n const cost = session.stats.total_cost;\n if (options.costMin != null) {\n if (options.costMinExclusive ? cost <= options.costMin : cost < options.costMin) {\n return false;\n }\n }\n if (options.costMax != null) {\n if (options.costMaxExclusive ? cost >= options.costMax : cost > options.costMax) {\n return false;\n }\n }\n return true;\n}\n\nexport function buildSessionSearchFilters(options: SearchOptions): {\n where: string;\n params: unknown[];\n} {\n const clauses: string[] = [];\n const params: unknown[] = [];\n\n if (options.agent) {\n clauses.push(\"s.agent_name = ?\");\n params.push(options.agent);\n }\n if (options.projectKind || options.projectKey) {\n if (options.projectKind && options.projectKey) {\n clauses.push(\"s.project_identity_kind = ? AND s.project_identity_key = ?\");\n params.push(options.projectKind, options.projectKey);\n } else {\n clauses.push(\"0\");\n }\n }\n if (options.cwd) {\n const identity = computeIdentity(options.cwd, realFs);\n clauses.push(\n \"((s.project_identity_kind = ? AND s.project_identity_key = ?) OR LOWER(s.directory) LIKE ? ESCAPE '\\\\')\",\n );\n params.push(identity.kind, identity.key, likePattern(options.cwd));\n }\n if (options.project) {\n clauses.push(\n \"(LOWER(s.project_identity_key) LIKE ? ESCAPE '\\\\' OR LOWER(s.project_display_name) LIKE ? ESCAPE '\\\\' OR LOWER(s.directory) LIKE ? ESCAPE '\\\\')\",\n );\n const pattern = likePattern(options.project);\n params.push(pattern, pattern, pattern);\n }\n for (const tag of options.tags ?? []) {\n clauses.push(\"s.smart_tags_json LIKE ?\");\n params.push(`%\"${tag}\"%`);\n }\n for (const tool of options.tools ?? []) {\n const toolName = normalizeToolName(tool);\n if (!toolName) continue;\n clauses.push(\n \"EXISTS (SELECT 1 FROM message_tools mt WHERE mt.tool_name = ? AND mt.agent_name = s.agent_name AND mt.session_id = s.session_id)\",\n );\n params.push(toolName);\n }\n if (options.file || options.fileKind) {\n const fileClauses = [\"fa.agent_name = s.agent_name\", \"fa.session_id = s.session_id\"];\n if (options.file) {\n const pathQuery = filePathFtsQuery(options.file);\n if (pathQuery) {\n fileClauses.push(\n \"fa.rowid IN (SELECT rowid FROM session_file_activity_path_fts WHERE path MATCH ?)\",\n );\n params.push(pathQuery);\n } else {\n fileClauses.push(\"LOWER(fa.path) LIKE ? ESCAPE '\\\\'\");\n params.push(likePattern(options.file));\n }\n }\n if (options.fileKind) {\n fileClauses.push(\"fa.kind = ?\");\n params.push(options.fileKind);\n }\n clauses.push(\n `EXISTS (SELECT 1 FROM session_file_activity fa WHERE ${fileClauses.join(\" AND \")})`,\n );\n }\n if (options.from != null) {\n clauses.push(\"s.activity_time >= ?\");\n params.push(options.from);\n }\n if (options.to != null) {\n clauses.push(\"s.activity_time <= ?\");\n params.push(options.to);\n }\n if (options.costMin != null) {\n clauses.push(options.costMinExclusive ? \"s.total_cost > ?\" : \"s.total_cost >= ?\");\n params.push(options.costMin);\n }\n if (options.costMax != null) {\n clauses.push(options.costMaxExclusive ? \"s.total_cost < ?\" : \"s.total_cost <= ?\");\n params.push(options.costMax);\n }\n\n return {\n where: clauses.length > 0 ? ` AND ${clauses.join(\" AND \")}` : \"\",\n params,\n };\n}\n\nexport interface SessionSearchReference {\n agentName: string;\n sessionId: string;\n}\n\nconst SQLITE_REFERENCE_BATCH_SIZE = 200;\n\nexport function filterIndexedSessionReferences(\n references: SessionSearchReference[],\n options: SearchOptions,\n): Set<string> {\n if (references.length === 0 || !hasCacheStorage()) return new Set();\n\n const matches = withSearchDb((db) => {\n const filters = buildSessionSearchFilters(options);\n const result = new Set<string>();\n\n for (let offset = 0; offset < references.length; offset += SQLITE_REFERENCE_BATCH_SIZE) {\n const batch = references.slice(offset, offset + SQLITE_REFERENCE_BATCH_SIZE);\n const referenceClauses = batch.map(() => \"(s.agent_name = ? AND s.session_id = ?)\");\n const referenceParams = batch.flatMap(({ agentName, sessionId }) => [agentName, sessionId]);\n const rows = db\n .prepare(\n `\n SELECT s.agent_name, s.session_id\n FROM sessions s\n WHERE (${referenceClauses.join(\" OR \")})\n ${filters.where}\n `,\n )\n .all(...referenceParams, ...filters.params) as SearchResultRow[];\n\n for (const row of rows) {\n result.add(searchResultRowKey(row));\n }\n }\n\n return result;\n });\n\n return matches ?? new Set();\n}\n\nfunction searchSessionColumns(): string {\n return `\n s.agent_name,\n s.session_id,\n s.slug,\n s.title,\n s.directory,\n s.project_identity_kind,\n s.project_identity_key,\n s.project_display_name,\n s.time_created,\n s.time_updated,\n s.message_count,\n s.total_input_tokens,\n s.total_output_tokens,\n s.total_cache_read_tokens,\n s.total_cache_create_tokens,\n s.total_cost,\n s.cost_source,\n s.total_tokens,\n s.model_usage_json,\n s.smart_tags_json,\n s.smart_tags_source_updated_at\n `;\n}\n\nfunction parseTextTerms(input: string): { terms: string[]; mode: \"all\" | \"any\" } {\n const tokens = splitSearchTokens(input);\n return {\n terms: tokens\n .filter((token) => !/^OR$/i.test(token))\n .map((token) => unwrapSearchValue(token).toLowerCase())\n .filter(Boolean),\n mode: tokens.some((token) => /^OR$/i.test(token)) ? \"any\" : \"all\",\n };\n}\n\nfunction textMatchesTerms(text: string, terms: { terms: string[]; mode: \"all\" | \"any\" }) {\n const lower = text.toLowerCase();\n if (terms.terms.length === 0) return true;\n if (terms.mode === \"any\") return terms.terms.some((term) => lower.includes(term));\n return terms.terms.every((term) => lower.includes(term));\n}\n\nfunction highlightTerm(text: string, term: string): string {\n return text.replace(new RegExp(escapeRegExp(term), \"gi\"), (match) => `<mark>${match}</mark>`);\n}\n\nfunction buildTermSnippet(text: string, terms: { terms: string[]; mode: \"all\" | \"any\" }): string {\n const lower = text.toLowerCase();\n const term = terms.terms.find((item) => lower.includes(item)) ?? terms.terms[0] ?? \"\";\n if (!term) return text.slice(0, 180);\n\n const index = lower.indexOf(term);\n const start = Math.max(0, index - 80);\n const end = Math.min(text.length, index + term.length + 80);\n return `${start > 0 ? \"… \" : \"\"}${highlightTerm(text.slice(start, end), term)}${\n end < text.length ? \" …\" : \"\"\n }`;\n}\n\nfunction messageMatchType(row: MessageSearchRow): SearchMatchType {\n if (row.role === \"user\") return \"user_message\";\n if (row.role === \"tool\" || row.mode === \"tool\" || row.tool_metadata_json) return \"tool_output\";\n return \"assistant_reply\";\n}\n\nfunction searchResultRowKey(row: Pick<SearchResultRow, \"agent_name\" | \"session_id\">): string {\n return `${String(row.agent_name)}\\u0000${String(row.session_id)}`;\n}\n\nfunction fetchMessageSearchMatches(\n db: SQLiteDatabase,\n rows: SearchResultRow[],\n ftsQuery: string,\n terms: { terms: string[]; mode: \"all\" | \"any\" },\n): Map<string, { snippet: string; matchType: SearchMatchType }> {\n const candidates = rows.filter((row) => !textMatchesTerms(String(row.title ?? \"\"), terms));\n if (candidates.length === 0) {\n return new Map();\n }\n\n const clauses: string[] = [];\n const params: unknown[] = [ftsQuery];\n for (const row of candidates) {\n clauses.push(\"(m.agent_name = ? AND m.session_id = ?)\");\n params.push(String(row.agent_name), String(row.session_id));\n }\n\n const messageRows = db\n .prepare(\n `\n SELECT\n m.agent_name,\n m.session_id,\n m.message_index,\n m.role,\n m.mode,\n m.content_text,\n m.tool_metadata_json\n FROM messages_fts\n JOIN messages m ON m.rowid = messages_fts.rowid\n WHERE messages_fts MATCH ?\n AND (${clauses.join(\" OR \")})\n ORDER BY m.message_index\n `,\n )\n .all(...params) as MessageSearchRow[];\n const matches = new Map<string, { snippet: string; matchType: SearchMatchType }>();\n\n for (const message of messageRows) {\n const key = searchResultRowKey(message);\n if (matches.has(key)) continue;\n\n const text = String(message.content_text ?? \"\");\n if (!textMatchesTerms(text, terms)) continue;\n\n matches.set(key, {\n snippet: buildTermSnippet(text, terms),\n matchType: messageMatchType(message),\n });\n }\n\n return matches;\n}\n\nfunction resolveSearchMatch(\n row: SearchResultRow,\n terms: { terms: string[]; mode: \"all\" | \"any\" },\n messageMatches: Map<string, { snippet: string; matchType: SearchMatchType }>,\n): { snippet: string; matchType: SearchMatchType } {\n const title = String(row.title ?? \"\");\n\n if (terms.terms.length === 0) {\n return {\n snippet: `Recent session · ${String(row.directory ?? \"\")}`,\n matchType: \"recent\",\n };\n }\n\n if (textMatchesTerms(title, terms)) {\n return { snippet: buildTermSnippet(title, terms), matchType: \"title\" };\n }\n\n const messageMatch = messageMatches.get(searchResultRowKey(row));\n if (messageMatch) {\n return messageMatch;\n }\n\n return {\n snippet: String(row.snippet ?? \"\"),\n matchType: \"assistant_reply\",\n };\n}\n\nfunction rowsToSearchResults(\n db: SQLiteDatabase,\n rows: SearchResultRow[],\n textQuery: string,\n ftsQuery = toFtsQuery(textQuery),\n): SearchResult[] {\n const terms = parseTextTerms(textQuery);\n const messageMatches =\n terms.terms.length > 0 && ftsQuery\n ? fetchMessageSearchMatches(db, rows, ftsQuery, terms)\n : new Map<string, { snippet: string; matchType: SearchMatchType }>();\n\n return rows.map((row) => {\n const match = resolveSearchMatch(row, terms, messageMatches);\n return {\n reference: {\n agentName: String(row.agent_name),\n sessionId: String(row.session_id),\n },\n session: sessionHeadFromSearchRow(row),\n snippet: match.snippet,\n matchType: match.matchType,\n };\n });\n}\n\nexport function searchSessions(query: string, options: SearchOptions = {}): SearchResult[] {\n const search = mergeSearchQueryOptions(query, options);\n const normalizedQuery = search.text.trim();\n if (!hasCacheStorage()) {\n return [];\n }\n\n const results = withSearchDb((db) => {\n const filters = buildSessionSearchFilters(search.options);\n\n if (!normalizedQuery) {\n const rows = db\n .prepare(\n `\n SELECT\n ${searchSessionColumns()},\n '' AS snippet\n FROM sessions s\n WHERE 1 = 1\n ${filters.where}\n ORDER BY s.activity_time DESC\n LIMIT ?\n `,\n )\n .all(...filters.params, search.options.limit ?? 50) as SearchResultRow[];\n\n return rowsToSearchResults(db, rows, \"\");\n }\n\n const ftsQuery = toFtsQuery(normalizedQuery);\n if (!ftsQuery) return [];\n const rows = db\n .prepare(\n `\n SELECT\n ${searchSessionColumns()},\n COALESCE(\n NULLIF(snippet(session_documents_fts, 1, '<mark>', '</mark>', ' … ', 18), ''),\n highlight(session_documents_fts, 0, '<mark>', '</mark>')\n ) AS snippet\n FROM session_documents_fts\n JOIN session_documents d ON d.id = session_documents_fts.rowid\n JOIN sessions s ON s.agent_name = d.agent_name AND s.session_id = d.session_id\n WHERE session_documents_fts MATCH ?\n ${filters.where}\n ORDER BY bm25(session_documents_fts, 8.0, 1.0), s.activity_time DESC\n LIMIT ?\n `,\n )\n .all(ftsQuery, ...filters.params, search.options.limit ?? 50) as SearchResultRow[];\n\n return rowsToSearchResults(db, rows, normalizedQuery, ftsQuery);\n });\n\n return results ?? [];\n}\n","/**\n * File activity aggregation: per-session / cross-session file activity queries\n * and file-path search.\n */\nimport type {\n FileActivityKind,\n ProjectIdentityKind,\n SessionFileActivity,\n} from \"../../types/index.js\";\nimport type { FileActivityResult } from \"../../contract/index.js\";\nimport { computeIdentity, realFs } from \"../../projects/index.js\";\nimport type { SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { filePathFtsQuery, hasCacheStorage, likePattern, normalizeFilePathSearch } from \"./db.js\";\nimport { withCacheDb, withCacheDbReadOnly } from \"./schema.js\";\nimport {\n buildSessionSearchFilters,\n mergeSearchQueryOptions,\n sessionHeadFromSearchRow,\n type SearchOptions,\n type SearchResult,\n type SearchResultRow,\n} from \"./search.js\";\n\nexport type { FileActivityResult };\n\nexport interface FileActivityRow extends SearchResultRow {\n project_identity_key?: string;\n path?: string;\n kind?: FileActivityKind;\n count?: number;\n latest_time?: number;\n}\n\nexport interface FileActivityOptions {\n agent?: string;\n sessionId?: string;\n projectKind?: ProjectIdentityKind;\n projectKey?: string;\n project?: string;\n cwd?: string;\n path?: string;\n kind?: FileActivityKind;\n from?: number;\n to?: number;\n limit?: number;\n}\n\nexport function fileActivityFilters(options: FileActivityOptions): {\n projectKind: ProjectIdentityKind | null;\n projectKey: string | null;\n projectLike: string | null;\n cwdKind: ProjectIdentityKind | null;\n cwdKey: string | null;\n cwdLike: string | null;\n path: string;\n pathLike: string | null;\n} {\n const path = options.path ? normalizeFilePathSearch(options.path) : \"\";\n const cwdIdentity = options.cwd ? computeIdentity(options.cwd, realFs) : null;\n return {\n projectKind: options.projectKind ?? null,\n projectKey: options.projectKey ?? null,\n projectLike: options.project ? likePattern(options.project) : null,\n cwdKind: cwdIdentity?.kind ?? null,\n cwdKey: cwdIdentity?.key ?? null,\n cwdLike: options.cwd ? likePattern(options.cwd) : null,\n path,\n pathLike: path ? likePattern(path) : null,\n };\n}\n\nexport function fileActivityFromRow(row: FileActivityRow): SessionFileActivity {\n return {\n reference: {\n agentName: String(row.agent_name),\n sessionId: String(row.session_id),\n },\n projectIdentityKey: String(row.project_identity_key ?? \"\"),\n path: String(row.path ?? \"\"),\n kind: (row.kind ?? \"read\") as FileActivityKind,\n count: Number(row.count ?? 0),\n latestTime: Number(row.latest_time ?? 0),\n };\n}\n\nexport function buildFileActivityWhere(options: FileActivityOptions): {\n where: string;\n params: unknown[];\n} {\n const filters = fileActivityFilters(options);\n const clauses: string[] = [];\n const params: unknown[] = [];\n\n if (options.agent != null) {\n clauses.push(\"fa.agent_name = ?\");\n params.push(options.agent);\n }\n if (options.sessionId != null) {\n clauses.push(\"fa.session_id = ?\");\n params.push(options.sessionId);\n }\n if (filters.projectKind != null || filters.projectKey != null) {\n if (filters.projectKind != null && filters.projectKey != null) {\n clauses.push(\"s.project_identity_kind = ? AND fa.project_identity_key = ?\");\n params.push(filters.projectKind, filters.projectKey);\n } else {\n clauses.push(\"0\");\n }\n }\n if (filters.projectLike != null) {\n clauses.push(\n \"(LOWER(fa.project_identity_key) LIKE ? ESCAPE '\\\\' OR LOWER(s.project_display_name) LIKE ? ESCAPE '\\\\' OR LOWER(s.directory) LIKE ? ESCAPE '\\\\')\",\n );\n params.push(filters.projectLike, filters.projectLike, filters.projectLike);\n }\n if (filters.cwdKey != null) {\n clauses.push(\n \"((s.project_identity_kind = ? AND s.project_identity_key = ?) OR LOWER(s.directory) LIKE ? ESCAPE '\\\\')\",\n );\n params.push(filters.cwdKind, filters.cwdKey, filters.cwdLike);\n }\n if (filters.pathLike != null) {\n const pathQuery = filePathFtsQuery(filters.path);\n if (pathQuery) {\n clauses.push(\n \"fa.rowid IN (SELECT rowid FROM session_file_activity_path_fts WHERE path MATCH ?)\",\n );\n params.push(pathQuery);\n } else {\n clauses.push(\"LOWER(fa.path) LIKE ? ESCAPE '\\\\'\");\n params.push(filters.pathLike);\n }\n }\n if (options.kind != null) {\n clauses.push(\"fa.kind = ?\");\n params.push(options.kind);\n }\n if (options.from != null) {\n clauses.push(\"fa.latest_time >= ?\");\n params.push(options.from);\n }\n if (options.to != null) {\n clauses.push(\"fa.latest_time <= ?\");\n params.push(options.to);\n }\n\n return {\n where: clauses.length > 0 ? `WHERE ${clauses.join(\" AND \")}` : \"\",\n params,\n };\n}\n\nconst FILE_ACTIVITY_COLUMNS = `\n fa.agent_name,\n fa.session_id,\n fa.project_identity_key,\n fa.path,\n fa.kind,\n fa.count,\n fa.latest_time,\n s.slug,\n s.title,\n s.directory,\n s.project_identity_kind,\n s.project_display_name,\n s.time_created,\n s.time_updated,\n s.message_count,\n s.total_input_tokens,\n s.total_output_tokens,\n s.total_cache_read_tokens,\n s.total_cache_create_tokens,\n s.total_cost,\n s.cost_source,\n s.total_tokens,\n s.model_usage_json,\n s.smart_tags_json,\n s.smart_tags_source_updated_at\n`;\n\nconst FILE_ACTIVITY_JOIN = `\n FROM session_file_activity fa\n JOIN sessions s ON s.agent_name = fa.agent_name AND s.session_id = fa.session_id\n`;\n\n/** Most recent first, then busiest, then path — the tie-break every caller relies on. */\nconst FILE_ACTIVITY_ORDER = \"fa.latest_time DESC, fa.count DESC, fa.path\";\n\nexport function listFileActivity(options: FileActivityOptions = {}): FileActivityResult[] {\n return queryFileActivity(options);\n}\n\ninterface FileActivityQuery {\n options: FileActivityOptions;\n sessionSearchOptions?: SearchOptions;\n /** Keep only each session's top-ranked row, so the limit counts sessions. */\n onePerSession?: boolean;\n}\n\nfunction fileActivityWhere(query: FileActivityQuery): { where: string; params: unknown[] } {\n const filters = buildFileActivityWhere(query.options);\n const sessionFilters = query.sessionSearchOptions\n ? buildSessionSearchFilters(query.sessionSearchOptions)\n : { where: \"\", params: [] };\n const clauses = [\n filters.where.replace(/^WHERE /, \"\"),\n sessionFilters.where.replace(/^ AND /, \"\"),\n ].filter(Boolean);\n return {\n where: clauses.length > 0 ? `WHERE ${clauses.join(\" AND \")}` : \"\",\n params: [...filters.params, ...sessionFilters.params],\n };\n}\n\nfunction fileActivitySql(query: FileActivityQuery, where: string): string {\n if (!query.onePerSession) {\n return `\n SELECT ${FILE_ACTIVITY_COLUMNS}\n ${FILE_ACTIVITY_JOIN}\n ${where}\n ORDER BY ${FILE_ACTIVITY_ORDER}\n LIMIT ?\n `;\n }\n\n return `\n SELECT ${FILE_ACTIVITY_COLUMNS}\n FROM (\n SELECT\n fa.rowid AS activity_rowid,\n ROW_NUMBER() OVER (\n PARTITION BY fa.agent_name, fa.session_id\n ORDER BY ${FILE_ACTIVITY_ORDER}\n ) AS session_rank\n ${FILE_ACTIVITY_JOIN}\n ${where}\n ) ranked\n JOIN session_file_activity fa ON fa.rowid = ranked.activity_rowid\n JOIN sessions s ON s.agent_name = fa.agent_name AND s.session_id = fa.session_id\n WHERE ranked.session_rank = 1\n ORDER BY ${FILE_ACTIVITY_ORDER}\n LIMIT ?\n `;\n}\n\nfunction queryFileActivity(\n options: FileActivityOptions,\n sessionSearchOptions?: SearchOptions,\n onePerSession = false,\n): FileActivityResult[] {\n if (!hasCacheStorage()) {\n return [];\n }\n\n const query: FileActivityQuery = { options, sessionSearchOptions, onePerSession };\n const { where, params } = fileActivityWhere(query);\n const sql = fileActivitySql(query, where);\n const queryRows = (db: SQLiteDatabase) =>\n db.prepare(sql).all(...params, options.limit ?? 50) as FileActivityRow[];\n\n let rows = withCacheDbReadOnly(queryRows);\n if (rows == null && options.path) {\n rows = withCacheDb(queryRows);\n }\n\n return (rows ?? []).map((row) => ({\n ...fileActivityFromRow(row),\n session: sessionHeadFromSearchRow(row),\n }));\n}\n\nexport function listSessionFileActivity(\n agentName: string,\n sessionId: string,\n): SessionFileActivity[] {\n return listFileActivity({ agent: agentName, sessionId, limit: 500 }).map(\n ({ session: _session, ...activity }) => activity,\n );\n}\n\nexport function highlightFilePath(path: string, query: string): string {\n const needle = normalizeFilePathSearch(query);\n if (!needle) return path;\n const lower = path.toLowerCase();\n const index = lower.indexOf(needle.toLowerCase());\n if (index < 0) return path;\n return `${path.slice(0, index)}<mark>${path.slice(index, index + needle.length)}</mark>${path.slice(\n index + needle.length,\n )}`;\n}\n\nexport function searchFileActivitySessions(\n query: string,\n options: SearchOptions = {},\n): SearchResult[] {\n const search = mergeSearchQueryOptions(query, options);\n const path = normalizeFilePathSearch(search.options.file ?? search.text);\n if (!path) return [];\n\n const rows = queryFileActivity(\n {\n path,\n kind: search.options.fileKind,\n limit: search.options.limit ?? 50,\n },\n search.options,\n true,\n );\n\n return rows.map((row) => ({\n reference: row.reference,\n session: row.session,\n snippet: `${row.kind} ${highlightFilePath(row.path, path)} · ${row.count} events`,\n matchType: \"file_path\",\n }));\n}\n","/**\n * Shared scan-orchestration helpers — pure functions reused by both the CLI\n * one-shot scanner (scanner.ts) and the live file-watch refresher (live-scan.ts).\n *\n * Nothing here touches SQLite, worker threads, or event emission. The two\n * orchestrators keep their own branch strategies (one-shot vs live refresh);\n * these helpers only collapse the duplicated identity / meta / signature / diff\n * plumbing that previously had to be kept in sync by hand.\n */\nimport type { BaseAgent, SessionCacheMeta } from \"../agents/index.js\";\nimport { sortSessionsByActivity } from \"../contract/session-index.js\";\nimport type { SessionHead } from \"../types/index.js\";\nimport type { SessionHeadChange } from \"./cache/db.js\";\nimport { computeIdentity, realFs } from \"../projects/index.js\";\n\n/** Attach a project identity to sessions that don't already have one. */\nexport function attachMissingProjectIdentities(sessions: SessionHead[]): SessionHead[] {\n return sessions.map((session) => {\n if (session.project_identity) return session;\n return { ...session, project_identity: computeIdentity(session.directory, realFs) };\n });\n}\n\n/** Serialize an agent's session meta map, optionally restricted to a set of ids. */\nexport function buildAgentCacheMeta(\n agent: BaseAgent,\n sessionIds?: Set<string>,\n): Record<string, SessionCacheMeta> {\n const metaMap = agent.getSessionMetaMap?.();\n const meta: Record<string, SessionCacheMeta> = {};\n if (!metaMap) return meta;\n\n for (const [id, data] of metaMap.entries()) {\n if (sessionIds && !sessionIds.has(id)) continue;\n meta[id] = { id, ...(data as Record<string, unknown>) } as SessionCacheMeta;\n }\n\n return meta;\n}\n\n/**\n * Stable signature for the user-visible fields that define a session's identity.\n * Used by both orchestrators to decide whether a session \"changed\". Includes\n * smart_tags_source_updated_at so that smart-tag reclassification propagates to\n * the persistence diff even when the underlying message stats are unchanged.\n */\nexport function sessionSignature(session: SessionHead): string {\n return JSON.stringify([\n session.title,\n session.directory,\n session.parent_reference?.agentName ?? null,\n session.parent_reference?.sessionId ?? null,\n session.time_created,\n session.time_updated ?? session.time_created,\n session.stats.message_count,\n session.stats.total_input_tokens,\n session.stats.total_output_tokens,\n session.stats.total_cost,\n session.stats.total_tokens ?? 0,\n session.smart_tags_source_updated_at ?? null,\n ]);\n}\n\n/** Sort sessions by activity time, newest first. */\nexport function sortSessions(sessions: SessionHead[]): SessionHead[] {\n return sortSessionsByActivity(sessions);\n}\n\nexport interface SessionDiffResult {\n changes: SessionHeadChange[];\n removedSessionIds: string[];\n counts: { new: number; updated: number; removed: number };\n}\n\n/**\n * Compute the diff between a cached session set and an updated one.\n *\n * `signature` is injected so callers control the equality口径: a session counts\n * as \"changed\" if it is new, if its id is in `changedIds`, or if its signature\n * differs from the cached copy. The algorithm is pure — event assembly and\n * no-op short-circuiting stay with the caller.\n *\n * `signatureCache` is an optional id→signature memo the caller owns across\n * calls (e.g. across refresh cycles). On the cached side it's consulted before\n * falling back to `signature(cached)`; every updated session's signature is\n * written back into it, so the next call's cached-side lookups for unchanged\n * sessions can skip recomputation entirely. Mutating this caller-supplied map\n * is the only side effect — there's no module-level state. Callers must only\n * pass a cache whose lineage matches `cachedSessions`: if `cachedSessions` can\n * be a baseline the cache was never populated from (e.g. a DB snapshot instead\n * of the previous call's `updatedSessions`), a stale or mismatched hit will\n * silently suppress a real change.\n */\nexport function computeSessionDiff(\n cachedSessions: SessionHead[],\n updatedSessions: SessionHead[],\n changedIds: string[] = [],\n signature: (session: SessionHead) => string = sessionSignature,\n signatureCache?: Map<string, string>,\n): SessionDiffResult {\n const cachedMap = new Map(cachedSessions.map((session) => [session.id, session]));\n const updatedIds = new Set(updatedSessions.map((session) => session.id));\n const changedIdSet = new Set(changedIds);\n const changes: SessionHeadChange[] = [];\n const removedSessionIds: string[] = [];\n let newCount = 0;\n let updatedCount = 0;\n\n updatedSessions.forEach((session, sortIndex) => {\n const cached = cachedMap.get(session.id);\n if (!cached) {\n newCount += 1;\n changes.push({ session, sortIndex });\n signatureCache?.set(session.id, signature(session));\n return;\n }\n const cachedSignature = signatureCache?.get(cached.id) ?? signature(cached);\n const updatedSignature = signature(session);\n signatureCache?.set(session.id, updatedSignature);\n if (changedIdSet.has(session.id) || cachedSignature !== updatedSignature) {\n updatedCount += 1;\n changes.push({ session, sortIndex });\n }\n });\n\n for (const session of cachedSessions) {\n if (!updatedIds.has(session.id)) {\n removedSessionIds.push(session.id);\n }\n }\n\n return {\n changes,\n removedSessionIds,\n counts: { new: newCount, updated: updatedCount, removed: removedSessionIds.length },\n };\n}\n","import type { BaseAgent, SessionCacheMeta } from \"../agents/index.js\";\nimport type { SessionReference } from \"../contract/index.js\";\nimport type { SessionDetail, SessionHead } from \"../types/index.js\";\nimport { computeIdentity, realFs } from \"../projects/index.js\";\nimport {\n classifySessionTags,\n extractSessionFileActivity,\n getSmartTagSourceTimestamp,\n} from \"../utils/index.js\";\nimport { listSessionFileActivity } from \"./cache/file-activity.js\";\nimport { loadCachedSessionRawEntry, type CachedSessionRawEntry } from \"./cache/sessions.js\";\nimport { messageFromCachedRow, messageJsonFromCachedRow } from \"./cache/messages.js\";\nimport type { LiveSnapshot } from \"./scanner.js\";\n\nexport type SessionDetailResult =\n | { status: \"found\"; data: SessionDetail }\n | { status: \"unknown-agent\" }\n | { status: \"not-ready\" };\n\nexport type SessionDetailResponseResult =\n | SessionDetailResult\n | {\n status: \"found-json\";\n data: Omit<SessionDetail, \"messages\">;\n messages: Iterable<string>;\n messageCount: number;\n };\n\ninterface SessionDetailLookup {\n agentsByName: Map<string, BaseAgent>;\n headsByReference: Map<string, SessionHead>;\n}\n\ninterface SessionDetailContext {\n agent: BaseAgent;\n head: SessionHead | undefined;\n}\n\nconst sessionDetailLookups = new WeakMap<SessionHead[], SessionDetailLookup>();\n\nfunction sessionReferenceKey(agentName: string, sessionId: string): string {\n return `${agentName}\\0${sessionId}`;\n}\n\n/**\n * The canonical sessions array is replaced atomically with each scan snapshot,\n * so its identity also versions this lazily built lookup.\n */\nfunction getSessionDetailLookup(scanResult: LiveSnapshot): SessionDetailLookup {\n const cached = sessionDetailLookups.get(scanResult.sessions);\n if (cached) return cached;\n\n const agentsByName = new Map<string, BaseAgent>();\n for (const agent of scanResult.agents) {\n if (!agentsByName.has(agent.name)) agentsByName.set(agent.name, agent);\n }\n const headsByReference = new Map<string, SessionHead>();\n for (const [agentName, sessions] of Object.entries(scanResult.byAgent)) {\n for (const session of sessions) {\n const key = sessionReferenceKey(agentName, session.id);\n if (!headsByReference.has(key)) headsByReference.set(key, session);\n }\n }\n\n const lookup = { agentsByName, headsByReference };\n sessionDetailLookups.set(scanResult.sessions, lookup);\n return lookup;\n}\n\nfunction getSessionDetailContext(\n scanResult: LiveSnapshot,\n reference: SessionReference,\n): SessionDetailContext | null {\n const lookup = getSessionDetailLookup(scanResult);\n const agent = lookup.agentsByName.get(reference.agentName);\n if (!agent) return null;\n return {\n agent,\n head: lookup.headsByReference.get(\n sessionReferenceKey(reference.agentName, reference.sessionId),\n ),\n };\n}\n\nfunction cacheMatchesCurrentSource(\n cachedMeta: SessionCacheMeta | null,\n currentMeta: SessionCacheMeta | undefined,\n): boolean {\n const currentFingerprint = currentMeta?.sourceFingerprint;\n if (typeof currentFingerprint !== \"string\") return true;\n return cachedMeta?.sourceFingerprint === currentFingerprint;\n}\n\nfunction cacheHasCompleteDetail(\n cachedEntry: CachedSessionRawEntry | null,\n currentMeta: SessionCacheMeta | undefined,\n): cachedEntry is CachedSessionRawEntry {\n if (!cachedEntry || !cacheMatchesCurrentSource(cachedEntry.meta, currentMeta)) {\n return false;\n }\n\n return cachedEntry.messageRows.length > 0 || cachedEntry.data.stats.message_count === 0;\n}\n\nfunction getProjectIdentity(\n data: Pick<SessionDetail, \"directory\" | \"project_identity\">,\n head: SessionHead | undefined,\n) {\n return data.project_identity ?? head?.project_identity ?? computeIdentity(data.directory, realFs);\n}\n\nfunction materializeStructuredSessionDetail(\n context: SessionDetailContext,\n reference: SessionReference,\n cachedEntry = loadCachedSessionRawEntry(reference.agentName, reference.sessionId),\n): SessionDetailResult {\n const { agent, head } = context;\n const currentMeta = head ? agent.getSessionMetaMap().get(reference.sessionId) : undefined;\n const useCache = cacheHasCompleteDetail(cachedEntry, currentMeta);\n const data = useCache\n ? {\n ...cachedEntry.data,\n messages: cachedEntry.messageRows.map((messageRow) => messageFromCachedRow(messageRow)),\n }\n : head\n ? agent.getSessionData(reference.sessionId)\n : null;\n\n if (!data) {\n return { status: \"not-ready\" };\n }\n\n const projectIdentity = getProjectIdentity(data, head);\n const fileActivity =\n data.file_activity ??\n (useCache\n ? listSessionFileActivity(reference.agentName, reference.sessionId)\n : extractSessionFileActivity(\n reference.agentName,\n reference.sessionId,\n projectIdentity.key,\n data.messages,\n ));\n\n return {\n status: \"found\",\n data: {\n ...data,\n reference,\n project_identity: projectIdentity,\n smart_tags: data.smart_tags ?? classifySessionTags(data),\n smart_tags_source_updated_at: getSmartTagSourceTimestamp(data),\n file_activity: fileActivity,\n },\n };\n}\n\nfunction* serializeCachedMessages(entry: CachedSessionRawEntry): IterableIterator<string> {\n for (const messageRow of entry.messageRows) {\n yield messageJsonFromCachedRow(messageRow);\n }\n}\n\nexport function materializeSessionDetail(\n scanResult: LiveSnapshot,\n reference: SessionReference,\n): SessionDetailResult {\n const context = getSessionDetailContext(scanResult, reference);\n if (!context) return { status: \"unknown-agent\" };\n return materializeStructuredSessionDetail(context, reference);\n}\n\nexport function materializeSessionDetailResponse(\n scanResult: LiveSnapshot,\n reference: SessionReference,\n): SessionDetailResponseResult {\n const context = getSessionDetailContext(scanResult, reference);\n if (!context) return { status: \"unknown-agent\" };\n\n const cachedEntry = loadCachedSessionRawEntry(reference.agentName, reference.sessionId);\n const currentMeta = context.head\n ? context.agent.getSessionMetaMap().get(reference.sessionId)\n : undefined;\n const useCache = cacheHasCompleteDetail(cachedEntry, currentMeta);\n if (!useCache || cachedEntry.data.smart_tags == null) {\n return materializeStructuredSessionDetail(context, reference, cachedEntry);\n }\n\n const data = cachedEntry.data;\n return {\n status: \"found-json\",\n data: {\n ...data,\n reference,\n project_identity: getProjectIdentity(data, context.head),\n smart_tags_source_updated_at: getSmartTagSourceTimestamp(data),\n file_activity:\n data.file_activity ?? listSessionFileActivity(reference.agentName, reference.sessionId),\n },\n messages: serializeCachedMessages(cachedEntry),\n messageCount: cachedEntry.messageRows.length,\n };\n}\n","/**\n * Project grouping: reads the project_groups_v view (or falls back to an\n * in-memory build) to list cached project groups.\n */\nimport type { ProjectGroup, ProjectIdentityKind, SessionHead } from \"../../types/index.js\";\nimport { buildProjectGroups } from \"../../projects/index.js\";\nimport type { DatabaseRow, SQLiteDatabase } from \"../../utils/sqlite.js\";\nimport { hasCacheStorage } from \"./db.js\";\nimport { withCacheDb, withCacheDbReadOnly } from \"./schema.js\";\n\nexport interface ProjectGroupRow extends DatabaseRow {\n identity_kind?: ProjectIdentityKind;\n identity_key?: string;\n display_name?: string;\n sources_csv?: string | null;\n session_count?: number;\n last_activity?: number | null;\n}\n\nexport function listCachedProjectGroups(sessions?: SessionHead[]): ProjectGroup[] {\n if (sessions) {\n return buildProjectGroups(sessions);\n }\n\n if (!hasCacheStorage()) {\n return [];\n }\n\n const queryRows = (db: SQLiteDatabase) =>\n db\n .prepare(\n `\n SELECT identity_kind, identity_key, display_name, sources_csv, session_count, last_activity\n FROM project_groups_v\n ORDER BY\n CASE identity_kind WHEN 'loose' THEN 1 ELSE 0 END,\n last_activity IS NULL,\n last_activity DESC\n `,\n )\n .all() as ProjectGroupRow[];\n\n let rows = withCacheDbReadOnly(queryRows);\n if (rows == null) {\n rows = withCacheDb(queryRows);\n }\n\n return (rows ?? []).map((row) => ({\n identityKind: row.identity_kind ?? \"path\",\n identityKey: String(row.identity_key ?? \"\"),\n displayName: String(row.display_name ?? \"\"),\n sources: String(row.sources_csv ?? \"\")\n .split(\",\")\n .filter(Boolean)\n .sort(),\n sessionCount: Number(row.session_count ?? 0),\n lastActivity: row.last_activity == null ? null : Number(row.last_activity),\n }));\n}\n","import { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\nimport {\n columnExists,\n getUserVersion,\n openDb,\n runSchemaMigrations,\n setUserVersion,\n tableExists,\n type DatabaseRow,\n type SQLiteDatabase,\n} from \"../utils/sqlite.js\";\n\nconst STATE_DB_FILENAME = \"state.db\";\nconst STATE_SCHEMA_VERSION = 2;\nconst MEMORY_STATE_STORE = \"memory\";\n\n// One-shot per-process ensureSchema guard, mirroring the cache side's\n// schemaEnsuredPath (discovery/cache/db.ts). Keyed by dbPath so tests can\n// switch state directories; exported so tests can reset it between runs.\nlet stateSchemaEnsuredPath: string | null = null;\n\nexport function getStateSchemaEnsuredPath(): string | null {\n return stateSchemaEnsuredPath;\n}\n\nexport function setStateSchemaEnsuredPath(path: string | null): void {\n stateSchemaEnsuredPath = path;\n}\n\nexport class StateStorageUnavailableError extends Error {\n constructor() {\n super(\"SQLite state database is unavailable\");\n this.name = \"StateStorageUnavailableError\";\n }\n}\n\nfunction getStateDir(): string {\n if (process.env.CODESESH_STATE_DIR) return process.env.CODESESH_STATE_DIR;\n\n const currentPlatform = platform();\n if (currentPlatform === \"darwin\") {\n return join(homedir(), \"Library\", \"Application Support\", \"codesesh\");\n }\n if (currentPlatform === \"win32\") {\n const appData = process.env.APPDATA ?? process.env.LOCALAPPDATA;\n return join(appData ?? join(homedir(), \"AppData\", \"Roaming\"), \"codesesh\");\n }\n return join(process.env.XDG_DATA_HOME ?? join(homedir(), \".local\", \"share\"), \"codesesh\");\n}\n\nfunction getStateDbPath(): string {\n return join(getStateDir(), STATE_DB_FILENAME);\n}\n\nexport function useMemoryStateStore(): boolean {\n return process.env.CODESESH_STATE_STORE === MEMORY_STATE_STORE;\n}\n\nfunction createBookmarksTable(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS bookmarks (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n slug TEXT NOT NULL,\n title TEXT NOT NULL,\n directory TEXT NOT NULL,\n time_created INTEGER NOT NULL,\n time_updated INTEGER,\n stats_json TEXT NOT NULL,\n bookmarked_at INTEGER NOT NULL,\n PRIMARY KEY (agent_name, session_id)\n );\n `);\n}\n\nfunction createSessionAliasesTable(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS session_aliases (\n agent_name TEXT NOT NULL,\n session_id TEXT NOT NULL,\n alias TEXT NOT NULL,\n updated_at INTEGER NOT NULL,\n PRIMARY KEY (agent_name, session_id)\n );\n `);\n}\n\nfunction createStateSchema(db: SQLiteDatabase): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS state_meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n );\n `);\n createBookmarksTable(db);\n createSessionAliasesTable(db);\n}\n\nfunction readLegacyStateVersion(db: SQLiteDatabase): number {\n if (\n !tableExists(db, \"state_meta\") ||\n !columnExists(db, \"state_meta\", \"key\") ||\n !columnExists(db, \"state_meta\", \"value\")\n ) {\n return 0;\n }\n\n const row = db.prepare(\"SELECT value FROM state_meta WHERE key = 'version'\").get() as\n | DatabaseRow\n | undefined;\n return Number(row?.value ?? 0);\n}\n\nfunction getCurrentStateSchemaVersion(db: SQLiteDatabase): number {\n const userVersion = getUserVersion(db);\n if (userVersion > 0) return userVersion;\n\n const legacyVersion = readLegacyStateVersion(db);\n if (legacyVersion > 0) return legacyVersion;\n\n return tableExists(db, \"bookmarks\") ? 1 : 0;\n}\n\nfunction hasAnyStateSchema(db: SQLiteDatabase): boolean {\n return tableExists(db, \"state_meta\") || tableExists(db, \"bookmarks\");\n}\n\nfunction setStateSchemaVersion(db: SQLiteDatabase): void {\n createStateSchema(db);\n setUserVersion(db, STATE_SCHEMA_VERSION);\n db.prepare(\n `\n INSERT INTO state_meta(key, value)\n VALUES ('version', ?)\n ON CONFLICT(key) DO UPDATE SET value = excluded.value\n `,\n ).run(String(STATE_SCHEMA_VERSION));\n}\n\nfunction ensureSchema(db: SQLiteDatabase, dbPath: string): void {\n const currentVersion = getCurrentStateSchemaVersion(db);\n if (currentVersion === 0 && !hasAnyStateSchema(db)) {\n setStateSchemaVersion(db);\n return;\n }\n\n runSchemaMigrations(db, {\n dbPath,\n currentVersion,\n targetVersion: STATE_SCHEMA_VERSION,\n backupLabel: \"state-migration\",\n backupTables: [\"bookmarks\", \"session_aliases\"],\n migrations: [\n { version: 1, migrate: createBookmarksTable },\n { version: 2, migrate: createSessionAliasesTable },\n ],\n });\n\n if (currentVersion < STATE_SCHEMA_VERSION) {\n setStateSchemaVersion(db);\n }\n}\n\nexport function withStateDb<T>(fn: (db: SQLiteDatabase) => T): T {\n const statePath = getStateDbPath();\n const db = openDb(statePath);\n if (!db) throw new StateStorageUnavailableError();\n\n try {\n if (getStateSchemaEnsuredPath() !== statePath) {\n ensureSchema(db, statePath);\n setStateSchemaEnsuredPath(statePath);\n }\n return fn(db);\n } finally {\n db.close();\n }\n}\n","import type { SessionStats } from \"../types/index.js\";\nimport {\n formatSessionReference,\n normalizeSessionReference,\n type BookmarkRecord,\n type SessionReference,\n} from \"../contract/index.js\";\nimport { StateStorageUnavailableError, useMemoryStateStore, withStateDb } from \"./database.js\";\nimport type { DatabaseRow } from \"../utils/sqlite.js\";\n\nconst memoryBookmarks = new Map<string, BookmarkRecord>();\n\nexport { StateStorageUnavailableError as BookmarkStorageUnavailableError };\n\nexport type { BookmarkRecord };\n\ninterface BookmarkRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n title?: string;\n directory?: string;\n time_created?: number;\n time_updated?: number | null;\n stats_json?: string;\n bookmarked_at?: number;\n}\n\nfunction getBookmarkKey(reference: SessionReference): string {\n const normalized = normalizeSessionReference(reference);\n return JSON.stringify([normalized.agentName, normalized.sessionId]);\n}\n\nfunction getActivityTime(bookmark: BookmarkRecord): number {\n return bookmark.session.time_updated ?? bookmark.session.time_created;\n}\n\nfunction sortBookmarks(bookmarks: BookmarkRecord[]): BookmarkRecord[] {\n return bookmarks.sort((a, b) => {\n const activityDelta = getActivityTime(b) - getActivityTime(a);\n return activityDelta || b.bookmarkedAt - a.bookmarkedAt;\n });\n}\n\nfunction listMemoryBookmarks(): BookmarkRecord[] {\n return sortBookmarks(Array.from(memoryBookmarks.values()));\n}\n\nfunction normalizeBookmark(\n bookmark: Omit<BookmarkRecord, \"bookmarkedAt\">,\n): Omit<BookmarkRecord, \"bookmarkedAt\"> {\n const reference = normalizeSessionReference(bookmark.reference);\n return {\n reference,\n session: {\n ...bookmark.session,\n id: reference.sessionId,\n slug: formatSessionReference(reference),\n },\n };\n}\n\nfunction upsertMemoryBookmark(bookmark: Omit<BookmarkRecord, \"bookmarkedAt\">): BookmarkRecord {\n const key = getBookmarkKey(bookmark.reference);\n const saved = {\n ...bookmark,\n bookmarkedAt: memoryBookmarks.get(key)?.bookmarkedAt ?? Date.now(),\n };\n memoryBookmarks.set(key, saved);\n return saved;\n}\n\nfunction toBookmarkRecord(row: BookmarkRow): BookmarkRecord {\n const reference = normalizeSessionReference({\n agentName: String(row.agent_name ?? \"\"),\n sessionId: String(row.session_id ?? \"\"),\n });\n return {\n reference,\n session: {\n id: reference.sessionId,\n slug: formatSessionReference(reference),\n title: String(row.title ?? \"\"),\n directory: String(row.directory ?? \"\"),\n time_created: Number(row.time_created ?? 0),\n time_updated: row.time_updated == null ? undefined : Number(row.time_updated),\n stats: JSON.parse(String(row.stats_json ?? \"{}\")) as SessionStats,\n },\n bookmarkedAt: Number(row.bookmarked_at ?? 0),\n };\n}\n\nexport function listBookmarks(): BookmarkRecord[] {\n if (useMemoryStateStore()) {\n return listMemoryBookmarks();\n }\n\n return withStateDb((db) => {\n const rows = db\n .prepare(\n `\n SELECT\n agent_name,\n session_id,\n title,\n directory,\n time_created,\n time_updated,\n stats_json,\n bookmarked_at\n FROM bookmarks\n ORDER BY COALESCE(time_updated, time_created) DESC, bookmarked_at DESC\n `,\n )\n .all() as BookmarkRow[];\n\n return rows.map(toBookmarkRecord);\n });\n}\n\nexport function upsertBookmark(bookmark: Omit<BookmarkRecord, \"bookmarkedAt\">): BookmarkRecord {\n const normalized = normalizeBookmark(bookmark);\n if (useMemoryStateStore()) {\n return upsertMemoryBookmark(normalized);\n }\n\n return withStateDb((db) => {\n const existing = db\n .prepare(\n `\n SELECT bookmarked_at\n FROM bookmarks\n WHERE agent_name = ? AND session_id = ?\n `,\n )\n .get(normalized.reference.agentName, normalized.reference.sessionId) as\n | DatabaseRow\n | undefined;\n const bookmarkedAt = Number(existing?.bookmarked_at ?? Date.now());\n\n db.prepare(\n `\n INSERT INTO bookmarks(\n agent_name,\n session_id,\n slug,\n title,\n directory,\n time_created,\n time_updated,\n stats_json,\n bookmarked_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n slug = excluded.slug,\n title = excluded.title,\n directory = excluded.directory,\n time_created = excluded.time_created,\n time_updated = excluded.time_updated,\n stats_json = excluded.stats_json\n `,\n ).run(\n normalized.reference.agentName,\n normalized.reference.sessionId,\n formatSessionReference(normalized.reference),\n normalized.session.title,\n normalized.session.directory,\n normalized.session.time_created,\n normalized.session.time_updated ?? null,\n JSON.stringify(normalized.session.stats),\n bookmarkedAt,\n );\n\n return { ...normalized, bookmarkedAt };\n });\n}\n\nexport function importBookmarks(\n bookmarks: Omit<BookmarkRecord, \"bookmarkedAt\">[],\n): BookmarkRecord[] {\n const normalizedBookmarks = bookmarks.map(normalizeBookmark);\n if (useMemoryStateStore()) {\n for (const bookmark of normalizedBookmarks) {\n upsertMemoryBookmark(bookmark);\n }\n return listMemoryBookmarks();\n }\n\n return withStateDb((db) => {\n const existingRows = db\n .prepare(\"SELECT agent_name, session_id, bookmarked_at FROM bookmarks\")\n .all() as DatabaseRow[];\n const existingTimes = new Map(\n existingRows.map((row) => [\n getBookmarkKey({\n agentName: String(row.agent_name ?? \"\"),\n sessionId: String(row.session_id ?? \"\"),\n }),\n Number(row.bookmarked_at ?? 0),\n ]),\n );\n\n const upsert = db.prepare(\n `\n INSERT INTO bookmarks(\n agent_name,\n session_id,\n slug,\n title,\n directory,\n time_created,\n time_updated,\n stats_json,\n bookmarked_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n slug = excluded.slug,\n title = excluded.title,\n directory = excluded.directory,\n time_created = excluded.time_created,\n time_updated = excluded.time_updated,\n stats_json = excluded.stats_json\n `,\n );\n\n const write = db.transaction(() => {\n for (const bookmark of normalizedBookmarks) {\n const key = getBookmarkKey(bookmark.reference);\n upsert.run(\n bookmark.reference.agentName,\n bookmark.reference.sessionId,\n formatSessionReference(bookmark.reference),\n bookmark.session.title,\n bookmark.session.directory,\n bookmark.session.time_created,\n bookmark.session.time_updated ?? null,\n JSON.stringify(bookmark.session.stats),\n existingTimes.get(key) ?? Date.now(),\n );\n }\n });\n\n write();\n const rows = db\n .prepare(\n `\n SELECT\n agent_name,\n session_id,\n title,\n directory,\n time_created,\n time_updated,\n stats_json,\n bookmarked_at\n FROM bookmarks\n ORDER BY COALESCE(time_updated, time_created) DESC, bookmarked_at DESC\n `,\n )\n .all() as BookmarkRow[];\n return rows.map(toBookmarkRecord);\n });\n}\n\nexport function deleteBookmark(reference: SessionReference): void {\n const normalized = normalizeSessionReference(reference);\n if (useMemoryStateStore()) {\n memoryBookmarks.delete(getBookmarkKey(normalized));\n return;\n }\n\n withStateDb((db) => {\n db.prepare(\n `\n DELETE FROM bookmarks\n WHERE agent_name = ? AND session_id = ?\n `,\n ).run(normalized.agentName, normalized.sessionId);\n });\n}\n","import { StateStorageUnavailableError, useMemoryStateStore, withStateDb } from \"./database.js\";\nimport type { DatabaseRow } from \"../utils/sqlite.js\";\nimport { normalizeSessionReference, type SessionReference } from \"../contract/index.js\";\n\nexport const SESSION_ALIAS_MAX_LENGTH = 160;\n\nexport class SessionAliasValidationError extends Error {\n constructor() {\n super(\"Invalid session alias\");\n this.name = \"SessionAliasValidationError\";\n }\n}\n\nexport interface SessionAlias {\n reference: SessionReference;\n alias: string;\n updatedAt: number;\n}\n\ninterface SessionAliasRow extends DatabaseRow {\n agent_name?: string;\n session_id?: string;\n alias?: string;\n updated_at?: number;\n}\n\nconst memoryAliases = new Map<string, SessionAlias>();\n\nfunction getAliasKey(reference: SessionReference): string {\n const normalized = normalizeSessionReference(reference);\n return JSON.stringify([normalized.agentName, normalized.sessionId]);\n}\n\nfunction toSessionAlias(row: SessionAliasRow): SessionAlias {\n const reference = normalizeSessionReference({\n agentName: String(row.agent_name ?? \"\"),\n sessionId: String(row.session_id ?? \"\"),\n });\n return {\n reference,\n alias: String(row.alias ?? \"\"),\n updatedAt: Number(row.updated_at ?? 0),\n };\n}\n\nexport function normalizeSessionAlias(value: string): string | null {\n const alias = value.trim();\n if (!alias || alias.length > SESSION_ALIAS_MAX_LENGTH) return null;\n return alias;\n}\n\nexport function listSessionAliases(): SessionAlias[] {\n if (useMemoryStateStore()) return [...memoryAliases.values()];\n\n return withStateDb((db) =>\n (\n db\n .prepare(\n `\n SELECT agent_name, session_id, alias, updated_at\n FROM session_aliases\n ORDER BY updated_at DESC\n `,\n )\n .all() as SessionAliasRow[]\n ).map(toSessionAlias),\n );\n}\n\nexport function upsertSessionAlias(reference: SessionReference, alias: string): SessionAlias {\n const normalizedAlias = normalizeSessionAlias(alias);\n if (!normalizedAlias) {\n throw new SessionAliasValidationError();\n }\n\n const normalizedReference = normalizeSessionReference(reference);\n const saved: SessionAlias = {\n reference: normalizedReference,\n alias: normalizedAlias,\n updatedAt: Date.now(),\n };\n if (useMemoryStateStore()) {\n memoryAliases.set(getAliasKey(normalizedReference), saved);\n return saved;\n }\n\n return withStateDb((db) => {\n db.prepare(\n `\n INSERT INTO session_aliases(agent_name, session_id, alias, updated_at)\n VALUES (?, ?, ?, ?)\n ON CONFLICT(agent_name, session_id) DO UPDATE SET\n alias = excluded.alias,\n updated_at = excluded.updated_at\n `,\n ).run(saved.reference.agentName, saved.reference.sessionId, saved.alias, saved.updatedAt);\n return saved;\n });\n}\n\nexport function deleteSessionAlias(reference: SessionReference): void {\n const normalizedReference = normalizeSessionReference(reference);\n if (useMemoryStateStore()) {\n memoryAliases.delete(getAliasKey(normalizedReference));\n return;\n }\n\n withStateDb((db) => {\n db.prepare(\n `\n DELETE FROM session_aliases\n WHERE agent_name = ? AND session_id = ?\n `,\n ).run(normalizedReference.agentName, normalizedReference.sessionId);\n });\n}\n\nexport { StateStorageUnavailableError };\n","/**\n * Dashboard analytics — pure aggregation over SessionHead[] with no HTTP or DB\n * coupling. The handler parses request params and supplies file-activity; this\n * module owns the domain math: per-agent metrics, daily buckets, model\n * distribution, and the recent-sessions window.\n */\nimport type { AgentInfo } from \"../types/index.js\";\nimport type { ProjectIdentityKind, SessionHead } from \"../types/session.js\";\nimport type {\n DailyTokenBucket,\n DashboardAgentStat,\n DashboardAggregate,\n DashboardDailyBucket,\n DashboardData,\n DashboardRecentSession,\n DashboardTotals,\n ModelDistributionEntry,\n} from \"../contract/index.js\";\nimport {\n addCalendarDays,\n countCalendarDays,\n filterSessionTreeByActivityWindow,\n getSessionAgentKey,\n isChildSession,\n toCalendarDayKey,\n} from \"../contract/index.js\";\n\nexport type {\n DailyTokenBucket,\n DashboardAgentStat,\n DashboardAggregate,\n DashboardDailyBucket,\n DashboardData,\n DashboardRecentSession,\n DashboardTotals,\n ModelDistributionEntry,\n};\n\nexport const DASHBOARD_RECENT_LIMIT = 10;\n\nexport interface DashboardScope {\n agent?: string;\n projectKind?: ProjectIdentityKind;\n projectKey?: string;\n}\n\ninterface DashboardAgentAggregate {\n sessions: number;\n messages: number;\n tokens: number;\n}\n\ninterface DashboardRecentCandidate {\n session: SessionHead;\n activity: number;\n}\n\nexport interface DashboardOptions {\n byAgentNames: string[];\n scope: DashboardScope;\n from?: number;\n to: number;\n agentInfoMap?: Map<string, AgentInfo>;\n}\n\n// --- SessionHead domain helpers (shared with other handlers via re-export) ---\n\nexport function getTotalTokens(stats: SessionHead[\"stats\"]): number {\n return stats.total_tokens ?? stats.total_input_tokens + stats.total_output_tokens;\n}\n\nexport function getSessionAgentName(session: SessionHead): string {\n return getSessionAgentKey(session);\n}\n\nexport function getSessionActivityTime(session: SessionHead): number {\n return session.time_updated ?? session.time_created;\n}\n\n/**\n * Aggregate sessions into dashboard metrics, daily buckets, model distribution,\n * and the recent-sessions window. Pure — no HTTP, no DB.\n */\nexport function buildDashboard(\n sessions: SessionHead[],\n options: DashboardOptions,\n): DashboardAggregate {\n const { byAgentNames, scope, from, to, agentInfoMap } = options;\n\n const agentMetrics = new Map<string, DashboardAgentAggregate>();\n const agentMetricKeyByName = new Map<string, string>();\n for (const name of byAgentNames) {\n if (scope.agent && name.toLowerCase() !== scope.agent) continue;\n agentMetrics.set(name, { sessions: 0, messages: 0, tokens: 0 });\n agentMetricKeyByName.set(name.toLowerCase(), name);\n }\n\n let totalSessions = 0;\n let totalMessages = 0;\n let totalTokens = 0;\n let totalCost = 0;\n let hasEstimatedCost = false;\n let latestActivity = 0;\n const recentCandidates: DashboardRecentCandidate[] = [];\n const modelAgg = new Map<string, { tokens: number; sessions: number }>();\n\n const dailyMap = new Map<string, DashboardDailyBucket>();\n const dailyTokenMap = new Map<string, DailyTokenBucket>();\n if (from != null) {\n const bucketDays = countCalendarDays(from, to);\n for (let i = 0; i < bucketDays; i += 1) {\n const key = toCalendarDayKey(addCalendarDays(from, i));\n dailyMap.set(key, { date: key, sessions: 0, messages: 0 });\n dailyTokenMap.set(key, { date: key, input: 0, output: 0, cache_read: 0, cache_create: 0 });\n }\n }\n\n const visibleSessions = filterSessionTreeByActivityWindow(sessions, from, to);\n for (const session of visibleSessions) {\n if (isChildSession(session)) continue;\n const agentName = getSessionAgentName(session);\n if (scope.agent && agentName !== scope.agent) continue;\n if (scope.projectKind || scope.projectKey) {\n const identity = session.project_identity;\n if (\n !identity ||\n !scope.projectKind ||\n !scope.projectKey ||\n identity.kind !== scope.projectKind ||\n identity.key !== scope.projectKey\n ) {\n continue;\n }\n }\n\n const activity = getSessionActivityTime(session);\n\n const messageCount = session.stats.message_count;\n const sessionTokens = getTotalTokens(session.stats);\n totalSessions += 1;\n totalMessages += messageCount;\n totalTokens += sessionTokens;\n totalCost += session.stats.total_cost ?? 0;\n if (session.stats.cost_source === \"estimated\") hasEstimatedCost = true;\n if (activity > latestActivity) latestActivity = activity;\n\n const metricKey = agentMetricKeyByName.get(agentName);\n if (metricKey) {\n const metric = agentMetrics.get(metricKey)!;\n metric.sessions += 1;\n metric.messages += messageCount;\n metric.tokens += sessionTokens;\n }\n\n const key = toCalendarDayKey(activity);\n let bucket = dailyMap.get(key);\n if (!bucket) {\n bucket = { date: key, sessions: 0, messages: 0 };\n dailyMap.set(key, bucket);\n }\n bucket.sessions += 1;\n bucket.messages += messageCount;\n\n let tokenBucket = dailyTokenMap.get(key);\n if (!tokenBucket) {\n tokenBucket = { date: key, input: 0, output: 0, cache_read: 0, cache_create: 0 };\n dailyTokenMap.set(key, tokenBucket);\n }\n const cacheRead = session.stats.total_cache_read_tokens ?? 0;\n const cacheCreate = session.stats.total_cache_create_tokens ?? 0;\n const pureInput = session.stats.total_input_tokens - cacheRead - cacheCreate;\n tokenBucket.input += Math.max(0, pureInput);\n tokenBucket.output += session.stats.total_output_tokens;\n tokenBucket.cache_read += cacheRead;\n tokenBucket.cache_create += cacheCreate;\n\n if (session.model_usage) {\n for (const [model, tokens] of Object.entries(session.model_usage)) {\n const entry = modelAgg.get(model);\n if (entry) {\n entry.tokens += tokens;\n entry.sessions += 1;\n } else {\n modelAgg.set(model, { tokens, sessions: 1 });\n }\n }\n }\n\n let recentIndex = recentCandidates.length;\n for (let i = 0; i < recentCandidates.length; i += 1) {\n if (activity > recentCandidates[i]!.activity) {\n recentIndex = i;\n break;\n }\n }\n if (recentIndex < DASHBOARD_RECENT_LIMIT) {\n recentCandidates.splice(recentIndex, 0, { session, activity });\n if (recentCandidates.length > DASHBOARD_RECENT_LIMIT) recentCandidates.pop();\n }\n }\n\n const perAgent: DashboardAgentStat[] = [...agentMetrics.entries()]\n .map(([name, metrics]) => {\n const info = agentInfoMap?.get(name);\n return {\n name,\n displayName: info?.displayName ?? name,\n icon: info?.icon ?? \"\",\n iconColored: info?.iconColored,\n sessions: metrics.sessions,\n messages: metrics.messages,\n tokens: metrics.tokens,\n };\n })\n .filter((item) => item.sessions > 0)\n .sort((a, b) => b.sessions - a.sessions);\n\n const dailyActivity = [...dailyMap.values()].sort((a, b) => a.date.localeCompare(b.date));\n const dailyTokenActivity = [...dailyTokenMap.values()].sort((a, b) =>\n a.date.localeCompare(b.date),\n );\n\n const modelDistribution: ModelDistributionEntry[] = [...modelAgg.entries()]\n .map(([model, { tokens, sessions: count }]) => ({ model, tokens, sessions: count }))\n .sort((a, b) => b.tokens - a.tokens);\n\n const recentSessions: DashboardRecentSession[] = recentCandidates.map(({ session }) => {\n const agentKey = getSessionAgentName(session);\n return {\n reference: { agentName: agentKey, sessionId: session.id },\n session,\n };\n });\n\n return {\n totals: {\n sessions: totalSessions,\n messages: totalMessages,\n tokens: totalTokens,\n cost: totalCost,\n cost_source: totalCost > 0 ? (hasEstimatedCost ? \"estimated\" : \"recorded\") : undefined,\n latestActivity: latestActivity || undefined,\n },\n perAgent,\n dailyActivity,\n dailyTokenActivity,\n modelDistribution,\n recentSessions,\n };\n}\n","/**\n * Project analytics — pure aggregation over SessionHead[], the project-level\n * counterpart to dashboard.ts. No HTTP, no DB: the caller supplies the groups\n * and the sessions, this module owns the arithmetic.\n */\nimport type { ProjectGroup, SessionHead } from \"../types/index.js\";\nimport type { ApiProjectAgentStat, ApiProjectGroup } from \"../contract/index.js\";\nimport { getProjectIdentityKey } from \"../contract/project-identity.js\";\nimport { isChildSession } from \"../contract/session-tree.js\";\nimport { getSessionAgentName, getTotalTokens } from \"./dashboard.js\";\n\ninterface ProjectMetrics {\n messages: number;\n tokens: number;\n cost: number;\n hasEstimatedCost: boolean;\n agentStats: Map<string, ApiProjectAgentStat>;\n}\n\nfunction emptyMetrics(): ProjectMetrics {\n return { messages: 0, tokens: 0, cost: 0, hasEstimatedCost: false, agentStats: new Map() };\n}\n\n/**\n * Fold per-session totals into the project groups they belong to. Sessions with\n * no resolved project identity contribute to nothing.\n */\nexport function attachProjectMetrics(\n projects: ProjectGroup[],\n sessions: SessionHead[],\n): ApiProjectGroup[] {\n const metrics = new Map<string, ProjectMetrics>();\n\n for (const session of sessions) {\n if (isChildSession(session)) continue;\n const identity = session.project_identity;\n if (!identity) continue;\n\n const key = getProjectIdentityKey(identity);\n let current = metrics.get(key);\n if (!current) {\n current = emptyMetrics();\n metrics.set(key, current);\n }\n\n const tokens = getTotalTokens(session.stats);\n const cost = session.stats.total_cost ?? 0;\n current.messages += session.stats.message_count;\n current.tokens += tokens;\n current.cost += cost;\n if (session.stats.cost_source === \"estimated\") current.hasEstimatedCost = true;\n\n const agentName = getSessionAgentName(session);\n const agent = current.agentStats.get(agentName);\n if (agent) {\n agent.sessions += 1;\n agent.messages += session.stats.message_count;\n agent.tokens += tokens;\n agent.cost += cost;\n } else {\n current.agentStats.set(agentName, {\n name: agentName,\n sessions: 1,\n messages: session.stats.message_count,\n tokens,\n cost,\n });\n }\n }\n\n return projects.map((project) => {\n const metric = metrics.get(\n getProjectIdentityKey({ kind: project.identityKind, key: project.identityKey }),\n );\n return {\n ...project,\n messages: metric?.messages ?? 0,\n tokens: metric?.tokens ?? 0,\n cost: metric?.cost ?? 0,\n cost_source:\n metric && metric.cost > 0\n ? metric.hasEstimatedCost\n ? \"estimated\"\n : \"recorded\"\n : undefined,\n agentStats: [...(metric?.agentStats.values() ?? [])].sort((a, b) => b.sessions - a.sessions),\n };\n });\n}\n","/**\n * Deep session search: single owner for search-query interpretation\n * (qualifier parsing/merging), source selection between the live LiveSnapshot\n * snapshot (\"recent\" path) and the SQLite search index (FTS / file-activity\n * paths), and cross-source result merging.\n */\nimport type { SessionHead } from \"../types/index.js\";\nimport type { SearchResult } from \"../contract/index.js\";\nimport {\n filterIndexedSessionReferences,\n mergeSearchQueryOptions,\n searchSessions,\n sessionMatchesSearchCost,\n type ParsedSearchQuery,\n type SearchOptions,\n} from \"../discovery/cache/search.js\";\nimport { searchFileActivitySessions } from \"../discovery/cache/file-activity.js\";\nimport {\n createProjectScopeMatcher,\n matchesProjectScope,\n type ProjectScopeMatcher,\n} from \"../projects/scope.js\";\nimport { matchesProjectIdentity } from \"../projects/identity.js\";\nimport { getSessionActivityTime } from \"../analytics/dashboard.js\";\n\nexport interface SessionSearchSnapshot {\n sessions: SessionHead[];\n byAgent: Record<string, SessionHead[]>;\n}\n\nexport function executeSessionSearch(\n query: string,\n options: SearchOptions,\n snapshot: SessionSearchSnapshot,\n): SearchResult[] {\n const merged = mergeSearchQueryOptions(query, options);\n\n if (!needsIndexedSearch(merged.text, merged.options)) {\n return searchRecentSessions(snapshot, merged.options);\n }\n\n return searchIndexedSessions(query, merged.text, merged.parsed, merged.options);\n}\n\n// Qualifiers alone (tag:/cost:/agent:/project:) do not force the indexed\n// path -- only text, file, fileKind, or tool do. A qualifier-only query is\n// treated identically to an empty query for source selection.\nfunction needsIndexedSearch(textQuery: string, options: SearchOptions): boolean {\n return Boolean(textQuery || options.file || options.fileKind || options.tools?.length);\n}\n\nfunction matchesRecentSearchFilters(\n session: SessionHead,\n options: SearchOptions,\n projectScope: ProjectScopeMatcher | null,\n): boolean {\n if (options.projectKind || options.projectKey) {\n if (\n !options.projectKind ||\n !options.projectKey ||\n !matchesProjectIdentity(session.project_identity, {\n kind: options.projectKind,\n key: options.projectKey,\n })\n ) {\n return false;\n }\n }\n if (projectScope && !matchesProjectScope(session, projectScope)) return false;\n if (options.project) {\n const projectNeedle = options.project.toLowerCase();\n const projectText = [\n session.project_identity?.key,\n session.project_identity?.displayName,\n session.directory,\n ]\n .filter(Boolean)\n .join(\"\\n\")\n .toLowerCase();\n if (!projectText.includes(projectNeedle)) return false;\n }\n if (options.tags?.length && !options.tags.every((tag) => session.smart_tags?.includes(tag))) {\n return false;\n }\n if (!sessionMatchesSearchCost(session, options)) return false;\n return true;\n}\n\n// Evaluates filters answerable from SessionHead. File and tool predicates\n// require the indexed batch seam in filterSessionSearchCandidates.\nexport function matchesSessionSearchFilters(\n agentName: string,\n session: SessionHead,\n options: SearchOptions,\n projectScope: ProjectScopeMatcher | null = null,\n): boolean {\n if (options.agent && agentName !== options.agent) return false;\n const activity = getSessionActivityTime(session);\n if (options.from != null && activity < options.from) return false;\n if (options.to != null && activity > options.to) return false;\n return matchesRecentSearchFilters(session, options, projectScope);\n}\n\nfunction sessionReferenceKey(agentName: string, sessionId: string): string {\n return `${agentName}\\u0000${sessionId}`;\n}\n\nexport function filterSessionSearchCandidates(\n candidates: SearchResult[],\n options: SearchOptions,\n): SearchResult[] {\n const projectScope = options.cwd ? createProjectScopeMatcher(options.cwd) : null;\n const headMatches = candidates.filter((candidate) =>\n matchesSessionSearchFilters(\n candidate.reference.agentName,\n candidate.session,\n options,\n projectScope,\n ),\n );\n if (!options.file && !options.fileKind && !options.tools?.length) return headMatches;\n\n const indexedMatches = filterIndexedSessionReferences(\n headMatches.map((candidate) => ({\n agentName: candidate.reference.agentName,\n sessionId: candidate.reference.sessionId,\n })),\n {\n file: options.file,\n fileKind: options.fileKind,\n tools: options.tools,\n },\n );\n return headMatches.filter((candidate) =>\n indexedMatches.has(\n sessionReferenceKey(candidate.reference.agentName, candidate.reference.sessionId),\n ),\n );\n}\n\nfunction searchRecentSessions(\n snapshot: SessionSearchSnapshot,\n options: SearchOptions,\n): SearchResult[] {\n const projectScope = options.cwd ? createProjectScopeMatcher(options.cwd) : null;\n const entries = options.agent\n ? ([[options.agent, snapshot.byAgent[options.agent] ?? []]] as Array<[string, SessionHead[]]>)\n : Object.entries(snapshot.byAgent);\n\n return entries\n .flatMap(([agentName, sessions]) =>\n sessions\n .filter((session) => matchesSessionSearchFilters(agentName, session, options, projectScope))\n .map((session) => ({\n reference: { agentName, sessionId: session.id },\n session,\n })),\n )\n .sort(\n (a, b) =>\n (b.session.time_updated ?? b.session.time_created) -\n (a.session.time_updated ?? a.session.time_created),\n )\n .slice(0, options.limit ?? 50)\n .map(({ reference, session }) => ({\n reference,\n session,\n snippet: `Recent session · ${session.directory}`,\n matchType: \"recent\",\n }));\n}\n\n// `options.file` already carries the qualifier's `file:`/`path:` value once\n// merged (options.file ?? filters.file), so the middle branch only matters\n// when options.file was merged from something other than this parse. When\n// the query has no qualifiers at all, a bare text search is also attempted\n// as a file-path search (usually a no-op match, but it is why plain text\n// queries still touch the file-activity path).\nfunction deriveFileQuery(query: string, parsed: ParsedSearchQuery, options: SearchOptions): string {\n return (\n options.file ??\n (!parsed.text ? parsed.filters.file : undefined) ??\n (!parsed.hasQualifiers && query ? parsed.text || query : \"\")\n );\n}\n\nfunction mergeSearchResultSources(results: SearchResult[], limit: number): SearchResult[] {\n const seen = new Set<string>();\n const merged: SearchResult[] = [];\n\n for (const result of results) {\n const key = sessionReferenceKey(result.reference.agentName, result.reference.sessionId);\n if (seen.has(key)) continue;\n seen.add(key);\n merged.push(result);\n if (merged.length >= limit) break;\n }\n\n return merged;\n}\n\nfunction canSkipSessionsSearch(fileQuery: string, textQuery: string): boolean {\n return Boolean(fileQuery && !textQuery);\n}\n\nfunction searchIndexedSessions(\n query: string,\n textQuery: string,\n parsed: ParsedSearchQuery,\n options: SearchOptions,\n): SearchResult[] {\n const fileQuery = deriveFileQuery(query, parsed, options);\n const fileResults = fileQuery ? searchFileActivitySessions(fileQuery, options) : [];\n const sessionResults = canSkipSessionsSearch(fileQuery, textQuery)\n ? []\n : searchSessions(query, options);\n const textMatchReferences =\n textQuery && options.file\n ? new Set(\n sessionResults.map((result) =>\n sessionReferenceKey(result.reference.agentName, result.reference.sessionId),\n ),\n )\n : null;\n const matchingFileResults = textMatchReferences\n ? fileResults.filter((result) =>\n textMatchReferences.has(\n sessionReferenceKey(result.reference.agentName, result.reference.sessionId),\n ),\n )\n : fileResults;\n\n return mergeSearchResultSources([...matchingFileResults, ...sessionResults], options.limit ?? 50);\n}\n"],"mappings":";;;AASA,SAAS,SAAS,OAAgD;AAChE,SAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,IACrE,QACD;AACN;AAEA,SAAS,eAAe,OAAoC;AAC1D,SAAO,OAAO,UAAU,YAAY,QAAQ,QAAQ;AACtD;AAEA,SAAS,aAAa,OAAoC;AACxD,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ;AACvE;AAEA,SAAS,UAAU,cAAkC;AACnD,SAAO,iBAAiB,SAAY,CAAC,IAAI,EAAE,aAAa;AAC1D;AAEA,SAAS,gBAAgB,QAA4B;AACnD,SAAO,OAAO,KAAK,CAAC,UAAU,UAAU,MAAS;AACnD;AAEA,SAAS,gBACP,OACA,QACA,OACgB;AAChB,QAAM,SAAS,MAAM;AACrB,MAAI,WAAW,aAAa,WAAW,eAAe,WAAW,QAAS,QAAO;AACjF,MAAI,WAAW,UAAW,QAAO;AACjC,MAAI,SAAS,KAAM,QAAO;AAC1B,MAAI,WAAW,OAAW,QAAO;AACjC,SAAO;AACT;AAEA,SAAS,kBAAkB,OAAyC;AAClE,QAAM,cAAc,MAAM,YAAY,MAAM;AAC5C,QAAM,SAAS,OAAO;IACpB,OAAO,QAAQ,KAAK,EAAE;MACpB,CAAC,CAAC,GAAG,MACH,CAAC,CAAC,UAAU,SAAS,aAAa,UAAU,UAAU,SAAS,YAAY,MAAM,EAAE;QACjF;MACF;IACJ;EACF;AACA,MAAI,OAAO,KAAK,MAAM,EAAE,WAAW,EAAG,QAAO;AAE7C,QAAM,WAAW,SAAS,WAAW;AACrC,SAAO,WAAW,EAAE,GAAG,UAAU,GAAG,OAAO,IAAI;AACjD;AAEA,SAAS,mBAAmB,OAAgB,YAAoD;AAC9F,QAAM,QAAQ,SAAS,KAAK,KAAK,CAAC;AAClC,QAAM,QAAQ,aAAa,MAAM,OAAO,MAAM,WAAW,WAAW,KAAK;AACzE,QAAM,SAAS,aAAa,MAAM,QAAQ,MAAM,QAAQ,WAAW,MAAM;AACzE,QAAM,QAAQ,MAAM;AACpB,QAAM,WAAW,kBAAkB,KAAK;AAExC,SAAO;IACL,QAAQ,gBAAgB,OAAO,QAAQ,KAAK;IAC5C,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;IACvC,GAAI,WAAW,SAAY,EAAE,OAAO,IAAI,CAAC;IACzC,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;IACvC,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;EAC/C;AACF;AAEA,SAAS,SAAS,OAAwB;AACxC,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,SAAS,SAAS,KAAK;AAC7B,MAAI,CAAC,OAAQ,QAAO;AACpB,SAAO,SAAS,OAAO,QAAQ,OAAO,QAAQ,OAAO,OAAO;AAC9D;AAEA,SAAS,kBACP,OACA,cACiB;AACjB,QAAM,kBAAkB,MAAM,oBAAoB,SAAS,SAAS;AACpE,QAAM,OAAO,SAAS,MAAM,SAAS,oBAAoB,SAAS,MAAM,SAAS,MAAM,MAAM;AAC7F,SAAO,OAAO,EAAE,MAAM,QAAQ,MAAM,iBAAiB,GAAG,UAAU,YAAY,EAAE,IAAI;AACtF;AAEA,SAAS,mBACP,OACA,cACkB;AAClB,QAAM,OAAO,eAAe,MAAM,IAAI;AACtC,QAAM,MAAM,eAAe,MAAM,GAAG;AACpC,QAAM,YAAY,eAAe,MAAM,SAAS;AAEhD,MAAI,QAAQ,WAAW;AACrB,WAAO;MACL,MAAM;MACN;MACA;MACA,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;MACrB,GAAG,UAAU,YAAY;IAC3B;EACF;AACA,MAAI,KAAK;AACP,WAAO;MACL,MAAM;MACN;MACA,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC;MACvB,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;MACjC,GAAG,UAAU,YAAY;IAC3B;EACF;AACA,SAAO;AACT;AAEA,SAAS,kBACP,OACA,cACiB;AACjB,QAAM,QAAQ,eAAe,MAAM,KAAK;AACxC,QAAM,SAAS,eAAe,MAAM,MAAM;AAC1C,QAAM,OAAO,eAAe,MAAM,IAAI,GAAG,KAAK,KAAK,OAAO,QAAQ,cAAc,EAAE,EAAE,KAAK;AACzF,MAAI,CAAC,KAAM,QAAO;AAElB,SAAO;IACL,MAAM;IACN;IACA,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;IACzB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;IAC3B,OAAO,mBAAmB,MAAM,OAAO,KAAK;IAC5C,GAAG,UAAU,YAAY;EAC3B;AACF;AAEA,SAAS,qBAAqB,OAAoC;AAChE,QAAM,OAAO,SAAS,KAAK;AAC3B,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,eAAe,aAAa,KAAK,YAAY;AAEnD,MAAI,KAAK,SAAS,UAAU,KAAK,SAAS,aAAa;AACrD,QAAI,OAAO,KAAK,SAAS,SAAU,QAAO;AAC1C,WAAO,EAAE,MAAM,KAAK,MAAM,MAAM,KAAK,MAAM,GAAG,UAAU,YAAY,EAAE;EACxE;AACA,MAAI,KAAK,SAAS,OAAQ,QAAO,kBAAkB,MAAM,YAAY;AACrE,MAAI,KAAK,SAAS,QAAS,QAAO,mBAAmB,MAAM,YAAY;AACvE,MAAI,KAAK,SAAS,OAAQ,QAAO,kBAAkB,MAAM,YAAY;AACrE,SAAO;AACT;AAEO,SAAS,sBAAsB,OAA+B;AACnE,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO,CAAC;AACnC,SAAO,MAAM,QAAQ,CAAC,SAAS;AAC7B,UAAM,aAAa,qBAAqB,IAAI;AAC5C,WAAO,aAAa,CAAC,UAAU,IAAI,CAAC;EACtC,CAAC;AACH;AClJO,SAAS,2BACd,UACA,MACsB;AACtB,QAAM,sBAAsB,oBAAI,IAAmC;AACnE,QAAM,qBAAqB,oBAAI,IAA8B;AAC7D,QAAMA,cAAa,CAAC,WAAmB,cAAsB,GAAG,SAAS,KAAK,SAAS;AACvF,QAAM,aAAa,CAAC,SAAgC;AAClD,UAAM,MAAMA,YAAW,KAAK,UAAU,WAAW,KAAK,UAAU,SAAS;AACzE,uBAAmB,OAAO,GAAG;AAC7B,wBAAoB,IAAI,KAAK,IAAI;EACnC;AACA,QAAM,aAAa,CAAC,SAA2B;AAC7C,UAAM,MAAMA,YAAW,KAAK,WAAW,KAAK,SAAS;AACrD,wBAAoB,OAAO,GAAG;AAC9B,uBAAmB,IAAI,KAAK,IAAI;EAClC;AAEA,aAAW,QAAQ,SAAS,oBAAqB,YAAW,IAAI;AAChE,aAAW,QAAQ,SAAS,mBAAoB,YAAW,IAAI;AAC/D,aAAW,QAAQ,KAAK,oBAAqB,YAAW,IAAI;AAC5D,aAAW,QAAQ,KAAK,mBAAoB,YAAW,IAAI;AAE3D,SAAO;IACL,MAAM;IACN,eAAe,MAAM,KAAK,oBAAI,IAAI,CAAC,GAAG,SAAS,eAAe,GAAG,KAAK,aAAa,CAAC,CAAC;IACrF,aAAa,SAAS,cAAc,KAAK;IACzC,iBAAiB,SAAS,kBAAkB,KAAK;IACjD,iBAAiB,SAAS,kBAAkB,KAAK;IACjD,eAAe,KAAK;IACpB,WAAW,KAAK;IAChB,qBAAqB,CAAC,GAAG,oBAAoB,OAAO,CAAC;IACrD,oBAAoB,CAAC,GAAG,mBAAmB,OAAO,CAAC;EACrD;AACF;ACxCO,SAAS,mBAAmB,WAA2B;AAC5D,QAAM,OAAO,IAAI,KAAK,SAAS;AAC/B,SAAO,IAAI,KAAK,KAAK,YAAY,GAAG,KAAK,SAAS,GAAG,KAAK,QAAQ,CAAC,EAAE,QAAQ;AAC/E;AAGO,SAAS,gBAAgB,WAAmB,MAAsB;AACvE,QAAM,OAAO,IAAI,KAAK,SAAS;AAC/B,SAAO,IAAI,KAAK,KAAK,YAAY,GAAG,KAAK,SAAS,GAAG,KAAK,QAAQ,IAAI,IAAI,EAAE,QAAQ;AACtF;AAGA,SAAS,oBAAoB,WAA2B;AACtD,QAAM,OAAO,IAAI,KAAK,SAAS;AAC/B,SAAO,KAAK,IAAI,KAAK,YAAY,GAAG,KAAK,SAAS,GAAG,KAAK,QAAQ,CAAC,IAAI;AACzE;AAGO,SAAS,kBAAkB,MAAc,IAAoB;AAClE,SAAO,KAAK,IAAI,GAAG,oBAAoB,EAAE,IAAI,oBAAoB,IAAI,IAAI,CAAC;AAC5E;AAGO,SAAS,iBAAiB,WAA2B;AAC1D,QAAM,OAAO,IAAI,KAAK,SAAS;AAC/B,SAAO,GAAG,OAAO,KAAK,YAAY,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,EAAE;IACnF;IACA;EACF,CAAC,IAAI,OAAO,KAAK,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC;AAC9C;ACnBO,IAAM,yBAAyB;EACpC;EACA;EACA;EACA;EACA;EACA;AACF;AASA,IAAM,cAAc,IAAI,IAAY,sBAAsB;AAEnD,SAAS,sBAAsB,OAA6C;AACjF,SAAO,YAAY,IAAI,KAAK;AAC9B;AAMO,SAAS,sBAAsB,UAAsC;AAC1E,SAAO,GAAG,SAAS,IAAI,IAAI,SAAS,GAAG;AACzC;AAEO,SAAS,uBACd,UACA,UACS;AACT,SAAO,UAAU,SAAS,SAAS,QAAQ,SAAS,QAAQ,SAAS;AACvE;ACjDO,IAAM,qBAAqB;AAE3B,SAAS,0BAA0B,WAA+C;AACvF,SAAO;IACL,WAAW,UAAU,UAAU,KAAK,EAAE,YAAY;IAClD,WAAW,UAAU;EACvB;AACF;AAEO,SAAS,sBAAsB,OAAwC;AAC5E,QAAM,iBAAiB,MAAM,QAAQ,GAAG;AACxC,MAAI,kBAAkB,KAAK,mBAAmB,MAAM,SAAS,EAAG,QAAO;AAEvE,QAAM,YAAY,MAAM,MAAM,GAAG,cAAc,EAAE,KAAK,EAAE,YAAY;AACpE,MAAI,CAAC,UAAW,QAAO;AACvB,SAAO;IACL;IACA,WAAW,MAAM,MAAM,iBAAiB,CAAC;EAC3C;AACF;AAEO,SAAS,uBAAuB,WAAqC;AAC1E,QAAM,aAAa,0BAA0B,SAAS;AACtD,SAAO,GAAG,WAAW,SAAS,IAAI,WAAW,SAAS;AACxD;AAEO,SAAS,mBAAmB,SAAmC;AACpE,SAAO,sBAAsB,QAAQ,IAAI,GAAG,aAAa;AAC3D;AAOO,SAAS,eAAe,WAA2B;AACxD,SAAO,IAAI,mBAAmB,UAAU,KAAK,EAAE,YAAY,CAAC,CAAC;AAC/D;AAOO,SAAS,iBAAiB,WAAqC;AACpE,QAAM,aAAa,0BAA0B,SAAS;AACtD,SAAO,GAAG,eAAe,WAAW,SAAS,CAAC,IAAI,mBAAmB,WAAW,SAAS,CAAC;AAC5F;AC/BO,SAAS,2BAA2B,GAAgB,GAAwB;AACjF,UAAQ,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE;AACnE;AAEO,SAAS,uBAAuB,UAAwC;AAC7E,WAAS,QAAQ,GAAG,QAAQ,SAAS,QAAQ,SAAS,GAAG;AACvD,QAAI,2BAA2B,SAAS,QAAQ,CAAC,GAAI,SAAS,KAAK,CAAE,IAAI,GAAG;AAC1E,aAAO,CAAC,GAAG,QAAQ,EAAE,KAAK,0BAA0B;IACtD;EACF;AACA,SAAO,CAAC,GAAG,QAAQ;AACrB;AAUO,SAAS,oBAAoB,QAAwC;AAC1E,QAAM,SAAS,OAAO,OAAO,CAAC,UAAU,MAAM,SAAS,CAAC;AACxD,MAAI,OAAO,WAAW,EAAG,QAAO,CAAC;AACjC,MAAI,OAAO,WAAW,EAAG,QAAO,CAAC,GAAG,OAAO,CAAC,CAAE;AAE9C,QAAM,QAAQ,OAAO,OAAO,CAAC,KAAK,UAAU,MAAM,MAAM,QAAQ,CAAC;AACjE,QAAM,SAAwB,CAAC;AAC/B,QAAM,UAAU,MAAM,KAAK,EAAE,QAAQ,OAAO,OAAO,GAAG,MAAM,CAAC;AAE7D,WAAS,WAAW,GAAG,WAAW,OAAO,YAAY,GAAG;AACtD,QAAI,OAAO;AACX,aAAS,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS,GAAG;AACrD,YAAM,SAAS,QAAQ,KAAK;AAC5B,UAAI,UAAU,OAAO,KAAK,EAAG,OAAQ;AACrC,UACE,SAAS,MACT,2BAA2B,OAAO,KAAK,EAAG,MAAM,GAAI,OAAO,IAAI,EAAG,QAAQ,IAAI,CAAE,CAAE,IAAI,GACtF;AACA,eAAO;MACT;IACF;AACA,WAAO,KAAK,OAAO,IAAI,EAAG,QAAQ,IAAI,CAAE,CAAE;AAC1C,YAAQ,IAAI,KAAM;EACpB;AAEA,SAAO;AACT;ACjEA,SAAS,aAAa,WAA6D;AACjF,SAAO,GAAG,UAAU,UAAU,KAAK,EAAE,YAAY,CAAC,KAAK,UAAU,SAAS;AAC5E;AAEA,SAAS,WAAW,SAA8B;AAChD,SAAO,GAAG,mBAAmB,OAAO,CAAC,KAAK,QAAQ,EAAE;AACtD;AAEA,SAAS,oBAAoB,SAAsB,MAAe,IAAsB;AACtF,QAAM,WAAW,QAAQ,gBAAgB,QAAQ;AACjD,UAAQ,QAAQ,QAAQ,YAAY,UAAU,MAAM,QAAQ,YAAY;AAC1E;AAEO,SAAS,eAAe,SAA+B;AAC5D,SAAO,QAAQ,oBAAoB;AACrC;AAEO,SAAS,gBAAgB,UAAwC;AACtE,SAAO,SAAS,OAAO,CAAC,YAAY,CAAC,QAAQ,gBAAgB;AAC/D;AAMO,SAAS,kCACd,UACA,MACA,IACe;AACf,MAAI,QAAQ,QAAQ,MAAM,KAAM,QAAO;AAEvC,QAAM,YAAY,IAAI,IAAI,SAAS,IAAI,UAAU,CAAC;AAClD,QAAM,mBAAmB,oBAAI,IAAsB;AAEnD,aAAW,WAAW,UAAU;AAC9B,UAAM,SAAS,QAAQ;AACvB,QAAI,CAAC,UAAU,CAAC,UAAU,IAAI,aAAa,MAAM,CAAC,EAAG;AACrD,UAAM,YAAY,aAAa,MAAM;AACrC,UAAM,WAAW,iBAAiB,IAAI,SAAS;AAC/C,QAAI,SAAU,UAAS,KAAK,WAAW,OAAO,CAAC;QAC1C,kBAAiB,IAAI,WAAW,CAAC,WAAW,OAAO,CAAC,CAAC;EAC5D;AAEA,QAAM,UAAU,oBAAI,IAAY;AAChC,QAAMC,WAAU,gBAAgB,QAAQ,EACrC,OAAO,CAAC,YAAY,oBAAoB,SAAS,MAAM,EAAE,CAAC,EAC1D,IAAI,UAAU;AAEjB,SAAOA,SAAQ,SAAS,GAAG;AACzB,UAAM,MAAMA,SAAQ,IAAI;AACxB,QAAI,QAAQ,IAAI,GAAG,EAAG;AACtB,YAAQ,IAAI,GAAG;AACf,eAAW,YAAY,iBAAiB,IAAI,GAAG,KAAK,CAAC,EAAG,CAAAA,SAAQ,KAAK,QAAQ;EAC/E;AAEA,SAAO,SAAS,OAAO,CAAC,YAAY,QAAQ,IAAI,WAAW,OAAO,CAAC,CAAC;AACtE;ACxDO,IAAM,sBAAsB;EACjC,IAAI;EACJ,MAAM;EACN,OAAO;EACP,WAAW;EACX,kBAAkB;IAChB,MAAM;IACN,KAAK;IACL,aAAa;EACf;EACA,cAAc;EACd,cAAc;EACd,OAAO;IACL,eAAe;IACf,oBAAoB;IACpB,qBAAqB;IACrB,YAAY;IACZ,aAAa;IACb,cAAc;IACd,yBAAyB;IACzB,2BAA2B;EAC7B;EACA,aAAa,EAAE,mBAAmB,IAAK;EACvC,YAAY,CAAC,QAAQ;EACrB,8BAA8B;AAChC;AAiCO,IAAM,gCAAgC;EAC3C,MAAM;EACN,eAAe,CAAC,YAAY;EAC5B,aAAa;EACb,iBAAiB;EACjB,iBAAiB;EACjB,eAAe;EACf,WAAW;EACX,qBAAqB;IACnB;MACE,WAAW,EAAE,WAAW,cAAc,WAAW,oBAAoB,GAAG;MACxE,SAAS;IACX;EACF;EACA,oBAAoB,CAAC;AACvB;AAEO,IAAM,wBAAwB;EACnC,QAAQ;IACN,UAAU;IACV,UAAU;IACV,QAAQ;IACR,MAAM;IACN,aAAa;IACb,gBAAgB;EAClB;EACA,UAAU;IACR;MACE,MAAM;MACN,aAAa;MACb,MAAM;MACN,UAAU;MACV,UAAU;MACV,QAAQ;IACV;EACF;EACA,eAAe,CAAC,EAAE,MAAM,cAAc,UAAU,GAAG,UAAU,GAAG,CAAC;EACjE,oBAAoB;IAClB,EAAE,MAAM,cAAc,OAAO,KAAK,QAAQ,MAAM,YAAY,KAAM,cAAc,IAAI;EACtF;EACA,mBAAmB,CAAC,EAAE,OAAO,mBAAmB,QAAQ,KAAM,UAAU,EAAE,CAAC;EAC3E,gBAAgB;IACd;MACE,WAAW,EAAE,WAAW,cAAc,WAAW,oBAAoB,GAAG;MACxE,SAAS;IACX;EACF;EACA,sBAAsB,CAAC;EACvB,QAAQ,EAAE,MAAM,SAAmB,IAAI,YAAmB,MAAM,EAAE;AACpE;;;AE/GA,SAAS,cAAAC,aAAY,eAAAC,cAAa,gBAAAC,eAAc,YAAAC,iBAAgB;AAChE,SAAS,QAAAC,OAAM,YAAAC,WAAU,WAAAC,gBAAe;ACDxC,SAAS,YAAY,aAAa,gBAAyC;AAC3E,SAAS,YAAY;AEDrB,SAAS,cAAAN,mBAAkB;AAC3B,SAAS,SAAS,gBAAgB;AAClC,SAAS,QAAAI,aAAY;ACFrB,SAAS,WAAW,UAAU,gBAAgB;AAC9C,SAAS,qBAAqB;ACD9B,SAAS,gBAAgB;AIAzB,SAAS,cAAAJ,aAAY,cAAc,YAAY,QAAQ,qBAAqB;AAC5E,SAAS,WAAAO,gBAAe;AACxB,SAAS,QAAAH,aAAY;ACSrB,SAAS,WAAW,cAAAJ,aAAY,WAAW,eAAAC,cAAa,YAAAE,iBAAgB;AACxE,SAAS,YAAAE,WAAU,SAAS,QAAAD,aAAY;AOZxC,SAAS,QAAAA,aAAY;ACIrB,SAAS,cAAAJ,mBAAkB;AAC3B,SAAS,YAAAK,WAAU,WAAAC,UAAS,QAAAF,aAAY;AACxC,SAAS,qBAAqB;AEN9B,SAAS,kBAAkB;AAC3B,SAAS,cAAAJ,aAAY,gBAAAE,eAAc,eAAAD,cAAa,YAAAE,iBAAgB;AAChE,SAAS,QAAAC,OAAM,YAAAC,WAAU,WAAAC,gBAAe;ACFxC,SAAS,cAAAN,aAAY,gBAAAE,eAAc,eAAAD,cAAa,YAAAE,iBAAgB;AAChE,SAAS,YAAAE,WAAU,WAAAC,UAAS,QAAAF,OAAM,eAAe;ACDjD;EACE,aAAAI;EACA,cAAAR;EACA,YAAAS;EACA,eAAAR;EACA,gBAAAC;EACA,YAAAQ;EACA,YAAAP;OAEK;AACP,SAAS,QAAAC,QAAM,YAAAC,iBAAgB;AEV/B,SAAS,cAAAL,cAAY,eAAAC,cAAa,gBAAAC,eAAc,YAAAC,iBAAgB;AAChE,SAAS,WAAAI,UAAS,YAAAI,iBAAgB;AAClC,SAAS,QAAAP,QAAM,iBAAiB;AEFhC,SAAS,cAAAJ,oBAAkB;AAC3B,SAAS,YAAAK,WAAU,QAAAD,cAAY;ACD/B,SAAS,WAAAG,UAAS,YAAAI,iBAAgB;AAClC,SAAS,QAAAP,cAAY;AEDrB,SAAS,4BAA4B;AACrC,SAAS,cAAc;AEDvB,SAAS,cAAAJ,cAAY,gBAAAE,qBAAoB;AACzC,SAAS,iBAAiB;ACD1B,YAAY,QAAQ;AACpB,YAAY,UAAU;AEDtB,SAAS,WAAAU,UAAS,WAAW;AGG7B,SAAS,cAAAZ,cAAY,UAAAa,SAAQ,kBAAkB;ACC/C,SAAS,cAAAb,oBAAkB;AAC3B,SAAS,QAAAI,cAAY;AACrB,SAAS,WAAAG,gBAAe;AUNxB,SAAS,WAAAA,UAAS,YAAAI,iBAAgB;AAClC,SAAS,QAAAP,cAAY;AjDgBrB,IAAI,gBAAqC,CAAC;AAEnC,SAAS,cAAc,KAA8B;AAC1D,gBAAc,KAAK,GAAG;AACxB;AAEO,SAAS,yBAAsC;AACpD,SAAO,cAAc,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;AAC5C;AAEO,SAAS,sBAAoD;AAClE,SAAO;AACT;AAWO,SAAS,gBAAgB,iBAAsD;AACpF,SAAO,cAAc,IAAI,CAAC,iBAAiB;AACzC,UAAM,QAAQ,aAAa,OAAO;AAClC,WAAO;MACL,MAAM,MAAM;MACZ,aAAa,MAAM;MACnB,MAAM,aAAa;MACnB,aAAa,aAAa;MAC1B,qBAAqB,aAAa;MAClC,OAAO,gBAAgB,MAAM,IAAI,KAAK;IACxC;EACF,CAAC;AACH;AGxCA,IAAI,cAAsC;AAQ1C,SAAS,WAAW,MAAwC;AAC1D,SAAO;IACL,KAAK,OAAO,QAAQ;AAClB,UAAI;AACF,aAAK,OAAO,OAAO,MAAM;MAC3B,QAAQ;MAAC;IACX;IACA,KAAK,OAAO,QAAQ;AAClB,UAAI;AACF,aAAK,KAAK,OAAO,MAAM;MACzB,QAAQ;MAAC;IACX;EACF;AACF;AAEO,SAAS,mBAAmB,MAAoC;AACrE,gBAAc,OAAO,WAAW,IAAI,IAAI;AAC1C;AAEO,SAAS,qBAA6C;AAC3D,SAAO;AACT;ADlCO,SAAS,cAAiB,SAAmC;AAClE,SAAO,EAAE,QAAQ,UAAU,MAAM,QAAQ;AAC3C;AAEO,SAAS,eAAkB,QAAuC;AACvE,SAAO,EAAE,QAAQ,WAAW,OAAO;AACrC;AAEO,SAAS,gBAAmB,QAAuC;AACxE,SAAO,EAAE,QAAQ,YAAY,OAAO;AACtC;AAEO,SAAS,iBAAoB,QAAyC;AAC3E,SAAO,OAAO,WAAW,WAAW,OAAO,OAAO;AACpD;AA4BO,SAAS,kBAAkB,cAAsB,SAAqC;AAC3F,MAAI,SAAS,QAAQ,QAAQ,eAAe,QAAQ,KAAM,QAAO;AACjE,MAAI,SAAS,MAAM,QAAQ,eAAe,QAAQ,GAAI,QAAO;AAC7D,SAAO;AACT;AAgEA,SAAS,eAAe,MAAwB,WAAiD;AAC/F,MAAI,gBAAgB,IAAK,QAAO,KAAK,IAAI,SAAS;AAClD,SAAQ,KAA0C,SAAS;AAC7D;AAOA,SAAS,mBAAmB,KAAuB,QAA+C;AAChG,SACE,OAAO,QAAQ,sBAAsB,YAAY,OAAO,sBAAsB,IAAI;AAEtF;AAeA,SAAS,sBACP,QACA,SACS;AACT,MAAI,SAAS,QAAQ,QAAQ,SAAS,MAAM,KAAM,QAAO;AACzD,QAAM,UAAU,QAAQ;AACxB,SAAO,OAAO,YAAY,YAAY,kBAAkB,SAAS,OAAO;AAC1E;AAQO,SAAS,mBACd,MACA,gBACA,YACA,SACmB;AACnB,QAAM,YAAY,IAAI,IAAI,eAAe,IAAI,CAAC,YAAY,QAAQ,EAAE,CAAC;AACrE,QAAM,gBAAgB,oBAAI,IAAY;AACtC,QAAM,aAAuB,CAAC;AAE9B,aAAW,OAAO,MAAM;AACtB,kBAAc,IAAI,IAAI,SAAS;AAC/B,UAAM,OAAO,eAAe,YAAY,IAAI,SAAS;AAGrD,UAAM,YACJ,UAAU,IAAI,IAAI,SAAS,KAC3B,MAAM,eAAe,IAAI,cACzB,mBAAmB,KAAK,IAAI;AAC9B,QAAI,CAAC,UAAW,YAAW,KAAK,IAAI,SAAS;EAC/C;AAEA,QAAM,aAAuB,CAAC;AAC9B,aAAW,WAAW,gBAAgB;AACpC,QAAI,cAAc,IAAI,QAAQ,EAAE,EAAG;AACnC,QAAI,CAAC,sBAAsB,eAAe,YAAY,QAAQ,EAAE,GAAG,OAAO,EAAG;AAC7E,eAAW,KAAK,QAAQ,EAAE;EAC5B;AAEA,SAAO,EAAE,YAAY,WAAW;AAClC;AAEO,IAAe,YAAf,MAAyB;EAuC9B,qBAAqB,UAAwC;AAC3D,WAAO;EACT;EAQA,OAAO,WAA2B;AAChC,WAAO,GAAG,KAAK,IAAI,MAAM,SAAS;EACpC;AACF;AAcO,IAAe,0BAAf,cAEG,UAAU;EACR,iBAAiB,oBAAI,IAAmB;EAC1C,kBAAkB,oBAAI,IAAmB;;;;;;EAajD,wBAAwB,YAAsB,OAAsC;AAClF,WAAO;EACT;EAEA,KAAK,SAA2C;AAC9C,UAAM,UAAU,KAAK,mBAAmB,OAAO;AAC/C,UAAM,WAA0B,CAAC;AACjC,aAAS,aAAa,EAAE,OAAO,QAAQ,QAAQ,WAAW,GAAG,UAAU,EAAE,CAAC;AAE1E,eAAW,CAAC,OAAO,MAAM,KAAK,QAAQ,QAAQ,GAAG;AAC/C,UAAI;AACF,cAAM,UAAU,KAAK,kBAAkB,OAAO,YAAY,OAAO;AACjE,YAAI,QAAS,UAAS,KAAK,OAAO;MACpC,SAAS,OAAO;AACd,2BAAmB,GAAG,KAAK,8BAA8B;UACvD,WAAW,KAAK;UAChB,YAAY,OAAO;UACnB,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;QAChE,CAAC;AACD;MACF,UAAA;AACE,iBAAS,aAAa;UACpB,OAAO,QAAQ;UACf,WAAW,QAAQ;UACnB,UAAU,SAAS;QACrB,CAAC;MACH;IACF;AAEA,WAAO;EACT;EAEA,oBAAmD;AACjD,WAAO,KAAK;EACd;EAEA,kBAAkB,MAA2C;AAC3D,SAAK,iBAAiB;EACxB;EAEU,UACR,OACA,eACA,UAA2B,CAAC,GACP;AACrB,UAAM,QAA6B,CAAC;AACpC,SAAK,gBAAgB,MAAM;AAE3B,UAAM,OAAO,CAAC,cAA4B;AACxC,UAAI;AACJ,UAAI;AACF,kBAAU,YAAY,WAAW,EAAE,eAAe,KAAK,CAAC;MAC1D,QAAQ;AACN;MACF;AAEA,iBAAW,SAAS,SAAS;AAC3B,cAAM,WAAW,KAAK,WAAW,MAAM,IAAI;AAC3C,YAAI,MAAM,YAAY,GAAG;AACvB,cAAI,QAAQ,cAAc,MAAO,MAAK,QAAQ;AAC9C;QACF;AACA,YAAI,CAAC,cAAc,KAAK,EAAG;AAE3B,YAAI;AACJ,YAAI;AACF,iBAAO,SAAS,QAAQ;QAC1B,QAAQ;AACN;QACF;AACA,YAAI,CAAC,kBAAkB,KAAK,SAAS,QAAQ,UAAU,EAAG;AAE1D,cAAM,KAAK,EAAE,MAAM,UAAU,KAAK,CAAC;AACnC,aAAK,gBAAgB,IAAI,UAAU,IAAI;MACzC;IACF;AAEA,eAAW,QAAQ,OAAO,UAAU,WAAW,CAAC,KAAK,IAAI,MAAO,MAAK,IAAI;AACzE,WAAO;EACT;EAEU,kBAAkB,YAAuC;AACjE,WAAO;MACL,MAAM;MACN,MAAM,KAAK,gBAAgB,IAAI,UAAU,KAAK,SAAS,UAAU;IACnE;EACF;EAEU,gBAAgB,UAAwC;AAChE,QAAI,CAAC,SAAU,QAAO;AACtB,QAAI;AACF,aAAO,SAAS,QAAQ,EAAE;IAC5B,QAAQ;AACN,aAAO;IACT;EACF;;;;;EAMA,gBAAgB,iBAAyB,gBAAkD;AACzF,UAAM,cAAc,KAAK,mBAAmB;AAC5C,UAAM,OAAO,mBAAmB,aAAa,gBAAgB,KAAK,cAAc;AAChF,UAAM,aAAa,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,KAAK,YAAY,GAAG,KAAK,UAAU,CAAC,CAAC;AAExE,WAAO;MACL,YAAY,WAAW,SAAS;MAChC;MACA,WAAW,KAAK,IAAI;MACpB,MAAM;IACR;EACF;;;;;;EAOA,gBACE,gBACA,YACA,MACe;AACf,UAAM,UAAU,QAAQ,KAAK,mBAAmB;AAChD,UAAM,aAAa,IAAI,IAAI,eAAe,IAAI,CAAC,YAAY,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAC;AACjF,UAAM,aAAa,IAAI,IAAI,KAAK,wBAAwB,YAAY,OAAO,CAAC;AAC5E,UAAM,aAAa,oBAAI,IAAY;AAEnC,eAAW,OAAO,SAAS;AACzB,iBAAW,IAAI,IAAI,SAAS;AAC5B,UAAI,CAAC,WAAW,IAAI,IAAI,SAAS,EAAG;AACpC,YAAM,OAAO,KAAK,kBAAkB,IAAI,UAAU;AAClD,UAAI,MAAM;AACR,mBAAW,IAAI,KAAK,IAAI,IAAI;MAC9B,OAAO;AACL,mBAAW,OAAO,IAAI,SAAS;AAC/B,aAAK,eAAe,OAAO,IAAI,SAAS;MAC1C;IACF;AAGA,eAAW,MAAM,YAAY;AAC3B,UAAI,CAAC,WAAW,IAAI,EAAE,GAAG;AACvB,mBAAW,OAAO,EAAE;AACpB,aAAK,eAAe,OAAO,EAAE;MAC/B;IACF;AAEA,WAAO,CAAC,GAAG,WAAW,OAAO,CAAC;EAChC;AACF;AAGO,IAAe,0BAAf,cAEG,wBAA+B;EAQvC,kBAAkB,YAAoB,SAAgD;AACpF,UAAM,OAAO,KAAK,qBAAqB,YAAY,OAAO;AAC1D,QAAI,MAAM;AACR,WAAK,eAAe;QAClB,KAAK;QACL,KAAK,sBAAsB,MAAM,KAAK,kBAAkB,UAAU,CAAC;MACrE;IACF;AACA,WAAO;EACT;EAEU,qBAA4C;IACpD;IACA;IACA;IACA;EACF,GAK6B;AAC3B,WAAO;MACL,GAAG;MACH,IAAI,KAAK;MACT,OAAO,KAAK;MACZ,YAAY,OAAO;MACnB,mBAAmB;MACnB,eAAe,OAAO,KAAK;MAC3B,WAAW,KAAK;MAChB,cAAc,KAAK,MAAM;MACzB,WAAW,KAAK;MAChB,WAAW,KAAK,gBAAgB,KAAK;IACvC;EACF;AACF;AAeO,IAAM,mBAAN,cAA+B,MAAM;EAC1C,YACW,WACA,OACT,SACA;AACA,UAAM,GAAG,SAAS,8BAA8B,KAAK,IAAI,OAAO;AAJvD,SAAA,YAAA;AACA,SAAA,QAAA;AAIT,SAAK,OAAO;EACd;EANW;EACA;AAMb;AAOO,SAAS,kBAAkB,QAA0B;AAC1D,SAAO,CAAC,QAAQ,GAAG,MAAM,MAAM;AACjC;AAEA,SAAS,WAAWU,OAAwD;AAC1E,MAAI;AACF,WAAO,SAASA,KAAI;EACtB,QAAQ;AACN,WAAO;EACT;AACF;AAGA,SAAS,wBAAwB,QAAwB;AACvD,SAAO,kBAAkB,MAAM,EAC5B,IAAI,CAACA,UAAS;AACb,UAAM,QAAQ,WAAWA,KAAI;AAC7B,WAAO,QAAQ,GAAG,MAAM,IAAI,IAAI,KAAK,MAAM,MAAM,OAAO,CAAC,KAAK;EAChE,CAAC,EACA,KAAK,GAAG;AACb;AAEA,SAAS,wBAAwB,QAAwB;AACvD,SAAO,kBAAkB,MAAM,EAAE,OAAO,CAAC,QAAQA,UAAS;AACxD,UAAM,QAAQ,WAAWA,KAAI;AAC7B,WAAO,SAAS,MAAM,UAAU,SAAS,MAAM,UAAU;EAC3D,GAAG,CAAC;AACN;AAEO,IAAe,wBAAf,cAA6C,UAAU;EAClD,iBAAiB,oBAAI,IAA8B;EACrD,wBAAuC;;EAMrC,gBAAgB,WAAyB;AACjD,UAAM,SAAS,KAAK,gBAAgB;AACpC,QAAI,CAAC,OAAQ;AACb,SAAK,eAAe,IAAI,WAAW,EAAE,IAAI,WAAW,YAAY,OAAO,CAAC;EAC1E;EAEA,oBAAmD;AACjD,WAAO,KAAK;EACd;EAEA,kBAAkB,MAA2C;AAC3D,SAAK,iBAAiB;EACxB;;;;;;;;;EAUA,gBAAgB,gBAAwB,iBAAmD;AACzF,UAAM,SAAS,KAAK,gBAAgB;AACpC,QAAI,CAAC,UAAU,CAAC,WAAW,MAAM,GAAG;AAClC,aAAO,EAAE,YAAY,OAAO,WAAW,KAAK,IAAI,EAAE;IACpD;AAEA,QAAI;AACF,YAAM,cAAc,wBAAwB,MAAM;AAClD,YAAM,WAAW,KAAK;AACtB,WAAK,wBAAwB;AAG7B,YAAM,aACJ,YAAY,OACR,wBAAwB,MAAM,IAAI,iBAClC,gBAAgB;AACtB,aAAO;QACL;QACA,WAAW,KAAK,IAAI;MACtB;IACF,QAAQ;AACN,aAAO,EAAE,YAAY,OAAO,WAAW,KAAK,IAAI,EAAE;IACpD;EACF;;EAGA,gBAAgB,iBAAgC,aAAsC;AACpF,WAAO,KAAK,KAAK;EACnB;AACF;AE9kBO,SAAS,YAAY,MAA6B;AACvD,QAAM,QAAQ,QAAQ,IAAI,IAAI;AAC9B,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO;AACT;AAEA,SAAS,iBAAiB,OAAgC;AACxD,aAAW,KAAK,OAAO;AACrB,QAAId,YAAW,CAAC,EAAG,QAAO;EAC5B;AACA,SAAO;AACT;AAEO,SAAS,kBAA0B;AACxC,QAAM,MAAM,YAAY,eAAe;AACvC,MAAI,IAAK,QAAO;AAEhB,QAAM,IAAI,SAAS;AACnB,MAAI,MAAM,SAAS;AACjB,WACE,YAAY,cAAc,KAAK,YAAY,SAAS,KAAKI,MAAK,QAAQ,GAAG,WAAW,OAAO;EAE/F;AAGA,SAAOA,MAAK,QAAQ,GAAG,UAAU,OAAO;AAC1C;AAEO,SAAS,gBAAgB,qBAA6B,mBAAmC;AAC9F,SAAO,YAAY,mBAAmB,KAAKA,MAAK,QAAQ,GAAG,iBAAiB;AAC9E;AC9BA,IAAM,mBAAmB,KAAK;AAEvB,UAAU,gBAAgB,SAAqD;AACpF,MAAI,QAAQ;AACZ,MAAI,UAAU;AACd,aAAW,QAAQ,QAAQ,MAAM,IAAI,GAAG;AACtC,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,CAAC,QAAS;AACd,aAAS;AACT,QAAI;AACF,YAAM,KAAK,MAAM,OAAO;IAC1B,QAAQ;AACN,iBAAW;IACb;EACF;AAIA,MAAI,UAAU,GAAG;AACf,uBAAmB,GAAG,KAAK,6BAA6B,EAAE,SAAS,MAAM,CAAC;EAC5E;AACF;AAQO,UAAU,mBACf,UACA,aAAa,kBACM;AACnB,QAAM,KAAK,SAAS,UAAU,GAAG;AACjC,MAAI;AACF,UAAM,SAAS,OAAO,MAAM,UAAU;AAEtC,UAAM,UAAU,IAAI,cAAc,MAAM;AAKxC,QAAIW,WAAoB,CAAC;AACzB,QAAI,YAAY,SAAS,IAAI,QAAQ,GAAG,YAAY,EAAE;AACtD,WAAO,YAAY,GAAG;AACpB,YAAM,UAAU,QAAQ,MAAM,OAAO,SAAS,GAAG,SAAS,CAAC;AAC3D,YAAM,YAAY,QAAQ,YAAY,IAAI;AAC1C,UAAI,cAAc,IAAI;AACpB,YAAI,QAASA,UAAQ,KAAK,OAAO;MACnC,OAAO;AACLA,iBAAQ,KAAK,QAAQ,MAAM,GAAG,SAAS,CAAC;AACxC,cAAM,WAAWA,SAAQ,KAAK,EAAE;AAChCA,mBAAU,CAAC,QAAQ,MAAM,YAAY,CAAC,CAAC;AACvC,mBAAW,QAAQ,SAAS,MAAM,IAAI,GAAG;AACvC,gBAAM,UAAU,KAAK,KAAK;AAC1B,cAAI,QAAS,OAAM;QACrB;MACF;AACA,kBAAY,SAAS,IAAI,QAAQ,GAAG,YAAY,EAAE;IACpD;AACAA,aAAQ,KAAK,QAAQ,IAAI,CAAC;AAC1B,UAAM,OAAOA,SAAQ,KAAK,EAAE,EAAE,KAAK;AACnC,QAAI,KAAM,OAAM;EAClB,UAAA;AACE,cAAU,EAAE;EACd;AACF;AAEO,UAAU,cAAc,UAAsD;AACnF,MAAI,QAAQ;AACZ,MAAI,UAAU;AACd,aAAW,QAAQ,mBAAmB,QAAQ,GAAG;AAC/C,aAAS;AACT,QAAI;AACF,YAAM,KAAK,MAAM,IAAI;IACvB,QAAQ;AACN,iBAAW;IACb;EACF;AAEA,MAAI,UAAU,GAAG;AACf,uBAAmB,GAAG,KAAK,6BAA6B,EAAE,SAAS,OAAO,SAAS,CAAC;EACtF;AACF;AEvFA,IAAM,gBAAgB;EACpB;EACA;EACA;EACA;AACF;AAEA,IAAM,uBAAuB,oBAAI,IAAI;EACnC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AACF,CAAC;AAED,SAAS,gBAAgB,KAAqB;AAC5C,SAAO,IAAI,OAAO,IAAI,GAAG,0BAA0B,GAAG,KAAK,IAAI;AACjE;AAEA,SAAS,oBAAoB,KAAqB;AAChD,SAAO,IAAI;IACT,sBAAsB,GAAG,0BAA0B,GAAG;IACtD;EACF;AACF;AAEA,SAAS,oBAAoB,KAAqB;AAChD,SAAO,IAAI,OAAO,QAAQ,GAAG,uBAAuB,IAAI;AAC1D;AAEA,SAAS,gBAAgB,KAAqB;AAC5C,SAAO,IAAI,OAAO,QAAQ,GAAG,aAAa,IAAI;AAChD;AAEO,SAAS,oBAAoB,OAAyB;AAC3D,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,aAAa,MAAM,KAAK,EAAE,YAAY,EAAE,QAAQ,UAAU,GAAG;AACnE,SAAO,qBAAqB,IAAI,UAAU;AAC5C;AAEO,SAAS,iBAAiB,MAA6B;AAC5D,MAAI,UAAU;AAEd,aAAW,OAAO,eAAe;AAC/B,cAAU,QAAQ,QAAQ,oBAAoB,GAAG,GAAG,IAAI;AACxD,cAAU,QAAQ,QAAQ,gBAAgB,GAAG,GAAG,EAAE;AAClD,cAAU,QAAQ,QAAQ,oBAAoB,GAAG,GAAG,EAAE;EACxD;AAEA,aAAW,OAAO,eAAe;AAC/B,cAAU,QAAQ,QAAQ,gBAAgB,GAAG,GAAG,EAAE;EACpD;AAEA,YAAU,QAAQ,QAAQ,sBAAsB,EAAE,EAAE,QAAQ,gBAAgB,EAAE;AAE9E,SAAO,QAAQ,KAAK,IAAI,UAAU;AACpC;AD1DA,IAAM,mBAAmB;AACzB,IAAM,mBAAmB;AAGlB,SAAS,mBAAmB,MAA6B;AAC9D,QAAM,UACJ,iBAAiB,IAAI,GACjB,MAAM,IAAI,EACX,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,GACzB,KAAK,KAAK;AAChB,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,UAAU,QAAQ,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAClD,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,QAAQ,MAAM,GAAG,gBAAgB;AAC1C;AAGO,SAAS,cAAcD,OAAgD;AAC5E,MAAI,CAACA,MAAM,QAAO;AAClB,QAAM,aAAaA,MAAK,KAAK,EAAE,QAAQ,WAAW,EAAE;AACpD,MAAI,CAAC,WAAY,QAAO;AACxB,QAAM,OAAO,SAAS,UAAU,EAAE,KAAK;AACvC,SAAO,QAAQ;AACjB;AAGO,SAAS,oBACd,UACA,SACA,WACQ;AACR,aAAW,aAAa,CAAC,UAAU,SAAS,SAAS,GAAG;AACtD,QAAI,WAAW;AACb,YAAM,aAAa,mBAAmB,SAAS;AAC/C,UAAI,WAAY,QAAO;IACzB;EACF;AACA,SAAO;AACT;AElCO,SAASE,qBAAoB,OAAyB;AAC3D,SAAO,oBAAuB,KAAK;AACrC;AAEO,SAAS,kBAAkB,MAAsB;AACtD,SAAO,iBAAiB,IAAI,KAAK;AACnC;AAEA,SAAS,aAAa,OAAyB;AAC7C,MAAI,OAAO,UAAU,SAAU,QAAO,kBAAkB,KAAK;AAC7D,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,YAAY;AACvD,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAEhD,QAAM,UAAmC,CAAC;AAC1C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,YAAQ,GAAG,IAAI,aAAa,KAAK;EACnC;AACA,SAAO;AACT;AAEO,SAAS,iBAAiB,MAAuC;AACtE,MAAI,KAAK,SAAS,UAAU,KAAK,SAAS,eAAe,KAAK,SAAS,QAAQ;AAC7E,UAAM,OAAO,kBAAkB,KAAK,IAAI;AACxC,WAAO,OAAO,EAAE,GAAG,MAAM,KAAK,IAAI;EACpC;AACA,MAAI,KAAK,SAAS,OAAQ,QAAO;AAEjC,QAAM,QAAQ,KAAK,QAAQ,kBAAkB,KAAK,KAAK,IAAI;AAC3D,QAAM,QAAQ;IACZ,GAAG,KAAK;IACR,GAAI,KAAK,MAAM,UAAU,SAAY,EAAE,OAAO,aAAa,KAAK,MAAM,KAAK,EAAE,IAAI,CAAC;IAClF,GAAI,KAAK,MAAM,WAAW,SAAY,EAAE,QAAQ,aAAa,KAAK,MAAM,MAAM,EAAE,IAAI,CAAC;IACrF,GAAI,KAAK,MAAM,UAAU,SAAY,EAAE,OAAO,aAAa,KAAK,MAAM,KAAK,EAAE,IAAI,CAAC;IAClF,GAAI,KAAK,MAAM,aAAa,SAAY,EAAE,UAAU,aAAa,KAAK,MAAM,QAAQ,EAAE,IAAI,CAAC;EAC7F;AACA,QAAM,EAAE,OAAO,QAAQ,GAAG,aAAa,IAAI;AAC3C,SAAO;IACL,GAAG;IACH,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;IACzB;EACF;AACF;AAEO,SAAS,kBAAkB,OAAqC;AACrE,SAAO,MAAM,QAAQ,CAAC,SAAS;AAC7B,UAAM,UAAU,iBAAiB,IAAI;AACrC,WAAO,UAAU,CAAC,OAAO,IAAI,CAAC;EAChC,CAAC;AACH;AAEO,SAAS,mBAAmB,SAAkC;AACnE,QAAM,QAAQ,kBAAkB,QAAQ,KAAK;AAC7C,MAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,SAAO,EAAE,GAAG,SAAS,MAAM;AAC7B;AAEO,SAAS,oBAAoB,UAAgC;AAClE,SAAO,SAAS,QAAQ,CAAC,YAAY;AACnC,UAAM,UAAU,mBAAmB,OAAO;AAC1C,WAAO,UAAU,CAAC,OAAO,IAAI,CAAC;EAChC,CAAC;AACH;AAEO,SAAS,sBAAsB,UAAoC;AACxE,aAAW,WAAW,UAAU;AAC9B,QAAI,QAAQ,SAAS,OAAQ;AAC7B,eAAW,QAAQ,QAAQ,OAAO;AAChC,UAAI,KAAK,SAAS,OAAQ;AAC1B,YAAM,QAAQ,mBAAmB,kBAAkB,KAAK,IAAI,CAAC;AAC7D,UAAI,MAAO,QAAO;IACpB;EACF;AACA,SAAO;AACT;AChFA,IAAA,kBAAA;EACE,8BAA8B;EAC9B,gCAAgC;EAChC,qBAAqB;EACrB,8BAA8B;EAC9B,gCAAgC;EAChC,+BAA+B;EAC/B,8BAA8B;EAC9B,4BAA4B;EAC5B,iBAAiB;EACjB,eAAe;EACf,qBAAqB;EACrB,gBAAgB;EAChB,uBAAuB;EACvB,0BAA0B;EAC1B,mBAAmB;EACnB,aAAa;EACb,yBAAyB;EACzB,eAAe;EACf,sBAAsB;EACtB,eAAe;AACjB;AELO,IAAM,mBAAmB;AAEzB,IAAM,oBAAoB;AAGjC,IAAM,0BAA0B,CAAC,QAAQ,QAAQ,UAAU;AAE3D,IAAM,UAAU,QAAQ,aAAa;AAErC,SAAS,mBAAmBF,OAAc,OAAsB;AAC9D,qBAAmB,GAAG,KAAK,8BAA8B;IACvD,MAAAA;IACA,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EAChE,CAAC;AACH;AAGA,SAAS,SAASA,OAAc,MAAoB;AAClD,MAAI,CAAC,WAAW,CAACd,YAAWc,KAAI,EAAG;AACnC,MAAI;AAEF,SAAKX,UAASW,KAAI,EAAE,OAAO,SAAW,KAAM;AAC5C,cAAUA,OAAM,IAAI;EACtB,SAAS,OAAO;AACd,uBAAmBA,OAAM,KAAK;EAChC;AACF;AASO,SAAS,uBAAuBA,OAAoB;AACzD,YAAUA,OAAM,EAAE,WAAW,MAAM,MAAM,iBAAiB,CAAC;AAE3D,WAASA,OAAM,gBAAgB;AACjC;AAGO,SAAS,oBAAoBA,OAAoB;AACtD,WAASA,OAAM,iBAAiB;AAClC;AAOO,SAAS,6BACd,WACA,MACM;AACN,MAAI;AACF,eAAW,SAASb,aAAY,SAAS,GAAG;AAC1C,UAAI,KAAK,KAAK,EAAG,qBAAoBG,MAAK,WAAW,KAAK,CAAC;IAC7D;EACF,SAAS,OAAO;AACd,uBAAmB,WAAW,KAAK;EACrC;AACF;AAGA,IAAM,kBAAkB,oBAAI,IAAY;AAGxC,SAAS,wBAAwB,QAAsB;AACrD,MAAI,gBAAgB,IAAI,MAAM,EAAG;AACjC,kBAAgB,IAAI,MAAM;AAE1B,QAAM,SAAS,GAAGC,UAAS,MAAM,CAAC;AAClC;IACE,QAAQ,MAAM;IACd,CAAC,SAAS,KAAK,WAAW,MAAM,KAAK,KAAK,SAAS,MAAM;EAC3D;AACF;AAOO,SAAS,wBAAwB,QAAsB;AAC5D,sBAAoB,MAAM;AAC1B,aAAW,UAAU,wBAAyB,qBAAoB,GAAG,MAAM,GAAG,MAAM,EAAE;AACtF,0BAAwB,MAAM;AAChC;ACxGA,IAAA,mBAAA;EACE,oBAAoB,CAAC,MAAM,MAAU,MAAU,IAAI;EACnD,qBAAqB,CAAC,MAAU,OAAU,QAAY,IAAI;EAC1D,qBAAqB,CAAC,MAAU,OAAU,QAAY,IAAI;EAC1D,oBAAoB,CAAC,MAAU,MAAU,QAAY,IAAI;EACzD,mBAAmB,CAAC,MAAU,OAAU,QAAY,IAAI;EACxD,qBAAqB,CAAC,MAAU,OAAU,QAAY,IAAI;EAC1D,qBAAqB,CAAC,MAAU,OAAU,QAAY,IAAI;EAC1D,iBAAiB,CAAC,OAAU,OAAU,SAAY,KAAS;EAC3D,mBAAmB,CAAC,OAAU,OAAU,SAAY,KAAS;EAC7D,mBAAmB,CAAC,MAAU,OAAU,QAAY,IAAI;EACxD,mBAAmB,CAAC,MAAU,OAAU,QAAY,IAAI;EACxD,mBAAmB,CAAC,MAAU,OAAU,QAAY,IAAI;EACxD,+BAA+B,CAAC,MAAU,OAAU,QAAY,IAAI;EACpE,+BAA+B,CAAC,MAAU,OAAU,QAAY,IAAI;EACpE,6BAA6B,CAAC,MAAU,OAAU,QAAY,IAAI;EAClE,WAAW,CAAC,MAAU,MAAU,MAAM,IAAI;EAC1C,gBAAgB,CAAC,MAAM,OAAW,MAAM,IAAI;EAC5C,gBAAgB,CAAC,MAAM,MAAM,MAAM,KAAM;EACzC,UAAU,CAAC,OAAW,MAAS,MAAM,MAAU;EAC/C,eAAe,CAAC,OAAQ,MAAM,MAAM,KAAM;EAC1C,SAAS,CAAC,QAAY,MAAS,MAAM,MAAO;EAC5C,WAAW,CAAC,QAAY,MAAS,MAAM,MAAO;EAC9C,iBAAiB,CAAC,QAAY,MAAS,MAAM,MAAO;EACpD,sBAAsB,CAAC,OAAQ,MAAU,MAAM,KAAM;EACrD,WAAW,CAAC,QAAY,OAAU,MAAM,MAAO;EAC/C,iBAAiB,CAAC,QAAY,OAAU,MAAM,MAAO;EACrD,iBAAiB,CAAC,QAAY,OAAU,MAAM,MAAO;EACrD,WAAW,CAAC,OAAW,OAAU,MAAM,KAAM;EAC7C,gBAAgB,CAAC,OAAQ,OAAW,MAAM,KAAM;EAChD,gBAAgB,CAAC,MAAM,QAAY,MAAM,IAAI;EAC7C,WAAW,CAAC,MAAU,MAAS,MAAM,IAAI;EACzC,cAAc,CAAC,OAAQ,MAAU,MAAM,KAAM;EAC7C,cAAc,CAAC,MAAM,MAAM,MAAM,IAAI;EACrC,2BAA2B,CAAC,MAAM,OAAW,MAAM,IAAI;EACvD,+BAA+B,CAAC,OAAQ,OAAW,MAAM,IAAI;EAC7D,+BAA+B,CAAC,MAAM,OAAW,MAAM,IAAI;EAC3D,iBAAiB,CAAC,OAAQ,OAAQ,MAAM,KAAM;EAC9C,qBAAqB,CAAC,OAAQ,OAAQ,MAAM,KAAM;EAClD,kCAAkC,CAAC,MAAM,OAAW,MAAM,IAAI;EAC9D,kBAAkB,CAAC,QAAY,MAAS,MAAM,MAAO;EACrD,oBAAoB,CAAC,MAAM,OAAW,MAAM,IAAI;AAClD;AFdA,IAAM,cACJ;AACF,IAAM,eAAe,KAAK,KAAK,KAAK;AACpC,IAAM,kBAAkB;AACxB,IAAM,qBAAqB;AAY3B,IAAI,YAA+B,EAAE,IAAI,GAAG,SAAS,aAAa,EAAE;AAEpE,IAAI,UAA4C;AAChD,cAAc;AAEd,SAAS,aAAa,KAAqB;AACzC,SAAO,IAAI,KAAK,EAAE,YAAY;AAChC;AAEA,SAAS,WAAW,OAAgB,UAA0B;AAC5D,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ;AACvE;AAEA,SAAS,cAAc;AACrB,SAAOD,MAAKG,SAAQ,GAAG,UAAU,UAAU;AAC7C;AAEA,SAAS,eAAe;AACtB,SAAOH,MAAK,YAAY,GAAG,sBAAsB;AACnD;AAEA,SAAS,eAA0C;AACjD,QAAM,MAAM,oBAAI,IAA0B;AAC1C,QAAM,WAAW;AACjB,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACpD,UAAM,CAAC,OAAO,QAAQ,aAAa,WAAW,WAAW,SAAS,IAAI;AACtE,QAAI,IAAI,aAAa,IAAI,GAAG;MAC1B,mBAAmB;MACnB,oBAAoB;MACpB,yBAAyB,eAAe,QAAQ;MAChD,uBAAuB,aAAa,QAAQ;MAC5C,uBAAuB,aAAa;MACpC,yBAAyB,aAAa;IACxC,CAAC;EACH;AACA,SAAO;AACT;AAEA,SAAS,kBAAkB,OAA0C;AACnE,QAAM,QAAQ,MAAM;AACpB,QAAM,SAAS,MAAM;AACrB,MAAI,OAAO,UAAU,YAAY,OAAO,WAAW,SAAU,QAAO;AAEpE,SAAO;IACL,mBAAmB;IACnB,oBAAoB;IACpB,yBAAyB,MAAM,mCAAmC,QAAQ;IAC1E,uBAAuB,MAAM,+BAA+B,QAAQ;IACpE,uBAAuB,MAAM,mCAAmC;IAChE,yBAAyB;MACvB,MAAM,+BAA+B,MAAM;MAC3C;IACF;EACF;AACF;AAEA,SAAS,uBAAuB,KAAmD;AACjF,QAAM,QAAQ,WAAW,IAAI,mBAAmB,GAAG,CAAC;AACpD,QAAM,SAAS,WAAW,IAAI,oBAAoB,GAAG,CAAC;AACtD,MAAI,SAAS,KAAK,UAAU,EAAG,QAAO;AAEtC,SAAO;IACL,mBAAmB;IACnB,oBAAoB;IACpB,yBAAyB,WAAW,IAAI,yBAAyB,GAAG,QAAQ,IAAI;IAChF,uBAAuB,WAAW,IAAI,uBAAuB,GAAG,QAAQ,GAAG;IAC3E,uBAAuB,WAAW,IAAI,uBAAuB,GAAG,MAAM;IACtE,yBAAyB,WAAW,IAAI,yBAAyB,GAAG,eAAe;EACrF;AACF;AAEA,SAAS,aAAa,KAAgC,MAAc,SAAuB;AACzF,QAAM,aAAa,aAAa,IAAI;AACpC,MAAI,IAAI,YAAY,OAAO;AAE3B,QAAM,aAAa,WAAW,QAAQ,GAAG;AACzC,MAAI,cAAc,GAAG;AACnB,UAAM,WAAW,WAAW,MAAM,aAAa,CAAC;AAChD,QAAI,CAAC,IAAI,IAAI,QAAQ,EAAG,KAAI,IAAI,UAAU,OAAO;EACnD;AACF;AAEA,SAAS,iBAAiB,MAA+D;AACvF,QAAM,MAAM,oBAAI,IAA0B;AAC1C,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,IAAI,GAAG;AAChD,UAAM,UAAU,kBAAkB,KAAK;AACvC,QAAI,QAAS,cAAa,KAAK,MAAM,OAAO;EAC9C;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB;AACvB,QAAMU,QAAO,aAAa;AAC1B,MAAI,CAACd,YAAWc,KAAI,EAAG;AAEvB,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,aAAaA,OAAM,OAAO,CAAC;AAIrD,QAAI,KAAK,IAAI,IAAI,OAAO,aAAa,cAAc;AACjD,YAAM,OAAO,aAAa;AAC1B,iBAAW,CAAC,MAAM,UAAU,KAAK,OAAO,QAAQ,OAAO,IAAI,GAAG;AAC5D,cAAM,UAAU,uBAAuB,UAAU;AACjD,YAAI,CAAC,QAAS;AACd,aAAK,IAAI,aAAa,IAAI,GAAG,OAAO;MACtC;AACA,kBAAY,EAAE,IAAI,UAAU,KAAK,GAAG,SAAS,KAAK;IACpD;EACF,QAAQ;EAER;AACF;AAEO,SAAS,qBAAgD;AAC9D,SAAO,UAAU;AACnB;AAGO,SAAS,uBAA0C;AACxD,SAAO;AACT;AAMO,SAAS,wBAAiC;AAC/C,MAAI,CAAC,QAAS,QAAO;AACrB,cAAY,EAAE,IAAI,UAAU,KAAK,GAAG,SAAS,QAAQ;AACrD,YAAU;AACV,qBAAmB,GAAG,OAAO,gCAAgC;IAC3D,YAAY,UAAU;IACtB,QAAQ,UAAU,QAAQ;EAC5B,CAAC;AACD,SAAO;AACT;AAGO,SAAS,oBAA6B;AAC3C,SAAO,YAAY;AACrB;AAEO,SAAS,mBAAmB,SAAgC;AACjE,SACE,QAAQ,oBAAoB,KAC5B,QAAQ,qBAAqB,KAC7B,QAAQ,wBAAwB,KAChC,QAAQ,0BAA0B;AAEtC;AAGA,SAAS,yBAAyBA,OAAc,SAA0C;AACxF,QAAM,gBAAgB,GAAGA,KAAI,IAAI,QAAQ,GAAG;AAC5C,QAAM,UAAU,KAAK,UAAU,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,OAAO,YAAY,OAAO,EAAE,CAAC;AAC3F,MAAI;AACF,2BAAuB,YAAY,CAAC;AACpC,kBAAc,eAAe,OAAO;AACpC,wBAAoB,aAAa;AACjC,eAAW,eAAeA,KAAI;EAChC,SAAS,OAAO;AACd,WAAO,eAAe,EAAE,OAAO,KAAK,CAAC;AACrC,uBAAmB,GAAG,KAAK,8BAA8B;MACvD,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAChE,CAAC;EACH;AACF;AAaA,eAAsB,oBAAoB,UAAiC,CAAC,GAAqB;AAC/F,QAAMA,QAAO,aAAa;AAC1B,MAAId,YAAWc,KAAI,GAAG;AACpB,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,aAAaA,OAAM,OAAO,CAAC;AACrD,UAAI,OAAO,OAAO,cAAc,YAAY,KAAK,IAAI,IAAI,OAAO,aAAa,cAAc;AACzF,eAAO;MACT;IACF,QAAQ;IAER;EACF;AAEA,QAAM,UAAU,YAAY,QAAQ,QAAQ,aAAa,kBAAkB;AAC3E,QAAM,SAAS,QAAQ,SAAS,YAAY,IAAI,CAAC,QAAQ,QAAQ,OAAO,CAAC,IAAI;AAE7E,qBAAmB,GAAG,OAAO,2BAA2B,EAAE,YAAY,UAAU,GAAG,CAAC;AACpF,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,aAAa,EAAE,OAAO,CAAC;AACpD,QAAI,CAAC,SAAS,GAAI,QAAO;AACzB,UAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,UAAM,SAAS,iBAAiB,IAAI;AACpC,QAAI,OAAO,SAAS,EAAG,QAAO;AAE9B,UAAM,OAAO,aAAa;AAC1B,eAAW,CAAC,MAAM,OAAO,KAAK,OAAO,QAAQ,GAAG;AAC9C,WAAK,IAAI,MAAM,OAAO;IACxB;AAEA,cAAU;AACV,6BAAyBA,OAAM,IAAI;AACnC,uBAAmB,GAAG,OAAO,6BAA6B;MACxD,YAAY,UAAU;MACtB,QAAQ,KAAK;IACf,CAAC;AACD,WAAO;EACT,SAAS,OAAO;AACd,uBAAmB,GAAG,KAAK,0BAA0B;MACnD,YAAY,UAAU;MACtB,SAAS,OAAO;MAChB,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAChE,CAAC;AACD,WAAO;EACT;AACF;AGzQA,IAAM,kBAAkB,OAAO;EAC7B,OAAO,QAAQ,eAAqC,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM;IAC1E,kBAAkB,GAAG;IACrB,kBAAkB,KAAK;EACzB,CAAC;AACH;AAEA,SAAS,kBAAkB,OAAuB;AAChD,SAAO,MAAM,KAAK,EAAE,YAAY,EAAE,WAAW,KAAK,GAAG;AACvD;AAEA,SAAS,aAAa,OAAuB;AAC3C,SAAO,MAAM,QAAQ,QAAQ,EAAE,EAAE,QAAQ,WAAW,EAAE;AACxD;AAEA,SAAS,oBAAoB,OAAuB;AAClD,QAAM,QAAQ,MAAM,MAAM,GAAG;AAC7B,SAAO,MAAM,MAAM,SAAS,CAAC,KAAK;AACpC;AAEA,SAAS,aAAa,OAAuB;AAC3C,SAAO,gBAAgB,KAAK,KAAK;AACnC;AAEA,SAAS,cAAc,UAA4B;AACjD,QAAM,aAAa,aAAa,kBAAkB,QAAQ,CAAC;AAC3D,QAAM,WAAW,oBAAoB,UAAU;AAC/C,QAAM,UAAU,aAAa,QAAQ;AACrC,QAAM,aAAa;IACjB;IACA,aAAa,UAAU;IACvB;IACA;IACA,aAAa,QAAQ;IACrB,UAAU,QAAQ;IAClB,qBAAqB,QAAQ;IAC7B,wBAAwB,QAAQ;IAChC,cAAc,QAAQ;IACtB,qBAAqB,QAAQ;EAC/B;AAEA,SAAO,CAAC,GAAG,IAAI,IAAI,WAAW,OAAO,OAAO,CAAC,CAAC;AAChD;AAEA,SAAS,gBAAgB,OAAe,UAAqC;AAC3E,QAAM,SAAS,SAAS,IAAI,KAAK;AACjC,MAAI,UAAU,mBAAmB,MAAM,EAAG,QAAO;AAEjD,QAAM,QAAQ,aAAa,KAAK;AAChC,MAAI,UAAU,OAAO;AACnB,UAAM,UAAU,SAAS,IAAI,KAAK;AAClC,QAAI,WAAW,mBAAmB,OAAO,EAAG,QAAO;EACrD;AAEA,SAAO;AACT;AAEA,SAAS,YAAY,OAAe,UAAqC;AACvE,MAAI,OAAsC;AAC1C,aAAW,CAAC,KAAK,OAAO,KAAK,SAAS,QAAQ,GAAG;AAC/C,QAAI,CAAC,mBAAmB,OAAO,EAAG;AAClC,QAAI,MAAM,WAAW,GAAG,GAAG,GAAG,KAAK,MAAM,WAAW,GAAG,GAAG,GAAG,KAAK,UAAU,KAAK;AAC/E,UAAI,CAAC,QAAQ,IAAI,SAAS,KAAK,CAAC,EAAE,OAAQ,QAAO,CAAC,KAAK,OAAO;IAChE;EACF;AACA,SAAO,OAAO,CAAC,KAAK;AACtB;AAMO,IAAM,kBAAmC;EAC9C,QAAQ,cAA2C;AACjD,UAAM,WAAW,mBAAmB;AACpC,UAAM,aAAa,cAAc,YAAY;AAE7C,eAAW,aAAa,YAAY;AAClC,YAAM,UAAU,gBAAgB,WAAW,QAAQ;AACnD,UAAI,QAAS,QAAO;IACtB;AAEA,eAAW,aAAa,YAAY;AAClC,YAAM,UAAU,YAAY,WAAW,QAAQ;AAC/C,UAAI,QAAS,QAAO;IACtB;AAEA,WAAO;EACT;AACF;AChFA,SAAS,SAAS,OAAmC;AACnD,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,KAAK,QAAQ,IAAI,QAAQ;AACpF;AAEO,SAAS,sBACd,OACA,OACqB;AACrB,MAAI,CAAC,SAAS,CAAC,MAAO,QAAO;AAE7B,QAAM,UAAU,gBAAgB,QAAQ,KAAK;AAC7C,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,YAAY,SAAS,MAAM,UAAU;AAC3C,QAAM,cAAc,SAAS,MAAM,YAAY;AAC/C,QAAM,QAAQ,KAAK,IAAI,GAAG,SAAS,MAAM,KAAK,IAAI,YAAY,WAAW;AACzE,QAAM,SAAS,SAAS,MAAM,MAAM;AACpC,QAAM,YAAY,SAAS,MAAM,SAAS;AAC1C,QAAM,oBAAoB,SAAS,MAAM,mBAAmB;AAE5D,QAAM,OACJ,QAAQ,QAAQ,oBAChB,SAAS,QAAQ,qBACjB,YAAY,QAAQ,wBACpB,YAAY,QAAQ,wBACpB,cAAc,QAAQ,0BACtB,oBAAoB,QAAQ;AAE9B,SAAO,OAAO,IAAI,EAAE,MAAM,OAAO,KAAK,QAAQ,CAAC,CAAC,GAAG,QAAQ,YAAY,IAAI;AAC7E;ACtCO,SAAS,kBACd,OACA,QACe;AACf,SAAO,sBAAsB,OAAO,MAAM,GAAG,QAAQ;AACvD;ACLO,SAAS,SAAS,OAAqD;AAC5E,MAAI,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,GAAG;AAC/D,WAAO;EACT;AACA,SAAO;AACT;AAGO,SAAS,SAAS,OAAoC;AAC3D,SAAO,OAAO,UAAU,WAAW,QAAQ;AAC7C;AAGO,SAAS,SAAS,OAAoC;AAC3D,SAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ;AACvE;AAGO,SAAS,QAAQ,OAAuC;AAC7D,SAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ;AACxC;AAOO,SAAS,oBAAoB,MAAmD;AACrF,MAAI;AACJ,MAAI;AACF,UAAM,KAAK,MAAM,IAAI;EACvB,QAAQ;AACN,WAAO;EACT;AACA,SAAO,SAAS,GAAG;AACrB;AAEA,IAAM,0BAA0B,oBAAI,IAAY;AAOzC,SAAS,oBAAoB,WAAmB,OAAqB;AAC1E,QAAM,MAAM,GAAG,SAAS,KAAK,KAAK;AAClC,MAAI,wBAAwB,IAAI,GAAG,EAAG;AACtC,0BAAwB,IAAI,GAAG;AAC/B,qBAAmB,GAAG,KAAK,8BAA8B,EAAE,WAAW,MAAM,CAAC;AAC/E;AAQO,SAAS,YACd,OACA,OACA,OACA,QACe;AACf,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,QAAM,SAAS,OAAO,KAAK;AAC3B,MAAI,WAAW,OAAW,qBAAoB,OAAO,KAAK;AAC1D,SAAO;AACT;AC/BO,IAAM,oBAAN,MAAwB;EAM7B,YAA6B,UAAuD,CAAC,GAAG;AAA3D,SAAA,UAAA;EAA4D;EAA5D;EALZ,WAAsB,CAAC;EACvB,mBAAmB,oBAAI,IAAsB;EACtD,mBAAmC;EACnC,sBAAsC;EAI9C,YAAkB;AAChB,SAAK,mBAAmB;AACxB,SAAK,sBAAsB;EAC7B;EAEA,cAAc,OAAwC;AACpD,UAAM,UAAU,KAAK,cAAc,KAAK;AACxC,SAAK,SAAS,KAAK,OAAO;AAC1B,SAAK,kBAAkB,QAAQ,KAAK;AAEpC,QAAI,QAAQ,SAAS,aAAa;AAChC,WAAK,mBAAmB;AACxB,UAAI,QAAQ,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,MAAM,GAAG;AACtD,aAAK,sBAAsB;MAC7B;IACF,WAAW,QAAQ,SAAS,QAAQ;AAClC,WAAK,UAAU;IACjB;AAEA,WAAO;EACT;EAEA,oBACE,MACA,OACA,UAII,CAAC,GACI;AACT,UAAM,UAAU,KAAK;AACrB,UAAM,WACJ,YAAY,SACX,QAAQ,aAAa,cACnB,KAAK,SAAS,SACX,CAAC,QAAQ,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,MAAM,IAClD,KAAK,SAAS,cACZ,CAAC,QAAQ,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,UAAU,KAAK,SAAS,MAAM,IAC1E;AAEV,UAAM,UAAU,WACZ,UACA,KAAK,cAAc,EAAE,GAAG,OAAO,MAAM,aAAa,OAAO,CAAC,IAAI,EAAE,CAAC;AAErE,QAAI,UAAU;AACZ,UAAI,QAAQ,gBAAiB,MAAK,gBAAgB,SAAS,IAAI;UAC1D,SAAQ,MAAM,KAAK,IAAI;AAC5B,WAAK,qBAAqB,SAAS,KAAK;IAC1C;AACA,QAAI,KAAK,SAAS,QAAQ;AACxB,WAAK,sBAAsB;IAC7B,WAAW,QAAQ,iBAAiB;AAClC,WAAK,sBAAsB;IAC7B;AACA,WAAO;EACT;EAEA,eACE,MACA,OACA,UAII,CAAC,GACI;AACT,UAAM,SACJ,QAAQ,WAAW,YACf,KAAK,mBACJ,KAAK,uBAAuB,KAAK;AACxC,UAAM,UAAU,SACZ,SACA,KAAK,cAAc;MACjB,GAAG;MACH,MAAM;MACN,MAAM,QAAQ,iBAAiB,QAAQ,iBAAiB,SAAS,MAAM;MACvE,OAAO,CAAC,IAAI;IACd,CAAC;AAEL,QAAI,QAAQ;AACV,cAAQ,MAAM,KAAK,IAAI;AACvB,WAAK,qBAAqB,SAAS,KAAK;AACxC,UAAI,QAAQ,eAAgB,SAAQ,OAAO;AAC3C,WAAK,iBAAiB,IAAI;IAC5B;AAEA,SAAK,mBAAmB;AACxB,WAAO;EACT;EAEA,yBAAyB,MAA4B;AACnD,QAAI,CAAC,KAAK,iBAAkB,QAAO;AACnC,SAAK,iBAAiB,MAAM,KAAK,IAAI;AACrC,WAAO;EACT;EAEA,eAAe,QAAgB,QAA2C;AACxE,UAAM,OAAO,KAAK,iBAAiB,IAAI,MAAM;AAC7C,QAAI,CAAC,KAAM,QAAO;AAClB,WAAO,IAAI;AACX,WAAO;EACT;EAEA,gBAAgB,QAAgB,YAAqC;AACnE,WAAO,KAAK,eAAe,QAAQ,CAAC,SAAS;AAC3C,YAAM,QAAQ,KAAK;AACnB,UAAI,WAAW,WAAW,OAAW,OAAM,SAAS,WAAW;AAC/D,UAAI,WAAW,WAAW,OAAW,OAAM,SAAS,WAAW;eACtD,WAAW,WAAW,UAAa,MAAM,WAAW,WAAW;AACtE,cAAM,SAAS;MACjB;AACA,UAAI,WAAW,aAAa,OAAW,OAAM,WAAW,WAAW;AACnE,UAAI,WAAW,QAAS,MAAK,iBAAiB,OAAO,MAAM;IAC7D,CAAC;EACH;EAEA,6BACE,QACA,UAAyF,CAAC,GACjF;AACT,aAAS,QAAQ,KAAK,SAAS,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;AACjE,YAAM,UAAU,KAAK,SAAS,KAAK;AACnC,UAAI,QAAQ,SAAS,eAAe,QAAQ,OAAQ;AACpD,cAAQ,SAAS;AACjB,UAAI,QAAQ,UAAU,OAAW,SAAQ,UAAU,QAAQ;AAC3D,UAAI,QAAQ,SAAS,OAAW,SAAQ,OAAO,QAAQ;AACvD,UAAI,QAAQ,eAAe,OAAW,SAAQ,cAAc,QAAQ;AACpE,aAAO;IACT;AACA,WAAO;EACT;EAEA,OAAO,WAA4C;AACjD,UAAM,WAAW,oBAAoB,KAAK,QAAQ;AAClD,UAAM,UAAU,KAAK,YAAY,QAAQ;AACzC,QAAI,CAAC,UAAW,QAAO,EAAE,UAAU,OAAO,QAAQ;AAElD,WAAO;MACL;MACA,OAAO;QACL,GAAG;QACH,GAAG;QACH,eAAe,SAAS;QACxB,aAAa,UAAU;MACzB;IACF;EACF;EAEQ,cAAc,OAAwC;AAC5D,UAAM,SAAS,KAAK,QAAQ,oBAAoB;AAChD,WAAO;MACL,IAAI,MAAM;MACV,MAAM,MAAM;MACZ,OAAO,SAAS,MAAM,QAAS,MAAM,SAAS;MAC9C,cAAc,MAAM;MACpB,MAAM,SAAS,MAAM,OAAQ,MAAM,QAAQ;MAC3C,OAAO,SAAS,MAAM,QAAS,MAAM,SAAS;MAC9C,UAAU,SAAS,MAAM,WAAY,MAAM,YAAY;MACvD,QAAQ,MAAM;MACd,MAAM,SAAS,MAAM,OAAQ,MAAM,QAAQ;MAC3C,aAAa,MAAM;MACnB,OAAO,MAAM,SAAS,CAAC;MACvB,aAAa,MAAM;MACnB,UAAU,MAAM;IAClB;EACF;EAEQ,kBAAkB,OAA4B;AACpD,eAAW,QAAQ,MAAO,MAAK,iBAAiB,IAAI;EACtD;EAEQ,iBAAiB,MAAyB;AAChD,QAAI,KAAK,SAAS,UAAU,KAAK,QAAQ;AACvC,WAAK,iBAAiB,IAAI,KAAK,QAAQ,IAAI;IAC7C;EACF;EAEQ,gBAAgB,SAAkB,MAAyB;AACjE,UAAM,OAAO,QAAQ,MAAM,GAAG,EAAE;AAChC,QAAI,UAAU,QAAQ,MAAM,SAAS,KAAK,QAAQ,UAAU,QAAQ,KAAK,SAAS,KAAK,MAAM;AAC3F;IACF;AACA,YAAQ,MAAM,KAAK,IAAI;EACzB;EAEQ,qBAAqB,SAAkB,OAAoC;AACjF,QAAI,CAAC,QAAQ,MAAM,MAAM,GAAI,SAAQ,KAAK,MAAM;AAChD,QAAI,QAAQ,SAAS,QAAQ,MAAM,UAAU,OAAW,SAAQ,QAAQ,MAAM;AAC9E,QAAI,QAAQ,QAAQ,QAAQ,MAAM,SAAS,OAAW,SAAQ,OAAO,MAAM;AAC3E,QAAI,QAAQ,SAAS,QAAQ,MAAM,UAAU,OAAW,SAAQ,QAAQ,MAAM;AAC9E,QAAI,QAAQ,YAAY,QAAQ,MAAM,aAAa,OAAW,SAAQ,WAAW,MAAM;AACvF,QAAI,CAAC,QAAQ,UAAU,MAAM,OAAQ,SAAQ,SAAS,MAAM;AAC5D,SAAK,QAAQ,QAAQ,OAAO,KAAK,MAAM,SAAS,OAAW,SAAQ,OAAO,MAAM;AAChF,QAAI,CAAC,QAAQ,eAAe,MAAM,WAAY,SAAQ,cAAc,MAAM;EAC5E;EAEQ,YAAY,UAAmC;AACrD,QAAI,mBAAmB;AACvB,QAAI,oBAAoB;AACxB,QAAI,uBAAuB;AAC3B,QAAI,yBAAyB;AAC7B,QAAI,YAAY;AAChB,QAAI,mBAAmB;AAEvB,eAAW,WAAW,UAAU;AAC9B,0BAAoB,QAAQ,QAAQ,SAAS;AAC7C,2BAAqB,QAAQ,QAAQ,UAAU;AAC/C,8BAAwB,QAAQ,QAAQ,cAAc;AACtD,gCAA0B,QAAQ,QAAQ,gBAAgB;AAC1D,mBAAa,QAAQ,QAAQ;AAC7B,UAAI,QAAQ,gBAAgB,YAAa,oBAAmB;IAC9D;AAEA,WAAO;MACL,eAAe,SAAS;MACxB,oBAAoB;MACpB,qBAAqB;MACrB,yBAAyB,wBAAwB;MACjD,2BAA2B,0BAA0B;MACrD,YAAY;MACZ,aAAa,YAAY,IAAK,mBAAmB,cAAc,aAAc;IAC/E;EACF;AACF;AhB5OA,IAAM,qBAAqB;AAEpB,SAAS,4BAAoC;AAClD,SAAO,gBAAgB,qBAAqB,SAAS;AACvD;AAgCA,SAAS,iBAAiB,MAAuC;AAC/D,QAAM,MAAM,KAAK,WAAW;AAC5B,QAAM,QAAQ,SAAS,GAAG;AAC1B,MAAI,UAAU,QAAW;AACvB,QAAI,QAAQ,UAAa,QAAQ,KAAM,qBAAoB,cAAc,WAAW;AACpF,WAAO;EACT;AACA,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI;AACF,WAAO,IAAI,KAAK,QAAQ,SAAS,GAAG,IAAI,UAAU,UAAU,GAAG,EAAE,QAAQ;EAC3E,QAAQ;AACN,WAAO;EACT;AACF;AAGA,SAAS,gBAAgB,OAAgC,OAAuB;AAC9E,QAAM,MAAM,MAAM,KAAK;AACvB,MAAI,QAAQ,OAAW,QAAO;AAC9B,QAAM,QAAQ,SAAS,GAAG;AAC1B,MAAI,UAAU,QAAW;AACvB,wBAAoB,cAAc,iBAAiB,KAAK,EAAE;AAC1D,WAAO;EACT;AACA,SAAO;AACT;AAEA,SAAS,mBACP,MACA,KACoB;AACpB,QAAM,WAAW,IAAI,OAAO;AAC5B,MAAI,aAAa,UAAa,aAAa,KAAM,QAAO;AAExD,QAAM,QAAQ,SAAS,QAAQ;AAC/B,MAAI,CAAC,OAAO;AACV,wBAAoB,cAAc,eAAe;AACjD,WAAO;EACT;AAEA,QAAM,YAAY,OAAO,KAAK,WAAW,MAAM,WAAW,KAAK,WAAW,EAAE,KAAK,IAAI;AACrF,QAAM,OAAO,OAAO,KAAK,MAAM,MAAM,WAAW,KAAK,MAAM,EAAE,KAAK,IAAI;AACtE,QAAM,MAAM,aAAa;AACzB,MAAI,CAAC,IAAK,QAAO;AAEjB,SAAO;IACL;IACA,OAAO,gBAAgB,OAAO,cAAc;IAC5C,QAAQ,gBAAgB,OAAO,eAAe;IAC9C,WAAW,gBAAgB,OAAO,yBAAyB;IAC3D,aAAa,gBAAgB,OAAO,6BAA6B;EACnE;AACF;AAEO,IAAM,kBAAN,cAA8B,wBAAqC;EAC/D,OAAO;EACP,cAAc;EAEf,WAA0B;;EAE1B,qBAA0C,CAAC;EAC3C,qBAAoD,CAAC;EACrD,wBAAwB,oBAAI,IAAgC;EAC5D,oBAAoB,oBAAI,IAA0C;EAClE,4BAA4B,oBAAI,IAAoB;EACpD,kBAAkB;EAElB,eAA8B;AACpC,WAAO,cAAcV,MAAK,0BAA0B,GAAG,UAAU,GAAG,iBAAiB;EACvF;EAEA,sBAAsB;AACpB,UAAM,WAAW,0BAA0B;AAC3C,WAAO;MACL,QAAQ;MACR,SAAS,CAAC,EAAE,MAAM,UAAU,MAAMA,MAAK,UAAU,UAAU,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;IAC7F;EACF;EAEA,cAAuB;AACrB,SAAK,WAAW,KAAK,aAAa;AAClC,QAAI,CAAC,KAAK,SAAU,QAAO;AAC3B,QAAI;AACF,iBAAW,SAASH,aAAY,KAAK,QAAQ,GAAG;AAC9C,cAAM,MAAMG,MAAK,KAAK,UAAU,KAAK;AACrC,YAAIJ,YAAW,GAAG,KAAKC,aAAY,GAAG,EAAE,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ,CAAC,GAAG;AACzE,iBAAO;QACT;MACF;IACF,QAAQ;IAER;AACA,WAAO;EACT;EAEA,mBAAmB,SAAgD;AACjE,QAAI,CAAC,KAAK,SAAU,QAAO,CAAC;AAC5B,UAAM,cAAc,KAAK,gBAAgB;AACzC,UAAM,cAAc,oBAAI,IAA2B;AACnD,eAAW,cAAc,aAAa;AACpC,YAAM,YAAY,KAAK,qBAAqB,UAAU;AACtD,kBAAY,IAAI,YAAY,KAAK,gBAAgB,SAAS,CAAC;IAC7D;AAEA,UAAM,gBAAgB,IAAI,IAAI,WAAW;AACzC,UAAM,aAAa,KAAK,UAAU,aAAa,CAAC,UAAU,MAAM,KAAK,SAAS,QAAQ,GAAG;MACvF,WAAW;IACb,CAAC;AACD,SAAK,mBAAmB,YAAY,WAAW;AAC/C,UAAM,iBAAiB,WAAW,QAAQ,CAAC,WAAW;AACpD,YAAM,QAAQ,KAAK,sBAAsB,IAAI,OAAO,IAAI;AACxD,UAAI,CAAC,SAAS,CAAC,cAAc,IAAIK,SAAQ,OAAO,IAAI,CAAC,EAAG,QAAO,CAAC;AAChE,aAAO;QACL;UACE;UACA,WAAW,OAAO,aAAaD,UAAS,OAAO,MAAM,QAAQ;UAC7D;QACF;MACF;IACF,CAAC;AACD,QAAI,kBAAkB,eAAe;MAAO,CAAC,EAAE,OAAO,MACpD,kBAAkB,OAAO,KAAK,SAAS,OAAO;IAChD;AAEA,QAAI,SAAS,QAAQ,QAAQ,SAAS,MAAM,MAAM;AAEhD,YAAM,mBAAmB,oBAAI,IAA6B;AAC1D,iBAAW,WAAW,gBAAgB;AACpC,cAAM,WAAW,QAAQ,OAAO;AAChC,YAAI,CAAC,SAAU;AACf,cAAM,WAAW,iBAAiB,IAAI,QAAQ;AAC9C,YAAI,SAAU,UAAS,KAAK,OAAO;YAC9B,kBAAiB,IAAI,UAAU,CAAC,OAAO,CAAC;MAC/C;AAEA,YAAM,qBAAqB,IAAI;QAC7B,gBAAgB,IAAI,CAAC,YAAY,CAAC,QAAQ,WAAW,OAAO,CAAC;MAC/D;AACA,YAAM,oBAAoB,oBAAI,IAA2B;AACzD,YAAM,cAAc,oBAAI,IAAY;AACpC,YAAM,cAAc,oBAAI,IAAY;AACpC,YAAM,oBAAoB,CAAC,cAA+B;AACxD,YAAI,YAAY,IAAI,SAAS,EAAG,QAAO;AACvC,YAAI,YAAY,IAAI,SAAS,EAAG,QAAO;AAEvC,cAAM,UAAU,mBAAmB,IAAI,SAAS;AAChD,YAAI,CAAC,QAAS,QAAO;AACrB,cAAM,WAAW,QAAQ,OAAO;AAChC,YAAI,CAAC,UAAU;AACb,sBAAY,IAAI,SAAS;AACzB,iBAAO;QACT;AAEA,oBAAY,IAAI,SAAS;AACzB,cAAM,YAAY,kBAAkB,QAAQ;AAC5C,oBAAY,OAAO,SAAS;AAC5B,YAAI,UAAW,aAAY,IAAI,SAAS;AACxC,eAAO;MACT;AAEA,iBAAW,WAAW,iBAAiB;AACrC,YAAI,kBAAkB,QAAQ,SAAS,GAAG;AACxC,4BAAkB,IAAI,QAAQ,WAAW,OAAO;QAClD;MACF;AAEA,UAAI,SAAS,2BAA2B,OAAO;AAC7C,cAAMU,WAAU,CAAC,GAAG,kBAAkB,OAAO,CAAC,EAC3C,OAAO,CAAC,EAAE,MAAM,MAAM,CAAC,OAAO,eAAe,EAC7C,IAAI,CAAC,EAAE,UAAU,MAAM,SAAS;AACnC,eAAOA,SAAQ,SAAS,GAAG;AACzB,gBAAM,WAAWA,SAAQ,IAAI;AAC7B,qBAAW,SAAS,iBAAiB,IAAI,QAAQ,KAAK,CAAC,GAAG;AACxD,gBAAI,kBAAkB,IAAI,MAAM,SAAS,EAAG;AAC5C,8BAAkB,IAAI,MAAM,WAAW,KAAK;AAC5CA,qBAAQ,KAAK,MAAM,SAAS;UAC9B;QACF;MACF;AAEA,wBAAkB,CAAC,GAAG,kBAAkB,OAAO,CAAC;IAClD;AAEA,WAAO,gBAAgB,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,KAAK,GAAG,WAAW,MAAM,MAAM;AAC3E,YAAM,aAAa,OAAO,cAAcT,SAAQ,IAAI;AACpD,aAAO;QACL;QACA,YAAY;QACZ,aAAa,KAAK;UAChB;UACA,YAAY,IAAI,UAAU,KAAK;UAC/B,OAAO;QACT;MACF;IACF,CAAC;EACH;EAEA,kBAAkB,MAA2C;AAC3D,UAAM,kBAAkB,IAAI;AAC5B,SAAK,sBAAsB,MAAM;AACjC,SAAK,0BAA0B,MAAM;AACrC,SAAK,kBAAkB;EACzB;EAEU,qBAAqB,YAAwC;AACrE,UAAM,QAAQ,KAAK,gBAAgB,UAAU;AAC7C,UAAM,aAAa,OAAO,cAAcA,SAAQ,UAAU;AAC1D,WAAO,iBAAiB,KAAK,uBAAuB,YAAY,YAAY,KAAK,CAAC;EACpF;EAEA,eAAe,WAAkC;AAC/C,UAAM,OAAO,KAAK,eAAe,IAAI,SAAS;AAC9C,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,sBAAsB,SAAS,EAAE;IACnD;AACA,QAAI,CAACN,YAAW,KAAK,UAAU,GAAG;AAChC,YAAM,IAAI,MAAM,yBAAyB,KAAK,UAAU,EAAE;IAC5D;AAEA,SAAK,iBAAiB;AACtB,UAAM,UAAU,IAAI,kBAAkB;AACtC,UAAM,2BAA2B,oBAAI,IAAsB;AAC3D,UAAM,mBAAmB,oBAAI,IAAY;AACzC,eAAW,UAAU,cAAc,KAAK,UAAU,GAAG;AACnD,UAAI;AACF,aAAK;UACH;UACA;UACA;UACA;UACA,KAAK;QACP;MACF,QAAQ;MAER;IACF;AAEA,UAAM,aAAa,QAAQ,OAAO;AAElC,WAAO;MACL,WAAW,EAAE,WAAW,KAAK,MAAM,WAAW,KAAK,GAAG;MACtD,IAAI,KAAK;MACT,OAAO,KAAK;MACZ,MAAM,cAAc,KAAK,EAAE;MAC3B,WAAW,KAAK;MAChB,kBACE,KAAK,mBAAmB,OACpB,SACA,EAAE,WAAW,KAAK,MAAM,WAAW,KAAK,gBAAgB;MAC9D,SAAS;MACT,cAAc,KAAK;MACnB,cAAc,KAAK;MACnB,OAAO,WAAW;MAClB,UAAU,WAAW;IACvB;EACF;;EAIQ,kBAA4B;AAClC,QAAI,CAAC,KAAK,SAAU,QAAO,CAAC;AAC5B,QAAI;AACF,aAAOC,aAAY,KAAK,QAAQ,EAC7B,IAAI,CAAC,MAAMG,MAAK,KAAK,UAAW,CAAC,CAAC,EAClC,OAAO,CAAC,MAAMJ,YAAW,CAAC,CAAC;IAChC,QAAQ;AACN,aAAO,CAAC;IACV;EACF;EAEQ,mBAAyB;AAC/B,QAAI,KAAK,gBAAiB;AAC1B,SAAK,aAAa,KAAK,aAAa;AACpC,QAAI,CAAC,KAAK,UAAU;AAClB,WAAK,kBAAkB;AACvB;IACF;AAEA,UAAM,cAAc,KAAK,gBAAgB;AACzC,SAAK;MACH,KAAK,UAAU,aAAa,CAAC,UAAU,MAAM,KAAK,SAAS,QAAQ,GAAG;QACpE,WAAW;MACb,CAAC;MACD;IACF;EACF;EAEQ,mBACN,SACA,aACM;AACN,SAAK,sBAAsB,MAAM;AACjC,SAAK,0BAA0B,MAAM;AACrC,UAAM,gBAAgB,IAAI,IAAI,WAAW;AACzC,UAAM,WAAW,oBAAI,IAAgC;AACrD,UAAM,kBAAkB,oBAAI,IAAY;AAExC,eAAW,UAAU,SAAS;AAC5B,YAAM,QAAQ,KAAK,iBAAiB,OAAO,IAAI;AAC/C,UAAI,CAAC,OAAO;AACV,YAAI,cAAc,IAAIM,SAAQ,OAAO,IAAI,CAAC,GAAG;AAC3C,0BAAgB,IAAID,UAAS,OAAO,MAAM,QAAQ,CAAC;QACrD;AACA;MACF;AACA,eAAS,IAAI,OAAO,MAAM,KAAK;AAC/B,sBAAgB,IAAI,MAAM,SAAS;IACrC;AAEA,eAAW,CAAC,YAAY,KAAK,KAAK,UAAU;AAC1C,YAAM,kBACJ,MAAM,mBAAmB,gBAAgB,IAAI,MAAM,eAAe,IAC9D,MAAM,kBACN;AACN,YAAM,aACJ,oBAAoB,MAAM,kBAAkB,QAAQ,EAAE,GAAG,OAAO,gBAAgB;AAClF,WAAK,sBAAsB,IAAI,YAAY,UAAU;AACrD,UAAI,MAAM,WAAW;AACnB,aAAK,0BAA0B,IAAI,MAAM,WAAW,WAAW,SAAS;MAC1E;IACF;AAEA,SAAK,kBAAkB;EACzB;EAEQ,gBAAgB,YAA+C;AACrE,UAAM,SAAS,KAAK,sBAAsB,IAAI,UAAU;AACxD,QAAI,OAAQ,QAAO;AAEnB,UAAM,QAAQ,KAAK,iBAAiB,UAAU;AAC9C,QAAI,CAAC,MAAO,QAAO;AACnB,SAAK,sBAAsB,IAAI,YAAY,KAAK;AAChD,QAAI,MAAM,WAAW;AACnB,WAAK,0BAA0B,IAAI,MAAM,WAAW,MAAM,SAAS;IACrE;AACA,WAAO;EACT;EAEQ,iBAAiB,YAA+C;AACtE,UAAM,eAAeC,SAAQ,UAAU;AACvC,QAAID,UAAS,YAAY,MAAM,YAAa,QAAO;AAEnD,UAAM,YAAYC,SAAQ,YAAY;AAEtC,UAAM,aAAaA,SAAQ,SAAS;AACpC,UAAM,WAAWD,UAAS,YAAY,QAAQ;AAC9C,UAAM,WAAWD,MAAK,cAAc,WAAW,YAAY;AAC3D,UAAM,cAAc,KAAK,gBAAgB,QAAQ;AACjD,UAAM,SAAS,KAAK,kBAAkB,IAAI,UAAU;AACpD,QAAI,QAAQ,gBAAgB,YAAa,QAAO,OAAO;AAEvD,QAAI,WAA2C;AAC/C,QAAI,gBAAgB,MAAM;AACxB,UAAI;AACF,mBAAW,SAAS,KAAK,MAAMF,cAAa,UAAU,OAAO,CAAC,CAAC,KAAK;MACtE,QAAQ;MAER;IACF;AAEA,UAAM,YAAY,SAAS,WAAW,SAAS,CAAC,GAAG,KAAK,KAAK,SAAS,QAAQ,WAAW,EAAE;AAC3F,QAAI,CAAC,UAAW,QAAO;AAEvB,UAAM,gBAAgB,SAAS,WAAW,eAAe,CAAC,GAAG,KAAK;AAClE,UAAM,oBAAoB,iBAAiBG,UAAS,SAAS,KAAK;AAClE,UAAM,kBACJ,qBAAqB,KAAK,eAAe,YAAY,YAAY,iBAAiB,IAC9E,oBACA;AACN,UAAM,OAAO,SAAS,WAAW,MAAM,CAAC,GAAG,KAAK;AAChD,UAAM,cAAc,SAAS,WAAW,aAAa,CAAC,GAAG,KAAK;AAE9D,UAAM,UAAU;MACd;MACA;MACA;MACA,eAAe,QAAQ,eAAe;MACtC;MACA,WAAW,SAAS,WAAW,WAAW,CAAC,GAAG,KAAK,KAAK;IAC1D;AACA,SAAK,kBAAkB,IAAI,YAAY,EAAE,aAAa,QAAQ,CAAC;AAC/D,WAAO;EACT;EAEQ,eAAe,YAAoB,YAAoB,iBAAkC;AAC/F,UAAM,eAAeC,SAAQ,UAAU;AACvC,WAAO;MACLF,MAAK,YAAY,kBAAkB,QAAQ;MAC3CA,MAAK,cAAc,WAAW,kBAAkB,QAAQ;MACxDA,MAAK,cAAc,kBAAkB,QAAQ;IAC/C,EAAE,KAAK,CAACU,UAASd,YAAWc,KAAI,CAAC;EACnC;EAEU,sBAAsB,MAAmB,QAAwC;AACzF,UAAM,QAAQ,KAAK,gBAAgB,OAAO,IAAI;AAC9C,UAAM,aAAa,OAAO,cAAcR,SAAQ,OAAO,IAAI;AAC3D,UAAM,YAAY,KAAK,qBAAqB,UAAU;AACtD,UAAM,aAAa,KAAK,gBAAgB,SAAS;AACjD,WAAO,KAAK,qBAAqB;MAC/B;MACA;MACA,aAAa,KAAK,kBAAkB,OAAO,MAAM,YAAY,OAAO,WAAW;MAC/E,QAAQ;QACN,WAAW,eAAe,OAAO,OAAO;QACxC,cAAc;QACd,kBAAkB;QAClB,OAAO,KAAK,MAAM,eAAe,YAAY;QAC7C,iBAAiB,KAAK,kBAAkB,aAAa;MACvD;IACF,CAAC;EACH;;EAGQ,kBACN,MACA,YACA,WACQ;AACR,UAAM,cAAc,CAAC,oBAAoB,KAAK,SAAS,KAAK,MAAM,UAAU;AAC5E,QAAI,cAAc,OAAW,aAAY,KAAK,SAAS;AACvD,WAAO,KAAK,UAAU,WAAW;EACnC;EAEQ,qBAAqB,YAA4B;AACvD,WAAOF,MAAK,YAAY,qBAAqB;EAC/C;EAEQ,kBAAkB,YAA0D;AAClF,UAAM,WAAWC,UAAS,UAAU;AACpC,UAAM,YAAY,KAAK,qBAAqB,UAAU;AACtD,UAAM,QAAQ,KAAK,gBAAgB,SAAS;AAI5C,QAAI,YAAY,KAAK,sBAAsB,KAAK,mBAAmB,QAAQ,MAAM,OAAO;AACtF,aAAO,KAAK,mBAAmB,QAAQ;IACzC;AAEA,UAAM,MAAM,oBAAI,IAAqC;AAErD,QAAIL,YAAW,SAAS,GAAG;AACzB,UAAI;AACF,cAAM,OAAO,KAAK,MAAME,cAAa,WAAW,OAAO,CAAC;AACxD,cAAM,UAAqC,MAAM,WAAW,CAAC;AAC7D,mBAAW,SAAS,SAAS;AAC3B,gBAAM,MAAM,OAAO;AACnB,cAAI,OAAO,QAAQ,UAAU;AAC3B,gBAAI,IAAI,KAAK,KAAK;UACpB;QACF;MACF,QAAQ;MAER;IACF;AAEA,SAAK,mBAAmB,QAAQ,IAAI;AACpC,SAAK,mBAAmB,QAAQ,IAAI;AACpC,WAAO;EACT;EAEQ,uBACN,UACA,YACA,OACiC;AACjC,UAAM,YAAY,OAAO,aAAaG,UAAS,UAAU,QAAQ;AAGjE,UAAM,QAAQ,KAAK,kBAAkB,UAAU;AAC/C,UAAM,aAAa,MAAM,IAAI,SAAS;AACtC,UAAM,gBACJ,OAAO,kBAAkB,YAAY,UAAU,OAAO,WAAW,OAAO,IAAI;AAG9E,QAAI,YAAY;AAChB,QAAI,YAAY;AAChB,QAAI,YAAY;AAChB,QAAI,eAAe;AACnB,QAAI,QAAuB;AAC3B,QAAI,MAAqB;AACzB,QAAI,mBAAmB;AACvB,QAAI,oBAAoB;AACxB,QAAI,uBAAuB;AAC3B,QAAI,yBAAyB;AAC7B,QAAI,YAAY;AAChB,UAAM,gBAAwC,CAAC;AAC/C,UAAM,mBAAmB,oBAAI,IAAY;AACzC,QAAI,eAA8B;AAElC,eAAW,QAAQ,mBAAmB,QAAQ,GAAG;AAC/C,UAAI;AACJ,UAAI;AACF,eAAO,KAAK,MAAM,IAAI;MACxB,QAAQ;AAGN,YAAI,cAAc,EAAG,QAAO,eAAe,wBAAwB;AACnE,qBAAa;AACb;MACF;AAEA,UAAI,cAAc,GAAG;AACnB,oBAAY,iBAAiB,IAAI,KAAKF,UAAS,QAAQ,EAAE;AACzD,oBAAY;MACd;AACA,YAAM,cAAc;AACpB,mBAAa;AAEb,UAAI;AACF,YAAI,oBAAoB,KAAK,MAAM,CAAC,EAAG;AACvC,cAAM,KAAK,iBAAiB,IAAI;AAChC,YAAI,KAAK,UAAW,aAAY;AAEhC,YAAI,CAAC,OAAO,KAAK,KAAK,KAAK,OAAO,KAAK,KAAK,MAAM,UAAU;AAC1D,gBAAM,KAAK,KAAK;QAClB;AAEA,cAAM,MAAM,SAAS,KAAK,SAAS,CAAC;AACpC,YAAI,CAAC,OAAO,KAAK,SAAS,MAAM,UAAa,KAAK,SAAS,MAAM,MAAM;AACrE,8BAAoB,cAAc,SAAS;QAC7C;AACA,YAAI,KAAK;AACP,gBAAM,OAAO,SAAS,IAAI,MAAM,CAAC;AACjC,cAAI,IAAI,MAAM,MAAM,UAAa,SAAS,QAAW;AACnD,gCAAoB,cAAc,cAAc;UAClD;AACA,cAAI,MAAM,KAAK,GAAG;AAChB;UACF;AACA,cAAI,CAAC,OAAO;AACV,kBAAM,IAAI,SAAS,IAAI,OAAO,CAAC;AAC/B,gBAAI,GAAG,KAAK,EAAG,SAAQ,EAAE,KAAK;UAChC;AAGA,cAAI,iBAAiB,QAAQ,cAAc,MAAM,SAAS,QAAQ;AAChE,kBAAM,YAAY,KAAK,wBAAwB,IAAI,SAAS,CAAC;AAC7D,gBAAI,UAAW,gBAAe;UAChC;AACA,cAAI,SAAS,aAAa;AACxB,kBAAM,QAAQ,mBAAmB,MAAM,GAAG;AAC1C,gBAAI,SAAS,CAAC,iBAAiB,IAAI,MAAM,GAAG,GAAG;AAC7C,+BAAiB,IAAI,MAAM,GAAG;AAC9B,oBAAM,cAAc,MAAM;AAC1B,oBAAM,YAAY,MAAM;AACxB,oBAAM,cAAc,MAAM;AAC1B,oBAAM,eAAe,MAAM;AAE3B,kCAAoB,cAAc,YAAY;AAC9C,mCAAqB;AACrB,sCAAwB;AACxB,wCAA0B;AAE1B,oBAAM,IAAI,SAAS,IAAI,OAAO,CAAC;AAC/B,kBAAI,GAAG,KAAK,GAAG;AACb,sBAAM,OAAO,EAAE,KAAK;AACpB,sBAAM,WAAW,cAAc,YAAY,cAAc;AACzD,8BAAc,IAAI,KAAK,cAAc,IAAI,KAAK,KAAK;AACnD,sBAAM,OAAO,kBAAkB,MAAM;kBACnC,OAAO,cAAc,YAAY;kBACjC,QAAQ;kBACR,YAAY;kBACZ,cAAc;gBAChB,CAAC;AACD,oBAAI,SAAS,KAAM,cAAa;cAClC;YACF;UACF;QACF;MACF,QAAQ;MAER;IACF;AAEA,QAAI,cAAc,EAAG,QAAO,eAAe,YAAY;AAEvD,UAAM,YAAY,OAAO;AACzB,UAAM,iBAAiB,cAAc,SAAS,KAAK,cAAc,UAAU;AAE3E,UAAM,QAAQ,oBAAoB,eAAe,cAAc,cAAc;AAE7E,UAAM,gBAAgB,OAAO,KAAK,aAAa,EAAE,SAAS;AAC1D,QAAI,iBAAiB,EAAG,QAAO,gBAAgB,qBAAqB;AAEpE,WAAO,cAAc;MACnB,IAAI;MACJ,MAAM,cAAc,SAAS;MAC7B;MACA;MACA,kBACE,OAAO,mBAAmB,OACtB,SACA,EAAE,WAAW,KAAK,MAAM,WAAW,MAAM,gBAAgB;MAC/D,cAAc;MACd,cAAc;MACd,OAAO;QACL,eAAe;QACf,oBAAoB;QACpB,qBAAqB;QACrB,YAAY;QACZ,aAAa,YAAY,IAAI,cAAc;QAC3C,yBAAyB;QACzB,2BAA2B;MAC7B;MACA,aAAa,gBAAgB,gBAAgB;IAC/C,CAAC;EACH;;EAGQ,wBAAwB,SAAiC;AAC/D,QAAI,CAAC,QAAS,QAAO;AAErB,QAAI,OAAO,YAAY,UAAU;AAC/B,YAAM,QAAQ,mBAAmB,OAAO;AACxC,aAAO,SAAS;IAClB;AACA,QAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,YAAM,QAAQ,QACX,OAAO,CAAC,SAA0C;AACjD,cAAM,SAAS,SAAS,IAAI;AAC5B,eAAO,WAAW,UAAa,UAAU;MAC3C,CAAC,EACA,IAAI,CAAC,SAAS,OAAO,KAAK,MAAM,KAAK,EAAE,CAAC,EACxC,KAAK,GAAG;AACX,YAAM,QAAQ,mBAAmB,KAAK;AACtC,aAAO,SAAS;IAClB;AACA,WAAO;EACT;;EAIQ,cACN,MACA,SACA,0BACA,kBACA,2BACM;AACN,QAAI,KAAK,QAAQ,MAAM,KAAM;AAE7B,UAAM,UAAU,OAAO,KAAK,MAAM,KAAK,EAAE;AACzC,QAAI,oBAAoB,OAAO,EAAG;AAElC,QAAI,YAAY,aAAa;AAC3B,WAAK;QACH;QACA;QACA;QACA;QACA;MACF;IACF,WAAW,YAAY,QAAQ;AAC7B,WAAK,kBAAkB,MAAM,SAAS,wBAAwB;IAChE,WAAW,YAAY,eAAe;AACpC,WAAK,wBAAwB,MAAM,OAAO;IAC5C;EACF;EAEQ,uBACN,MACA,SACA,0BACA,kBACA,2BACM;AACN,UAAM,MAAM,SAAS,KAAK,SAAS,CAAC,KAAK,CAAC;AAC1C,UAAM,cAAc,iBAAiB,IAAI;AACzC,UAAM,aAAa,QAAQ,IAAI,SAAS,CAAC,KAAK,CAAC;AAC/C,UAAM,OAAO,OAAO,KAAK,MAAM,KAAK,EAAE;AAEtC,UAAM,cAAwB,CAAC;AAC/B,eAAW,QAAQ,YAAY;AAC7B,YAAM,OAAO,SAAS,IAAI;AAC1B,UAAI,CAAC,KAAM;AACX,YAAM,WAAW,OAAO,KAAK,MAAM,KAAK,EAAE;AAE1C,UAAI,aAAa,YAAY;AAC3B,cAAM,OAAO,kBAAkB,OAAO,KAAK,UAAU,KAAK,EAAE,CAAC;AAC7D,YAAI,MAAM;AACR,gBAAMc,WAAU,QAAQ;YACtB,KAAK,mBAAmB,MAAM,WAAW;YACzC,EAAE,IAAI,MAAM,aAAa,OAAO,SAAS;YACzC,EAAE,iBAAiB,KAAK;UAC1B;AACA,eAAK,uBAAuBA,UAAS,MAAM,KAAK,gBAAgB;QAClE;AACA;MACF;AAEA,UAAI,aAAa,QAAQ;AACvB,cAAM,OAAO,kBAAkB,OAAO,KAAK,MAAM,KAAK,EAAE,CAAC;AACzD,YAAI,MAAM;AACR,gBAAMA,WAAU,QAAQ;YACtB,KAAK,cAAc,MAAM,WAAW;YACpC;cACE,IAAI;cACJ;cACA,OAAO;YACT;YACA,EAAE,iBAAiB,KAAK;UAC1B;AACA,eAAK,uBAAuBA,UAAS,MAAM,KAAK,gBAAgB;QAClE;AACA;MACF;AAEA,UAAI,aAAa,WAAY;AAE7B,YAAM,aAAa,OAAO,KAAK,IAAI,KAAK,EAAE,EAAE,KAAK;AACjD,YAAM,aAAa,0BAA0B,IAAI,UAAU;AAE3D,YAAMC,YAAW,KAAK,cAAc,MAAM,WAAW;AACrD,YAAM,UAAU,QAAQ;QACtBA;QACA,EAAE,IAAI,MAAM,aAAa,OAAO,UAAU,WAAW;QACrD,EAAE,cAAc,OAAO;MACzB;AACA,UAAI,WAAY,SAAQ,cAAc;AACtC,WAAK,uBAAuB,SAAS,MAAM,KAAK,gBAAgB;AAChE,UAAI,YAAY;AACd,oBAAY,KAAK,UAAU;MAC7B;IACF;AAEA,QAAI,YAAY,SAAS,GAAG;AAC1B,+BAAyB,IAAI,MAAM,WAAW;IAChD;EACF;EAEQ,kBACN,MACA,SACA,0BACM;AACN,UAAM,MAAM,SAAS,KAAK,SAAS,CAAC,KAAK,CAAC;AAC1C,UAAM,cAAc,iBAAiB,IAAI;AACzC,UAAM,UAAU,IAAI,SAAS,KAAK;AAClC,UAAM,OAAO,OAAO,KAAK,MAAM,KAAK,EAAE;AAGtC,QAAI,OAAO,YAAY,UAAU;AAC/B,YAAM,QAAQ,KAAK,uBAAuB,SAAS,WAAW;AAC9D,UAAI,MAAM,WAAW,GAAG;AACtB,gBAAQ,UAAU;AAClB;MACF;AACA,cAAQ,cAAc,EAAE,IAAI,MAAM,MAAM,QAAQ,aAAa,MAAM,CAAC;AACpE;IACF;AAEA,QAAI,CAAC,MAAM,QAAQ,OAAO,GAAG;AAC3B,cAAQ,UAAU;AAClB;IACF;AAEA,UAAM,eAAe,KAAK,uBAAuB,SAAS,WAAW;AACrE,UAAM,mBAAmB,KAAK,wBAAwB,KAAK,eAAe,CAAC;AAE3E,eAAW,QAAQ,SAAS;AAC1B,YAAM,KAAK,SAAS,IAAI;AACxB,UAAI,CAAC,MAAM,GAAG,MAAM,MAAM,cAAe;AAEzC,YAAM,aAAa,KAAK,kBAAkB,MAAM,IAAI,wBAAwB;AAE5E,YAAM,cAAc,KAAK,0BAA0B,GAAG,SAAS,GAAG,WAAW;AAC7E,UAAI,KAAK,mBAAmB,SAAS,YAAY,aAAa,gBAAgB,GAAG;AAC/E;MACF;AAEA,YAAM,WAAW,KAAK,yBAAyB;QAC7C,WAAW;QACX;QACA;QACA;MACF,CAAC;AACD,UAAI,SAAU,SAAQ,cAAc,QAAQ;IAC9C;AAEA,QAAI,aAAa,SAAS,GAAG;AAC3B,cAAQ,cAAc,EAAE,IAAI,MAAM,MAAM,QAAQ,aAAa,OAAO,aAAa,CAAC;IACpF;AAEA,YAAQ,UAAU;EACpB;EAEQ,wBAAwB,MAA+B,SAAkC;AAC/F,UAAM,cAAc,iBAAiB,IAAI;AACzC,UAAM,MAAM,SAAS,KAAK,SAAS,CAAC,KAAK,CAAC;AAC1C,UAAM,cAAc,KAAK,0BAA0B,IAAI,SAAS,GAAG,WAAW;AAC9E,UAAM,OAAO,OAAO,KAAK,MAAM,KAAK,EAAE;AAEtC,UAAM,WAAW,KAAK,yBAAyB;MAC7C,WAAW;MACX;MACA,YAAY;MACZ;IACF,CAAC;AACD,QAAI,SAAU,SAAQ,cAAc,QAAQ;AAC5C,YAAQ,UAAU;EACpB;EAEQ,cAAc,MAAc,aAAkC;AACpE,WAAO,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY;EACzD;EAEQ,mBAAmB,MAAc,aAAkC;AACzE,WAAO,EAAE,MAAM,aAAa,MAAM,cAAc,YAAY;EAC9D;EAEQ,cAAc,MAA+B,aAA+B;AAClF,UAAM,WAAW,OAAO,KAAK,MAAM,KAAK,EAAE;AAC1C,WAAO;MACL,MAAM;MACN,MAAM;MACN,QAAQ,OAAO,KAAK,IAAI,KAAK,EAAE;MAC/B,OAAO,SAAS,QAAQ;MACxB,OAAO;QACL,QAAQ;QACR,OAAO,KAAK,OAAO,KAAK,CAAC;QACzB,QAAQ;MACV;MACA,cAAc;IAChB;EACF;EAEQ,uBACN,SACA,MACA,KACA,kBACM;AACN,UAAM,QAAQ,IAAI,OAAO;AACzB,QAAI,SAAS,OAAO,UAAU,YAAY,CAAC,QAAQ,OAAO;AACxD,cAAQ,QAAQ;IAClB;AACA,UAAM,QAAQ,mBAAmB,MAAM,GAAG;AAC1C,QAAI,SAAS,CAAC,QAAQ,UAAU,CAAC,iBAAiB,IAAI,MAAM,GAAG,GAAG;AAChE,uBAAiB,IAAI,MAAM,GAAG;AAC9B,cAAQ,SAAS;QACf,OAAO,MAAM,QAAQ,MAAM,cAAc,MAAM;QAC/C,QAAQ,MAAM;QACd,YAAY,MAAM;QAClB,cAAc,MAAM;MACtB;AACA,YAAM,OAAO,kBAAkB,QAAQ,OAAO,QAAQ,MAAM;AAC5D,UAAI,SAAS,MAAM;AACjB,gBAAQ,OAAO;AACf,gBAAQ,cAAc;MACxB;IACF;EACF;;EAIQ,uBAAuB,SAAkB,aAAoC;AACnF,QAAI,OAAO,YAAY,UAAU;AAC/B,YAAM,OAAO,kBAAkB,OAAO;AACtC,aAAO,OAAO,CAAC,KAAK,cAAc,MAAM,WAAW,CAAC,IAAI,CAAC;IAC3D;AACA,QAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,QAAO,CAAC;AAErC,UAAM,QAAuB,CAAC;AAC9B,eAAW,QAAQ,SAAS;AAC1B,YAAM,KAAK,SAAS,IAAI;AACxB,UAAI,IAAI;AACN,YAAI,GAAG,MAAM,MAAM,cAAe;AAClC,cAAM,OAAO,kBAAkB,OAAO,GAAG,MAAM,KAAK,EAAE,CAAC;AACvD,YAAI,KAAM,OAAM,KAAK,KAAK,cAAc,MAAM,WAAW,CAAC;MAC5D,WAAW,OAAO,SAAS,UAAU;AACnC,cAAM,OAAO,kBAAkB,IAAI;AACnC,YAAI,KAAM,OAAM,KAAK,KAAK,cAAc,MAAM,WAAW,CAAC;MAC5D;IACF;AACA,WAAO;EACT;EAEQ,0BAA0B,SAAkB,aAAoC;AACtF,QAAI,OAAO,YAAY,UAAU;AAC/B,YAAMC,QAAO,kBAAkB,OAAO;AACtC,aAAOA,QAAO,CAAC,KAAK,cAAcA,OAAM,WAAW,CAAC,IAAI,CAAC;IAC3D;AACA,QAAI,YAAY,QAAQ,YAAY,OAAW,QAAO,CAAC;AAEvD,QAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,YAAM,QAAuB,CAAC;AAC9B,iBAAW,QAAQ,SAAS;AAC1B,cAAM,aAAa,SAAS,IAAI;AAChC,YAAI,YAAY;AACd,gBAAM,YAAY,WAAW,QAAQ;AACrC,cAAI,WAAW,MAAM,MAAM,WAAW,WAAW;AAC/C,kBAAM,SAAS,SAAS,SAAS;AACjC,kBAAM,OAAO,SAAS,SAAS,MAAM,CAAC,KAAK;AAC3C,kBAAM,WAAW,SAAS,SAAS,YAAY,CAAC,KAAK;AACrD,gBAAI,QAAQ,SAAS,WAAW,QAAQ,GAAG;AACzC,oBAAM,KAAK,EAAE,MAAM,SAAS,MAAM,WAAW,UAAU,cAAc,YAAY,CAAC;YACpF;AACA;UACF;AACA,gBAAMA,QAAO,OAAO,WAAW,MAAM,KAAK,WAAW,SAAS,KAAK,EAAE;AACrE,gBAAM,UAAU,kBAAkBA,KAAI;AACtC,cAAI,QAAS,OAAM,KAAK,KAAK,cAAc,SAAS,WAAW,CAAC;QAClE,WAAW,OAAO,SAAS,UAAU;AACnC,gBAAMA,QAAO,kBAAkB,IAAI;AACnC,cAAIA,MAAM,OAAM,KAAK,KAAK,cAAcA,OAAM,WAAW,CAAC;QAC5D;MACF;AACA,aAAO;IACT;AAEA,UAAM,OAAO,kBAAkB,OAAO,OAAO,CAAC;AAC9C,WAAO,OAAO,CAAC,KAAK,cAAc,MAAM,WAAW,CAAC,IAAI,CAAC;EAC3D;;EAIQ,mBACN,SACA,QACA,aACA,cACS;AACT,QAAI,CAAC,OAAQ,QAAO;AAEpB,WAAO,QAAQ,eAAe,QAAQ,CAAC,SAAS;AAC9C,YAAM,QAAQ,KAAK;AACnB,UAAI,YAAY,SAAS,GAAG;AAC1B,cAAM,WAAW,MAAM;AACvB,YAAI,MAAM,QAAQ,QAAQ,EAAG,UAAS,KAAK,GAAG,WAAW;iBAChD,YAAY,KAAM,OAAM,SAAS,CAAC,GAAG,WAAW;YACpD,OAAM,SAAS,CAAC,UAAU,GAAG,WAAW;MAC/C;AACA,UAAI,cAAc,OAAQ,OAAM,SAAS,aAAa;AACtD,UAAI,cAAc,aAAa,OAAW,OAAM,WAAW,aAAa;AACxE,UAAI,YAAY,SAAS,KAAK,MAAM,WAAW,UAAW,OAAM,SAAS;IAC3E,CAAC;EACH;EAEQ,kBACN,MACA,MACA,0BACQ;AACR,UAAM,WAAW,OAAO,KAAK,aAAa,KAAK,EAAE,EAAE,KAAK;AACxD,QAAI,SAAU,QAAO;AAErB,UAAM,aAAa,OAAO,KAAK,yBAAyB,KAAK,EAAE,EAAE,KAAK;AACtE,QAAI,CAAC,WAAY,QAAO;AAExB,UAAM,MAAM,yBAAyB,IAAI,UAAU;AACnD,QAAI,OAAO,IAAI,WAAW,EAAG,QAAO,IAAI,CAAC;AACzC,WAAO;EACT;EAEQ,wBACN,eACqD;AACrD,UAAM,SAAS,SAAS,aAAa;AACrC,QAAI,CAAC,OAAQ,QAAO,CAAC;AAErB,UAAM,UAA+D,CAAC;AAEtE,UAAM,UAAU,OAAO,SAAS;AAChC,QAAI,OAAO,YAAY,WAAW;AAChC,cAAQ,SAAS,UAAU,cAAc;IAC3C;AAEA,UAAM,cAAc,OAAO,aAAa;AACxC,QAAI,aAAa;AACf,cAAQ,WAAW,EAAE,YAAY;IACnC;AAEA,WAAO;EACT;;EAIQ,yBAAyB,MAKC;AAChC,QAAI,KAAK,YAAY,WAAW,EAAG,QAAO;AAC1C,WAAO;MACL,IAAI,KAAK;MACT,MAAM;MACN,aAAa,KAAK;MAClB,OAAO,KAAK;IACd;EACF;AACF;AkBpgCA,IAAI,sBAAwD;AAC5D,IAAI,mBAAkC;AAEtC,IAAI;AACF,QAAMC,WAAU,cAAc,YAAY,GAAG;AAE7C,QAAM,MAAMA,SAAQ,gBAAgB;AACpC,wBACE,OAAO,QAAQ,aAAa,MAAO,IAA8B;AAErE,SAAS,OAAO;AAKd,qBAAmB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC1E;AAEA,IAAI,sBAAsB;AAE1B,SAAS,wBAA8B;AACrC,MAAI,oBAAqB;AACzB,wBAAsB;AACtB,qBAAmB,GAAG,KAAK,sBAAsB,EAAE,SAAS,iBAAiB,CAAC;AAChF;AA4BA,SAAS,gBAAgB,OAAuB;AAC9C,SAAO,IAAI,MAAM,WAAW,KAAK,IAAI,CAAC;AACxC;AAEA,SAAS,eAAe,OAAuB;AAC7C,SAAO,IAAI,MAAM,WAAW,KAAK,IAAI,CAAC;AACxC;AAEA,SAAS,eAAe,QAAyB;AAC/C,SACE,WAAW,cAAc,OAAO,WAAW,eAAe,KAAK,OAAO,SAAS,aAAa;AAEhG;AAEO,SAAS,eAAe,IAA4B;AACzD,QAAM,MAAM,GAAG,QAAQ,qBAAqB,EAAE,IAAI;AAClD,SAAO,OAAO,KAAK,gBAAgB,CAAC;AACtC;AAEO,SAAS,eAAe,IAAoB,SAAuB;AACxE,KAAG,KAAK,yBAAyB,KAAK,MAAM,OAAO,CAAC,EAAE;AACxD;AAEO,SAAS,YAAY,IAAoB,WAA4B;AAC1E,QAAM,MAAM,GACT;IACC;;;;;;EAMF,EACC,IAAI,SAAS;AAChB,SAAO,QAAQ;AACjB;AAEO,SAAS,aAAa,IAAoB,WAAmB,YAA6B;AAC/F,MAAI,CAAC,YAAY,IAAI,SAAS,GAAG;AAC/B,WAAO;EACT;AAEA,QAAM,OAAO,GAAG,QAAQ,qBAAqB,gBAAgB,SAAS,CAAC,GAAG,EAAE,IAAI;AAChF,SAAO,KAAK,KAAK,CAAC,QAAQ,OAAO,IAAI,IAAI,MAAM,UAAU;AAC3D;AAEO,SAAS,aAAa,IAAoB,WAA4B;AAC3E,MAAI,CAAC,YAAY,IAAI,SAAS,GAAG;AAC/B,WAAO;EACT;AAEA,QAAM,MAAM,GAAG,QAAQ,0BAA0B,gBAAgB,SAAS,CAAC,UAAU,EAAE,IAAI;AAG3F,SAAO,QAAQ;AACjB;AAEO,SAAS,eAAe,IAAoB,QAAgB,OAA8B;AAC/F,MAAI,eAAe,MAAM,GAAG;AAC1B,WAAO;EACT;AAEA,QAAM,YAAY,IAAI,KAAK,KAAK,IAAI,CAAC,EAAE,YAAY,EAAE,WAAW,KAAK,EAAE,EAAE,WAAW,KAAK,GAAG;AAC5F,MAAI,aAAahB,MAAKE,SAAQ,MAAM,GAAG,GAAGD,UAAS,MAAM,CAAC,IAAI,SAAS,IAAI,KAAK,MAAM;AACtF,WAAS,UAAU,GAAGL,YAAW,UAAU,GAAG,WAAW,GAAG;AAC1D,iBAAaI,MAAKE,SAAQ,MAAM,GAAG,GAAGD,UAAS,MAAM,CAAC,IAAI,SAAS,IAAI,KAAK,IAAI,OAAO,MAAM;EAC/F;AACA,KAAG,KAAK,eAAe,eAAe,UAAU,CAAC,EAAE;AAEnD,sBAAoB,UAAU;AAC9B,SAAO;AACT;AAEO,SAAS,0BACd,IACA,QACA,OACA,QACe;AACf,MAAI,CAAC,OAAO,KAAK,CAAC,UAAU,aAAa,IAAI,KAAK,CAAC,GAAG;AACpD,WAAO;EACT;AAEA,SAAO,eAAe,IAAI,QAAQ,KAAK;AACzC;AAEO,SAAS,oBACd,IACA,SACU;AACV,QAAM,UAAoB,CAAC;AAC3B,MAAI,iBAAiB,QAAQ;AAE7B,aAAW,aAAa,QAAQ,YAAY;AAC1C,QAAI,UAAU,WAAW,gBAAgB;AACvC;IACF;AACA,QAAI,UAAU,UAAU,QAAQ,eAAe;AAC7C;IACF;AAEA,UAAM,cAAc;AACpB,UAAM,YAAY,YAAY,IAAI;AAClC,uBAAmB,GAAG,OAAO,4BAA4B;MACvD,OAAO,QAAQ;MACf,cAAc;MACd,YAAY,UAAU;MACtB,aAAa,UAAU,eAAe;IACxC,CAAC;AAED,QAAI;AACF,UAAI,gBAAgB;AACpB,UAAI,UAAU,aAAa;AACzB,cAAM,aAAa;UACjB;UACA,QAAQ;UACR,QAAQ;UACR,QAAQ;QACV;AACA,YAAI,YAAY;AACd,kBAAQ,KAAK,UAAU;AACvB,0BAAgB;QAClB;MACF;AAEA,YAAM,QAAQ,GAAG,YAAY,MAAM;AACjC,kBAAU,QAAQ,EAAE;AACpB,uBAAe,IAAI,UAAU,OAAO;MACtC,CAAC;AACD,YAAM;AACN,uBAAiB,UAAU;AAC3B,yBAAmB,GAAG,OAAO,8BAA8B;QACzD,OAAO,QAAQ;QACf,cAAc;QACd,YAAY,UAAU;QACtB,aAAa,UAAU,eAAe;QACtC,gBAAgB;QAChB,aAAa,KAAK,MAAM,YAAY,IAAI,IAAI,SAAS;MACvD,CAAC;IACH,SAAS,OAAO;AACd,yBAAmB,GAAG,KAAK,2BAA2B;QACpD,OAAO,QAAQ;QACf,cAAc;QACd,YAAY,UAAU;QACtB,aAAa,UAAU,eAAe;QACtC,aAAa,KAAK,MAAM,YAAY,IAAI,IAAI,SAAS;QACrD,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;MAChE,CAAC;AACD,YAAM;IACR;EACF;AAEA,MAAI,iBAAiB,QAAQ,eAAe;AAC1C,mBAAe,IAAI,QAAQ,aAAa;EAC1C;AAEA,SAAO;AACT;AAMO,SAAS,eAAe,QAAuC;AACpE,MAAI,CAAC,qBAAqB;AACxB,0BAAsB;AACtB,WAAO;EACT;AACA,MAAI;AACF,UAAM,KAAK,oBAAoB,QAAQ,EAAE,UAAU,KAAK,CAAC;AACzD,WAAO;EACT,SAAS,OAAO;AACd,uBAAmB,GAAG,KAAK,sBAAsB;MAC/C;MACA,UAAU;MACV,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAChE,CAAC;AACD,WAAO;EACT;AACF;AAEO,SAAS,OAAO,QAAuC;AAC5D,MAAI,CAAC,qBAAqB;AACxB,0BAAsB;AACtB,WAAO;EACT;AACA,MAAI;AACF,2BAAuBC,SAAQ,MAAM,CAAC;AACtC,UAAM,KAAK,oBAAoB,MAAM;AAErC,4BAAwB,MAAM;AAC9B,QAAI;AACF,SAAG,OAAO,oBAAoB;AAC9B,SAAG,OAAO,sBAAsB;AAChC,SAAG,OAAO,mBAAmB;AAC7B,SAAG,OAAO,qBAAqB;IACjC,QAAQ;IAER;AACA,WAAO;EACT,SAAS,OAAO;AACd,uBAAmB,GAAG,KAAK,sBAAsB;MAC/C;MACA,UAAU;MACV,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAChE,CAAC;AACD,WAAO;EACT;AACF;AAKO,SAAS,oBAA6B;AAC3C,SAAO,wBAAwB;AACjC;AC9PA,IAAM,gBAAgB,oBAAI,IAAqB,CAAC,QAAQ,aAAa,MAAM,CAAC;AAC5E,IAAM,8BAA8B;AAEpC,SAAS,iCACP,MACA,OACQ;AACR,QAAM,cAAc,OAAO,KAAK,gBAAgB,KAAK,gBAAgB,CAAC;AACtE,QAAM,eAAe,OAAO,MAAM,gBAAgB,MAAM,gBAAgB,CAAC;AACzE,SACE,eAAe,eACf,OAAO,MAAM,gBAAgB,CAAC,IAAI,OAAO,KAAK,gBAAgB,CAAC,KAC/D,OAAO,MAAM,MAAM,EAAE,EAAE,cAAc,OAAO,KAAK,MAAM,EAAE,CAAC;AAE9D;AAEA,SAAS,qBACP,OACA,SACA,WACM;AACN,QAAM,OAAO,OAAO,QAAQ,QAAQ,CAAC;AACrC,QAAM,SAAS,YAAY,QAAQ,QAAQ,SAAS;AACpD,QAAM,cAAc,OAAO,QAAQ,SAAS,CAAC;AAC7C,QAAM,eAAe,OAAO,QAAQ,UAAU,CAAC;AAC/C,QAAM,QAAQ,WAAW,QAAQ,SAAS,SAAS;AACnD,QAAM,gBACJ,OAAO,IAAI,OAAO,kBAAkB,OAAO,EAAE,OAAO,aAAa,QAAQ,aAAa,CAAC;AAEzF,MAAI,kBAAkB,KAAM,OAAM,cAAc;AAChD,QAAM,cAAc,QAAQ,iBAAiB;AAC7C,QAAM,sBAAsB;AAC5B,QAAM,uBAAuB;AAC/B;AAGA,SAAS,gBAAgB,KAAc,WAAmB,OAAwC;AAChG,QAAM,SAAS,SAAS,KAAK,MAAM,OAAO,OAAO,IAAI,CAAC,CAAC;AACvD,MAAI,OAAQ,QAAO;AACnB,sBAAoB,WAAW,KAAK;AACpC,SAAO,CAAC;AACV;AAEA,SAAS,kBAAkB,OAA6C;AACtE,QAAM,OAAO,SAAS,KAAK;AAC3B,SAAO,SAAS,UAAc,cAA8B,IAAI,IAAI,IAC/D,OACD;AACN;AAEA,SAAS,iBAAiB,OAAgB,WAAoC;AAC5E,SAAO,YAAY,WAAW,gBAAgB,OAAO,iBAAiB,KAAK;AAC7E;AAEA,SAAS,YAAY,OAAgB,WAAwD;AAC3F,SAAO,YAAY,WAAW,kBAAkB,OAAO,QAAQ;AACjE;AAEA,SAAS,WAAW,OAAgB,WAAkC;AACpE,SAAO,YAAY,WAAW,mBAAmB,OAAO,QAAQ,KAAK;AACvE;AAEO,IAAM,sBAAN,cAAkC,sBAAsB;EAM7D,YAA6B,QAAmC;AAC9D,UAAM;AADqB,SAAA,SAAA;AAE3B,SAAK,OAAO,OAAO;AACnB,SAAK,cAAc,OAAO;EAC5B;EAJ6B;EALpB;EACA;EAED,SAAwB;EAQtB,kBAAiC;AACzC,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,SAAS,KAAK,WAAW;IAChC;AACA,WAAO,KAAK;EACd;EAEA,sBAAwC;AACtC,WAAO,KAAK,OAAO,oBAAoB;EACzC;EAEQ,aAA4B;AAClC,WAAO,KAAK,OAAO,WAAW;EAChC;EAEA,cAAuB;AACrB,SAAK,SAAS,KAAK,WAAW;AAC9B,WAAO,KAAK,WAAW;EACzB;EAEA,KAAK,SAA2C;AAC9C,QAAI,CAAC,KAAK,OAAQ,QAAO,CAAC;AAE1B,UAAM,KAAK,eAAe,KAAK,MAAM;AACrC,QAAI,CAAC,GAAI,OAAM,IAAI,iBAAiB,KAAK,MAAM,sBAAsB;AAErE,QAAI;AACF,YAAM,aAAa,SAAS,QAAQ,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,KAAK;AAEvE,YAAM,kBAAkB;QACtB,GACG,QAAQ,0EAA0E,EAClF,IAAI;MACT;AAEA,YAAM,cAAc,aAAa,IAAI,WAAW,WAAW;AAC3D,YAAM,cAAc,aAAa,IAAI,WAAW,WAAW;AAC3D,YAAM,iBAAiB,cACnB,4BACA,cACE,iEACA;AAEN,UAAI;AACJ,YAAM,iBAAiB,cAAc,kBAAkB;AACvD,UAAI,iBAAiB;AACnB,eAAO,GACJ,QAAQ;;;wCAGqB,cAAc;;;YAG1C,cAAc;;SAEjB,EACE,IAAI,UAAU;MACnB,OAAO;AACL,eAAO,GACJ,QAAQ;;wFAEqE,cAAc;;;YAG1F,cAAc;;SAEjB,EACE,IAAI,UAAU;MACnB;AAEA,UAAI,eAAe,SAAS,2BAA2B,OAAO;AAC5D,cAAM,UAAU,KAAK,IAAI,CAAC,QAAQ,OAAO,IAAI,MAAM,EAAE,CAAC,EAAE,OAAO,OAAO;AACtE,cAAM,cAAc,KAAK,uBAAuB,IAAI,OAAO;AAC3D,cAAM,WAAW,IAAI,IAAI,OAAO;AAChC,aAAK,KAAK,GAAG,YAAY,OAAO,CAAC,QAAQ,CAAC,SAAS,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC;MAC/E;AAEA,WAAK,KAAK,gCAAgC;AAE1C,YAAM,aAAa,IAAI,IAAI,KAAK,IAAI,CAAC,QAAQ,OAAO,IAAI,MAAM,EAAE,CAAC,EAAE,OAAO,OAAO,CAAC;AAElF,YAAM,eAAe,kBACjB,KAAK;QACH,KAAK;UACH;UACA;UACA;UACA,WAAW,OAAO,IAAI,aAAa;QACrC;QACA,KAAK,iBAAiB,IAAI,YAAY,WAAW,OAAO,IAAI,aAAa,MAAS;QAClF;MACF,IACA,oBAAI,IAAiC;AACzC,YAAM,QAAuB,CAAC;AAC9B,eAAS,aAAa,EAAE,OAAO,KAAK,QAAQ,WAAW,GAAG,UAAU,EAAE,CAAC;AACvE,UAAI,YAAY;AAChB,iBAAW,OAAO,MAAM;AACtB,cAAM,OAAO;UACX,KAAK,oBAAoB,KAAK,iBAAiB,aAAa,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC,CAAC;QACvF;AACA,YAAI,MAAM;AACR,gBAAM,KAAK,IAAI;AAGf,cAAI,KAAK,QAAQ;AACf,iBAAK,eAAe,IAAI,KAAK,IAAI;cAC/B,IAAI,KAAK;cACT,YAAY,KAAK;YACnB,CAAC;UACH;QACF;AACA,qBAAa;AACb,iBAAS,aAAa,EAAE,OAAO,KAAK,QAAQ,WAAW,UAAU,MAAM,OAAO,CAAC;MACjF;AAEA,aAAO;IACT,SAAS,OAAO;AACd,YAAM,IAAI,iBAAiB,KAAK,MAAM,oBAAoB,EAAE,OAAO,MAAM,CAAC;IAC5E,UAAA;AACE,SAAG,MAAM;IACX;EACF;EAEQ,oBACN,KACA,iBACA,SACiC;AACjC,UAAM,KAAK,OAAO,IAAI,MAAM,EAAE;AAC9B,QAAI,CAAC,GAAI,QAAO,eAAe,oBAAoB;AAEnD,UAAM,cAAc,OAAO,IAAI,gBAAgB,CAAC;AAChD,UAAM,cAAc,OAAO,IAAI,gBAAgB,WAAW;AAC1D,UAAM,QAAQ,SAAS,SAAS;AAChC,UAAM,eAAe,OAAO,iBAAiB;AAC7C,QAAI,mBAAmB,iBAAiB,EAAG,QAAO,gBAAgB,qBAAqB;AACvF,UAAM,eAAe,SAAS,gBAAgB;AAE9C,WAAO,cAAc;MACnB;MACA,MAAM,GAAG,KAAK,IAAI,IAAI,EAAE;MACxB,OAAO,oBAAoB,OAAO,IAAI,SAAS,EAAE,GAAG,cAAc,IAAI;MACtE,WAAW,OAAO,IAAI,aAAa,EAAE;MACrC,kBACE,IAAI,aAAa,QAAQ,OAAO,IAAI,SAAS,MAAM,KAC/C,SACA,EAAE,WAAW,KAAK,MAAM,WAAW,OAAO,IAAI,SAAS,EAAE;MAC/D,cAAc;MACd,cAAc;MACd,OAAO;QACL,eAAe;QACf,oBAAoB,OAAO,sBAAsB;QACjD,qBAAqB,OAAO,uBAAuB;QACnD,YAAY,OAAO,cAAc;QACjC,aAAa,OAAO;MACtB;IACF,CAAC;EACH;EAEQ,oBACN,IACA,YACA,cACA,YACsB;AACtB,UAAM,iBAAiB,eAAe,kBAAkB;AACxD,UAAM,MAAM,aAAa,CAAC,GAAG,UAAU,IAAI,CAAC;AAC5C,QAAI,IAAI,WAAW,GAAG;AACpB,aAAO,GACJ;QACC;+DACqD,cAAc;;;;;;MAMrE,EACC,IAAI,UAAU;IACnB;AAEA,UAAM,OAA6B,CAAC;AACpC,aAAS,SAAS,GAAG,SAAS,IAAI,QAAQ,UAAU,6BAA6B;AAC/E,YAAM,QAAQ,IAAI,MAAM,QAAQ,SAAS,2BAA2B;AACpE,WAAK;QACH,GAAI,GACD;UACC;iEACqD,cAAc;;;+BAGhD,MAAM,IAAI,MAAM,GAAG,EAAE,KAAK,GAAG,CAAC;;;QAGnD,EACC,IAAI,GAAG,KAAK;MACjB;IACF;AACA,WAAO;EACT;EAEQ,iBACN,IACA,YACA,YACmB;AACnB,UAAM,MAAM,aAAa,CAAC,GAAG,UAAU,IAAI,CAAC;AAC5C,QAAI,IAAI,WAAW,GAAG;AACpB,aAAO,GACJ;QACC;;;;;;;;MAQF,EACC,IAAI,UAAU;IACnB;AAEA,UAAM,OAA0B,CAAC;AACjC,aAAS,SAAS,GAAG,SAAS,IAAI,QAAQ,UAAU,6BAA6B;AAC/E,YAAM,QAAQ,IAAI,MAAM,QAAQ,SAAS,2BAA2B;AACpE,WAAK;QACH,GAAI,GACD;UACC;;;;;+BAKmB,MAAM,IAAI,MAAM,GAAG,EAAE,KAAK,GAAG,CAAC;;;QAGnD,EACC,IAAI,GAAG,KAAK;MACjB;IACF;AACA,WAAO;EACT;EAEQ,uBAAuB,IAAoB,SAA8C;AAC/F,QAAI,QAAQ,WAAW,EAAG,QAAO,CAAC;AAElC,UAAM,OAAO,GACV;MACC;;;;;;;;IAQF,EACC,IAAI;AACP,UAAM,mBAAmB,oBAAI,IAAuC;AACpE,eAAW,OAAO,MAAM;AACtB,YAAM,WAAW,OAAO,IAAI,aAAa,EAAE;AAC3C,UAAI,CAAC,SAAU;AACf,YAAM,WAAW,iBAAiB,IAAI,QAAQ;AAC9C,UAAI,SAAU,UAAS,KAAK,GAAG;UAC1B,kBAAiB,IAAI,UAAU,CAAC,GAAG,CAAC;IAC3C;AAEA,UAAM,SAAoC,CAAC;AAC3C,UAAMS,WAAU,CAAC,GAAG,OAAO;AAC3B,UAAM,OAAO,oBAAI,IAAY;AAC7B,WAAOA,SAAQ,SAAS,GAAG;AACzB,YAAM,WAAWA,SAAQ,IAAI;AAC7B,iBAAW,OAAO,iBAAiB,IAAI,QAAQ,KAAK,CAAC,GAAG;AACtD,cAAM,KAAK,OAAO,IAAI,MAAM,EAAE;AAC9B,YAAI,CAAC,MAAM,KAAK,IAAI,EAAE,EAAG;AACzB,aAAK,IAAI,EAAE;AACX,eAAO,KAAK,GAAG;AACfA,iBAAQ,KAAK,EAAE;MACjB;IACF;AACA,WAAO;EACT;EAEQ,aACN,SACoB;AACpB,UAAM,WAAW,gBAAgB,QAAQ,MAAM,KAAK,MAAM,WAAW;AACrE,UAAM,WAAW,OAAO,SAAS,QAAQ,EAAE;AAC3C,QAAI,oBAAoB,QAAQ,EAAG,QAAO;AAC1C,UAAM,CAAC,IAAI,IAAI,sBAAsB;MACnC,EAAE,GAAG,UAAU,cAAc,OAAO,QAAQ,gBAAgB,CAAC,EAAE;IACjE,CAAC;AACD,WAAO,OAAO,iBAAiB,IAAI,IAAI;EACzC;;;;;;EAOQ,oBAAoB,IAAoB,WAAsC;AACpF,WAAO,GACJ;MACC;;;;;;;IAOF,EACC,IAAI,SAAS;EAClB;EAEQ,oBAAoB,UAAyD;AACnF,UAAM,iBAAiB,oBAAI,IAA2B;AACtD,eAAW,OAAO,UAAU;AAC1B,YAAM,YAAY,OAAO,IAAI,cAAc,EAAE;AAC7C,UAAI,CAAC,UAAW;AAChB,YAAM,OAAO,KAAK,aAAa,GAAG;AAClC,UAAI,CAAC,KAAM;AACX,YAAM,QAAQ,eAAe,IAAI,SAAS;AAC1C,UAAI,OAAO;AACT,cAAM,KAAK,IAAI;MACjB,OAAO;AACL,uBAAe,IAAI,WAAW,CAAC,IAAI,CAAC;MACtC;IACF;AACA,WAAO;EACT;EAEQ,kBACN,aACA,UACA,cACkC;AAClC,UAAM,iBAAiB,KAAK,oBAAoB,QAAQ;AACxD,UAAM,WAAW,oBAAI,IAAiC;AAEtD,UAAM,gBAAgB,CAAC,cAA2C;AAChE,UAAI,UAAU,SAAS,IAAI,SAAS;AACpC,UAAI,CAAC,SAAS;AACZ,kBAAU;UACR,OAAO;YACL,eAAe;YACf,oBAAoB;YACpB,qBAAqB;YACrB,YAAY;UACd;UACA,cAAc;QAChB;AACA,iBAAS,IAAI,WAAW,OAAO;MACjC;AACA,aAAO;IACT;AAEA,eAAW,OAAO,aAAa;AAC7B,YAAM,YAAY,OAAO,IAAI,cAAc,EAAE;AAC7C,UAAI,CAAC,UAAW;AAChB,YAAM,UAAU,gBAAgB,IAAI,MAAM,KAAK,MAAM,cAAc;AACnE,UAAI,oBAAoB,QAAQ,IAAI,EAAG;AAEvC,YAAM,WAAW,eAAe,OAAO,IAAI,aAAa,EAAE,IAAI;AAC9D,YAAM,UAAU,aAAa;AAE7B,UAAI,SAAS;AACX,cAAM,eAAe,cAAc,SAAS;AAC5C,cAAMM,SAAQ,eAAe,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC,KAAK,CAAC;AAC3D,YAAIA,OAAM,SAAS,GAAG;AACpB,+BAAqB,aAAa,OAAO,SAAS,KAAK,IAAI;AAC3D,uBAAa,MAAM,iBAAiB;AACpC,cAAI,CAAC,aAAa,gBAAgB,OAAO,QAAQ,QAAQ,EAAE,MAAM,QAAQ;AACvE,yBAAa,eAAe,sBAAsB;cAChD;gBACE,IAAI,OAAO,IAAI,MAAM,EAAE;gBACvB,MAAM;gBACN,OAAO;gBACP,cAAc,OAAO,IAAI,gBAAgB,CAAC;gBAC1C,OAAAA;cACF;YACF,CAAC;UACH;QACF;AACA,cAAM,gBAAgB,cAAc,QAAQ;AAC5C,6BAAqB,cAAc,OAAO,SAAS,KAAK,IAAI;AAC5D;MACF;AAEA,YAAM,QAAQ,eAAe,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC,KAAK,CAAC;AAC3D,UAAI,MAAM,WAAW,EAAG;AAExB,YAAM,UAAU,cAAc,SAAS;AACvC,2BAAqB,QAAQ,OAAO,SAAS,KAAK,IAAI;AACtD,cAAQ,MAAM,iBAAiB;AAE/B,UAAI,CAAC,QAAQ,gBAAgB,OAAO,QAAQ,QAAQ,EAAE,MAAM,QAAQ;AAClE,gBAAQ,eAAe,sBAAsB;UAC3C;YACE,IAAI,OAAO,IAAI,MAAM,EAAE;YACvB,MAAM;YACN,OAAO;YACP,cAAc,OAAO,IAAI,gBAAgB,CAAC;YAC1C;UACF;QACF,CAAC;MACH;IACF;AAEA,eAAW,WAAW,SAAS,OAAO,GAAG;AACvC,UAAI,QAAQ,MAAM,aAAa,KAAK,QAAQ,MAAM,gBAAgB,aAAa;AAC7E,gBAAQ,MAAM,cAAc;MAC9B;IACF;AAEA,WAAO;EACT;EAEQ,mBAAmB,IAAoB,iBAAiD;AAC9F,QAAI,CAAC,aAAa,IAAI,WAAW,WAAW,EAAG,QAAO,CAAC;AAEvD,UAAM,YAAY,GACf,QAAQ,4CAA4C,EACpD,IAAI,eAAe;AAEtB,UAAM,UAAkC,CAAC;AACzC,eAAW,SAAS,WAAW;AAC7B,YAAM,UAAU,OAAO,MAAM,MAAM,EAAE;AACrC,UAAI,CAAC,QAAS;AACd,YAAM,UAAU,GACb,QAAQ,iFAAiF,EACzF,IAAI,OAAO;AACd,YAAM,QAA8B;QAClC,eAAe;QACf,oBAAoB;QACpB,qBAAqB;QACrB,YAAY;MACd;AACA,iBAAW,OAAO,SAAS;AACzB,cAAM,UAAU,gBAAgB,IAAI,MAAM,KAAK,MAAM,cAAc;AACnE,YAAI,oBAAoB,QAAQ,IAAI,EAAG;AACvC,6BAAqB,OAAO,SAAS,KAAK,IAAI;MAChD;AACA,cAAQ,KAAK,KAAK;IACpB;AACA,WAAO;EACT;EAEA,eAAe,WAAkC;AAE/C,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,SAAS,KAAK,WAAW;IAChC;AACA,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,IAAI,MAAM,GAAG,KAAK,WAAW,sBAAsB;IAC3D;AAEA,UAAM,KAAK,eAAe,KAAK,MAAM;AACrC,QAAI,CAAC,IAAI;AACP,YAAM,IAAI,MAAM,GAAG,KAAK,WAAW,sBAAsB;IAC3D;AAEA,QAAI;AAEF,YAAM,aAAa,GAAG,QAAQ,oCAAoC,EAAE,IAAI,SAAS;AAGjF,UAAI,CAAC,YAAY;AACf,cAAM,IAAI,MAAM,sBAAsB,SAAS,EAAE;MACnD;AAEA,YAAM,KAAK,OAAO,WAAW,MAAM,SAAS;AAC5C,YAAM,OAAO,GAAG,KAAK,IAAI,IAAI,EAAE;AAC/B,YAAM,YAAY,OAAO,WAAW,aAAa,EAAE;AACnD,YAAM,cAAc,OAAO,WAAW,gBAAgB,CAAC;AACvD,YAAM,cAAc,OAAO,WAAW,gBAAgB,WAAW;AAEjE,YAAM,WAAsB,CAAC;AAC7B,UAAI,mBAAmB;AAGvB,YAAM,UAAU,GACb,QAAQ,8EAA8E,EACtF,IAAI,SAAS;AAChB,YAAM,iBAAiB,KAAK,oBAAoB,KAAK,oBAAoB,IAAI,SAAS,CAAC;AAEvF,iBAAW,UAAU,SAAS;AAC5B,cAAM,UAAU,gBAAgB,OAAO,MAAM,KAAK,MAAM,cAAc;AACtE,YAAI,oBAAoB,QAAQ,IAAI,EAAG;AAEvC,cAAM,OAAO,OAAO,QAAQ,QAAQ,CAAC;AACrC,cAAM,SAAS,YAAY,QAAQ,QAAQ,KAAK,IAAI;AACpD,cAAM,cAAc,OAAO,QAAQ,SAAS,CAAC;AAC7C,cAAM,eAAe,OAAO,QAAQ,UAAU,CAAC;AAC/C,cAAM,QAAQ,WAAW,QAAQ,SAAS,KAAK,IAAI;AACnD,cAAM,gBACJ,OAAO,IAAI,OAAO,kBAAkB,OAAO,EAAE,OAAO,aAAa,QAAQ,aAAa,CAAC;AACzF,cAAM,eAAe,QAAQ,iBAAiB;AAE9C,cAAM,QAAQ,eAAe,IAAI,OAAO,OAAO,MAAM,EAAE,CAAC,KAAK,CAAC;AAC9D,YAAI,MAAM,WAAW,EAAG;AAExB,iBAAS,KAAK;UACZ,IAAI,OAAO,OAAO,MAAM,EAAE;UAC1B,MAAM,iBAAiB,QAAQ,MAAM,KAAK,IAAI;UAC9C,OAAO,SAAS,QAAQ,KAAK,KAAK;UAClC,MAAM,SAAS,QAAQ,IAAI,KAAK;UAChC;UACA,UAAU,SAAS,QAAQ,UAAU,KAAK;UAC1C,cAAc,OAAO,OAAO,gBAAgB,CAAC;UAC7C,QAAQ,SAAS,EAAE,OAAO,aAAa,QAAQ,aAAa,IAAI;UAChE,MAAM;UACN,aAAa,eAAe,IAAK,OAAO,IAAI,aAAa,cAAe;UACxE;QACF,CAAC;MACH;AAEA,YAAM,kBAAkB,oBAAoB,QAAQ;AACpD,YAAM,QAAQ;QACZ,OAAO,WAAW,SAAS,EAAE;QAC7B,sBAAsB,eAAe;QACrC;MACF;AACA,YAAM,QAA8B;QAClC,eAAe,gBAAgB;QAC/B,oBAAoB;QACpB,qBAAqB;QACrB,YAAY;MACd;AACA,iBAAW,WAAW,iBAAiB;AACrC,cAAM,cAAc,QAAQ,QAAQ;AACpC,cAAM,sBAAsB,QAAQ,QAAQ,SAAS;AACrD,cAAM,uBAAuB,QAAQ,QAAQ,UAAU;AACvD,YAAI,QAAQ,gBAAgB,YAAa,oBAAmB;MAC9D;AAEA,iBAAW,cAAc,KAAK,mBAAmB,IAAI,SAAS,GAAG;AAC/D,cAAM,cAAc,WAAW;AAC/B,cAAM,sBAAsB,WAAW;AACvC,cAAM,uBAAuB,WAAW;AACxC,YAAI,WAAW,gBAAgB,YAAa,oBAAmB;MACjE;AAEA,aAAO;QACL,WAAW,EAAE,WAAW,KAAK,MAAM,WAAW,GAAG;QACjD;QACA;QACA;QACA;QACA,kBACE,WAAW,aAAa,QAAQ,OAAO,WAAW,SAAS,MAAM,KAC7D,SACA,EAAE,WAAW,KAAK,MAAM,WAAW,OAAO,WAAW,SAAS,EAAE;QACtE,SAAS,SAAS,WAAW,OAAO,KAAK;QACzC,cAAc;QACd,cAAc;QACd,eAAe,WAAW,iBAAiB;QAC3C,OAAO;UACL,eAAe,MAAM;UACrB,oBAAoB,MAAM;UAC1B,qBAAqB,MAAM;UAC3B,YAAY,MAAM;UAClB,aACE,MAAM,aAAa,IAAK,mBAAmB,cAAc,aAAc;QAC3E;QACA,UAAU;MACZ;IACF,UAAA;AACE,SAAG,MAAM;IACX;EACF;AACF;AF/qBO,SAAS,0BAAkC;AAChD,SAAOjB,MAAK,gBAAgB,GAAG,UAAU;AAC3C;AAEA,SAAS,qBAAoC;AAC3C,MAAI,CAAC,kBAAkB,EAAG,QAAO;AACjC,SAAO,cAAcA,MAAK,wBAAwB,GAAG,aAAa,GAAG,2BAA2B;AAClG;AAEA,SAAS,8BAA8B;AACrC,QAAM,WAAW,wBAAwB;AACzC,SAAO;IACL,QAAQ;IACR,SAAS;MACP,EAAE,MAAM,UAAU,MAAMA,MAAK,UAAU,aAAa,EAAE;MACtD,EAAE,MAAM,iBAAiB,MAAM,4BAA4B;IAC7D;EACF;AACF;AAEO,IAAM,gBAAN,cAA4B,oBAAoB;EACrD,cAAc;AACZ,UAAM;MACJ,MAAM;MACN,aAAa;MACb,YAAY;MACZ,qBAAqB;IACvB,CAAC;EACH;AACF;AGDA,IAAM,sBAA8C;EAClD,UAAU;EACV,MAAM;EACN,gBAAgB;EAChB,MAAM;EACN,WAAW;EACX,OAAO;AACT;AAEA,IAAM,qBAAqB,oBAAI,IAAI,CAAC,aAAa,CAAC;AAE3C,SAAS,sBAA8B;AAC5C,SAAO,gBAAgB,kBAAkB,OAAO;AAClD;AAEA,SAAS,aAAa,UAA0B;AAC9C,SAAO,oBAAoB,QAAQ,KAAK;AAC1C;AA4BA,SAAS,cAAc,QAAgD;AACrE,SAAO,YAAY,QAAQ,sBAAsB,OAAO,YAAY,QAAQ,KAAK;AACnF;AAGA,SAAS,kBAAkB,QAAyC;AAClE,SAAO,YAAY,QAAQ,kBAAkB,OAAO,WAAW,QAAQ,KAAK;AAC9E;AAGA,SAAS,kBAAkB,OAAgC,OAAuB;AAChF,SAAO,YAAY,QAAQ,SAAS,KAAK,IAAI,MAAM,KAAK,GAAG,QAAQ,KAAK;AAC1E;AAEA,SAAS,uBAAuB,KAAuB;AACrD,MAAI,OAAO,QAAQ,UAAU;AAC3B,QAAI;AACF,aAAO,KAAK,MAAM,GAAG;IACvB,QAAQ;AACN,aAAO;IACT;EACF;AACA,SAAO;AACT;AAEA,SAAS,yBAAyB,SAAkB,aAAoC;AACtF,MAAI,OAAO,YAAY,UAAU;AAC/B,UAAMe,QAAO,kBAAkB,OAAO;AACtC,WAAOA,QAAO,CAAC,EAAE,MAAM,QAAiB,MAAAA,OAAM,cAAc,YAAY,CAAC,IAAI,CAAC;EAChF;AACA,MAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,UAAM,QAAuB,CAAC;AAC9B,eAAW,QAAQ,SAAS;AAC1B,YAAM,SAAS,SAAS,IAAI;AAC5B,UAAI,UAAU,UAAU,QAAQ;AAC9B,cAAMA,QAAO,OAAO,OAAO,QAAQ,EAAE;AACrC,cAAM,UAAU,kBAAkBA,KAAI;AACtC,YAAI,QAAS,OAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,SAAS,cAAc,YAAY,CAAC;MACpF,WAAW,OAAO,SAAS,UAAU;AACnC,cAAMA,QAAO,kBAAkB,IAAI;AACnC,YAAIA,MAAM,OAAM,KAAK,EAAE,MAAM,QAAQ,MAAAA,OAAM,cAAc,YAAY,CAAC;MACxE;IACF;AACA,WAAO;EACT;AACA,MAAI,WAAW,KAAM,QAAO,CAAC;AAC7B,QAAM,OAAO,kBAAkB,OAAO,OAAO,CAAC;AAC9C,SAAO,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC,IAAI,CAAC;AACvE;AAEA,SAAS,6BAA6B,aAAsB,aAAoC;AAC9F,MAAI,eAAe,KAAM,QAAO,CAAC;AACjC,MAAI,OAAO,gBAAgB,UAAU;AACnC,UAAMA,QAAO,kBAAkB,WAAW;AAC1C,WAAOA,QAAO,CAAC,EAAE,MAAM,QAAiB,MAAAA,OAAM,cAAc,YAAY,CAAC,IAAI,CAAC;EAChF;AACA,MAAI,OAAO,gBAAgB,UAAU;AACnC,UAAMA,QAAO,kBAAkB,KAAK,UAAU,aAAa,MAAM,CAAC,CAAC;AACnE,WAAOA,QAAO,CAAC,EAAE,MAAM,QAAQ,MAAAA,OAAM,cAAc,YAAY,CAAC,IAAI,CAAC;EACvE;AACA,QAAM,OAAO,kBAAkB,OAAO,WAAW,CAAC;AAClD,SAAO,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC,IAAI,CAAC;AACvE;AAEA,SAAS,gBAAgB,SAA0B;AACjD,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,MAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,QAAO;AAEpC,SAAO,QACJ,IAAI,CAAC,SAAS;AACb,QAAI,OAAO,SAAS,SAAU,QAAO;AACrC,UAAM,SAAS,SAAS,IAAI;AAC5B,QAAI,OAAQ,QAAO,OAAO,OAAO,QAAQ,OAAO,WAAW,EAAE;AAC7D,WAAO;EACT,CAAC,EACA,KAAK,GAAG;AACb;AAEA,SAAS,sBAAsB,aAA4B,UAAwC;AACjG,MAAI,eAAenB,YAAW,WAAW,GAAG;AAC1C,eAAW,UAAU,cAAc,WAAW,GAAG;AAC/C,UAAI,OAAO,SAAS,OAAQ;AAC5B,YAAM,QAAQ,mBAAmB,gBAAgB,OAAO,OAAO,CAAC;AAChE,UAAI,MAAO,QAAO;IACpB;EACF;AAEA,MAAI,YAAYA,YAAW,QAAQ,GAAG;AACpC,eAAW,UAAU,cAAc,QAAQ,GAAG;AAC5C,YAAM,UAAU,SAAS,OAAO,OAAO,KAAK,CAAC;AAC7C,UAAI,QAAQ,SAAS,YAAa;AAClC,YAAM,UAAU,SAAS,QAAQ,OAAO,KAAK,CAAC;AAC9C,YAAM,YAAY,QAAQ;AAC1B,UAAI,CAAC,MAAM,QAAQ,SAAS,EAAG;AAC/B,YAAM,QAAQ,mBAAmB,gBAAgB,SAAS,CAAC;AAC3D,UAAI,MAAO,QAAO;IACpB;EACF;AAEA,SAAO;AACT;AAEO,IAAM,YAAN,cAAwB,wBAAqC;EACzD,OAAO;EACP,cAAc;EAEf,WAA0B;EAC1B,aAAa,oBAAI,IAAoB;EACrC,eAA8B;EAE9B,eAA8B;AACpC,WAAO,cAAcI,MAAK,oBAAoB,GAAG,UAAU,GAAG,WAAW;EAC3E;EAEA,sBAAsB;AACpB,UAAM,WAAW,oBAAoB;AACrC,WAAO;MACL,QAAQ;MACR,SAAS,CAAC,EAAE,MAAM,UAAU,MAAMA,MAAK,UAAU,UAAU,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;IACvF;EACF;;EAGQ,iBAAuB;AAC7B,UAAM,WAAW,oBAAoB;AACrC,UAAM,aAAaA,MAAK,UAAU,WAAW;AAC7C,UAAM,WAAWA,MAAK,UAAU,aAAa;AAC7C,QAAIJ,YAAW,QAAQ,GAAG;AACxB,YAAM,aAAaE,cAAa,UAAU,OAAO;AACjD,WAAK,eAAe,WAAW,MAAM,iCAAiC,IAAI,CAAC,KAAK;IAClF;AACA,QAAI,CAACF,YAAW,UAAU,EAAG;AAC7B,QAAI;AACF,YAAM,MAAM,SAAS,KAAK,MAAME,cAAa,YAAY,OAAO,CAAC,CAAC;AAClE,YAAM,WAAW,QAAQ,KAAK,SAAS;AACvC,UAAI,CAAC,SAAU;AACf,iBAAW,MAAM,UAAU;AACzB,cAAMY,QAAO,SAAS,SAAS,EAAE,GAAG,IAAI;AACxC,YAAI,CAACA,MAAM;AACX,cAAM,OAAO,WAAW,KAAK,EAAE,OAAOA,KAAI,EAAE,OAAO,KAAK;AACxD,aAAK,WAAW,IAAI,MAAMA,KAAI;MAChC;IACF,QAAQ;IAER;EACF;EAEA,cAAuB;AACrB,SAAK,WAAW,KAAK,aAAa;AAClC,QAAI,CAAC,KAAK,SAAU,QAAO;AAC3B,SAAK,eAAe;AACpB,QAAI;AACF,aAAO,KAAK,gBAAgB,EAAE,SAAS;IACzC,QAAQ;IAER;AACA,WAAO;EACT;;EAGQ,kBAA4B;AAClC,QAAI,CAAC,KAAK,SAAU,QAAO,CAAC;AAC5B,UAAM,OAAiB,CAAC;AACxB,QAAI;AACF,iBAAW,aAAab,aAAY,KAAK,UAAU,EAAE,eAAe,KAAK,CAAC,GAAG;AAC3E,YAAI,CAAC,UAAU,YAAY,EAAG;AAC9B,cAAM,WAAWG,MAAK,KAAK,UAAU,UAAU,IAAI;AACnD,YAAI;AACF,qBAAW,gBAAgBH,aAAY,UAAU,EAAE,eAAe,KAAK,CAAC,GAAG;AACzE,gBAAI,CAAC,aAAa,YAAY,EAAG;AACjC,kBAAM,cAAcG,MAAK,UAAU,aAAa,IAAI;AACpD,gBACEJ,YAAWI,MAAK,aAAa,eAAe,CAAC,KAC7CJ,YAAWI,MAAK,aAAa,YAAY,CAAC,GAC1C;AACA,mBAAK,KAAK,WAAW;YACvB;UACF;QACF,QAAQ;QAER;MACF;IACF,QAAQ;IAER;AACA,WAAO;EACT;;;;;EAMQ,2BAA2B,YAAuD;AACxF,QAAI;AACF,YAAM,YAAYC,UAAS,UAAU;AACrC,YAAM,cAAcA,UAASC,SAAQ,UAAU,CAAC;AAChD,YAAM,cAAcF,MAAK,YAAY,eAAe;AACpD,YAAM,WAAWA,MAAK,YAAY,YAAY;AAE9C,YAAM,sBAAsBJ,YAAW,WAAW,IAAI,cAAc;AACpE,YAAM,mBAAmBA,YAAW,QAAQ,IAAI,WAAW;AAC3D,UAAI,CAAC,uBAAuB,CAAC,kBAAkB;AAC7C,eAAO,eAAe,oBAAoB;MAC5C;AAEA,YAAM,YAAYI,MAAK,YAAY,YAAY;AAC/C,YAAM,WAAWA,MAAK,YAAY,eAAe;AAEjD,UAAI,gBAAgB;AACpB,UAAI,YAA2B;AAC/B,UAAI,WAAW;AAEf,UAAIJ,YAAW,SAAS,GAAG;AACzB,cAAM,QAAQ,SAAS,KAAK,MAAME,cAAa,WAAW,OAAO,CAAC,CAAC,KAAK,CAAC;AACzE,wBAAgB,OAAO,MAAM,gBAAgB,EAAE;AAC/C,oBAAY,cAAc,KAAK;AAC/B,mBAAW;MACb,WAAWF,YAAW,QAAQ,GAAG;AAC/B,cAAM,OAAO,SAAS,KAAK,MAAME,cAAa,UAAU,OAAO,CAAC,CAAC,KAAK,CAAC;AACvE,wBAAgB,OAAO,KAAK,SAAS,EAAE;AACvC,oBAAY,cAAc,IAAI;AAC9B,mBAAW;MACb;AAEA,YAAM,YACJ,cAAc,OACV,YAAY,MACZ,WACEC,UAAS,QAAQ,EAAE,UACnBA,UAAS,UAAU,EAAE;AAE7B,aAAO,cAAc;QACnB,IAAI;QACJ,YAAY;QACZ,KAAK,KAAK,WAAW,IAAI,WAAW,KAAK;QACzC,aAAa;QACb,UAAU;QACV;QACA;QACA;MACF,CAAC;IACH,QAAQ;AACN,aAAO,eAAe,oBAAoB;IAC5C;EACF;;;;;EAMQ,sBAAsB,YAAqD;AACjF,UAAM,SAAS,KAAK,2BAA2B,UAAU;AACzD,QAAI,OAAO,WAAW,SAAU,QAAO;AAEvC,UAAM,SAAS,OAAO;AACtB,UAAM,QACJ,mBAAmB,OAAO,aAAa,KACvC,oBAAoB,MAAM,sBAAsB,OAAO,aAAa,OAAO,QAAQ,GAAG,IAAI;AAE5F,WAAO,cAAc,EAAE,GAAG,QAAQ,OAAO,eAAe,OAAO,UAAU,CAAC;EAC5E;EAEA,mBAAmB,SAAgD;AACjE,QAAI,CAAC,KAAK,SAAU,QAAO,CAAC;AAC5B,UAAM,OAA2B,CAAC;AAClC,eAAW,OAAO,KAAK,gBAAgB,GAAG;AACxC,YAAM,SAAS,iBAAiB,KAAK,2BAA2B,GAAG,CAAC;AACpE,UAAI,CAAC,UAAU,CAAC,kBAAkB,OAAO,WAAW,OAAO,EAAG;AAC9D,WAAK,KAAK;QACR,WAAW,OAAO;QAClB,YAAY,OAAO;QACnB,aAAa,KAAK,kBAAkB,MAAM;MAC5C,CAAC;IACH;AACA,WAAO;EACT;EAEA,kBAAkB,YAAwC;AACxD,UAAM,OAAO,iBAAiB,KAAK,sBAAsB,UAAU,CAAC;AACpE,QAAI,CAAC,KAAM,QAAO;AAClB,SAAK,oBAAoB,KAAK,kBAAkB,IAAI;AACpD,SAAK,eAAe,IAAI,KAAK,IAAI,IAAI;AACrC,UAAM,QAAQ,KAAK,aAAa,KAAK,UAAU;AAC/C,WAAO;MACL,IAAI,KAAK;MACT,MAAM,QAAQ,KAAK,EAAE;MACrB,OAAO,KAAK;MACZ,WAAW,KAAK;MAChB,cAAc,KAAK;MACnB,cAAc,KAAK;MACnB;IACF;EACF;EAEA,eAAe,WAAkC;AAC/C,UAAM,OAAO,KAAK,eAAe,IAAI,SAAS;AAC9C,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,sBAAsB,SAAS,EAAE;AAE5D,QAAI,KAAK,aAAa;AACpB,aAAO,KAAK,0BAA0B,IAAI;IAC5C;AACA,WAAO,KAAK,uBAAuB,IAAI;EACzC;EAEQ,0BAA0B,MAAkC;AAClE,QAAI,CAAC,KAAK,YAAa,OAAM,IAAI,MAAM,0BAA0B;AAEjE,UAAM,UAAU,IAAI,kBAAkB;AACtC,UAAM,qBAAqB,oBAAI,IAAY;AAE3C,QAAI,MAAM;AACV,UAAM,aAAa,KAAK;AACxB,eAAW,UAAU,cAAc,KAAK,WAAW,GAAG;AACpD;AACA,UAAI;AACF,cAAM,OAAO,OAAO,OAAO,QAAQ,EAAE;AACrC,YAAI,SAAS,iBAAiB,SAAS,YAAY,oBAAoB,IAAI,EAAG;AAE9E,YAAI,SAAS,QAAQ;AACnB,gBAAM,OAAO,kBAAkB,gBAAgB,OAAO,OAAO,CAAC;AAC9D,cAAI,MAAM;AACR,oBAAQ,cAAc;cACpB,IAAI,WAAW,GAAG;cAClB,MAAM;cACN,aAAa;cACb,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,cAAc,WAAW,CAAC;YAC1D,CAAC;UACH;AACA;QACF;AAEA,YAAI,SAAS,aAAa;AACxB,gBAAM,UAAU,KAAK;YACnB;YACA;YACA;YACA;UACF;AACA,cAAI,CAAC,QAAS;AACd,kBAAQ,cAAc,OAAO;AAC7B;QACF;AAEA,YAAI,SAAS,QAAQ;AACnB,gBAAM,SAAS,OAAO,OAAO,gBAAgB,EAAE,EAAE,KAAK;AACtD,cAAI,UAAU,mBAAmB,IAAI,MAAM,EAAG;AAC9C,gBAAM,cAAc,yBAAyB,OAAO,SAAS,UAAU;AACvE,cAAI,UAAU,KAAK,mBAAmB,SAAS,QAAQ,WAAW,GAAG;AACnE;UACF;AACA,cAAI,YAAY,SAAS,GAAG;AAC1B,oBAAQ,cAAc;cACpB,IAAI,WAAW,GAAG;cAClB,MAAM;cACN,aAAa;cACb,OAAO;YACT,CAAC;UACH;QACF;MACF,QAAQ;MAER;IACF;AAEA,UAAM,QAAQ,KAAK,aAAa,KAAK,UAAU;AAC/C,WAAO,KAAK,iBAAiB,MAAM,SAAS,KAAK;EACnD;EAEQ,uBAAuB,MAAkC;AAC/D,UAAM,WAAW,KAAK,YAAYC,MAAK,KAAK,YAAY,YAAY;AACpE,QAAI,CAACJ,YAAW,QAAQ,EAAG,OAAM,IAAI,MAAM,uBAAuB;AAElE,UAAM,UAAU,IAAI,kBAAkB;AACtC,UAAM,qBAAqB,oBAAI,IAAY;AAC3C,UAAM,yBAAyB,oBAAI,IAAoB;AAEvD,QAAI,iBAAgC;AACpC,QAAI,MAAM;AAEV,eAAW,UAAU,cAAc,QAAQ,GAAG;AAC5C;AACA,UAAI;AACF,cAAM,UAAU,SAAS,OAAO,OAAO,KAAK,CAAC;AAC7C,cAAM,UAAU,SAAS,QAAQ,IAAI,KAAK;AAC1C,YAAI,oBAAoB,OAAO,EAAG;AAClC,cAAM,UAAU,SAAS,QAAQ,OAAO,KAAK,CAAC;AAC9C,cAAM,cAAc,KAAK,MAAM,kBAAkB,MAAM,IAAI,GAAI;AAG/D,cAAM,QAAQ,SAAS,QAAQ,OAAO,CAAC;AACvC,YAAI,OAAO;AACT,gBAAM,cAAc,kBAAkB,OAAO,cAAc;AAC3D,gBAAM,eAAe,kBAAkB,OAAO,eAAe;AAC7D,cAAI,eAAe,cAAc;AAC/B,kBAAM,SAAS,EAAE,OAAO,aAAa,QAAQ,aAAa;AAC1D,kBAAM,OAAO,kBAAkB,KAAK,cAAc,MAAM;AACxD,oBAAQ,6BAA6B,QAAQ;cAC3C,OAAO,KAAK;cACZ,MAAM,QAAQ;cACd,YAAY,SAAS,OAAO,SAAY;YAC1C,CAAC;UACH;QACF;AAEA,YAAI,YAAY,aAAa;AAC3B,gBAAM,YAAY,QAAQ;AAC1B,cAAI,MAAM,QAAQ,SAAS,KAAK,UAAU,SAAS,GAAG;AACpD,kBAAM,OAAO,kBAAkB,gBAAgB,SAAS,CAAC;AACzD,gBAAI,MAAM;AACR,sBAAQ,cAAc;gBACpB,IAAI,QAAQ,GAAG;gBACf,MAAM;gBACN;gBACA,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC;cAC3D,CAAC;YACH;UACF;AACA,kBAAQ,UAAU;AAClB,2BAAiB;AACjB;QACF;AAEA,YAAI,YAAY,eAAe;AAC7B,gBAAM,WAAW,OAAO,QAAQ,QAAQ,EAAE;AAC1C,cAAI,aAAa,SAAS;AACxB,kBAAM,OAAO,kBAAkB,OAAO,QAAQ,SAAS,EAAE,CAAC;AAC1D,gBAAI,MAAM;AACR,sBAAQ;gBACN,EAAE,MAAM,aAAa,MAAM,cAAc,YAAY;gBACrD,EAAE,IAAI,QAAQ,GAAG,IAAI,aAAa,GAAG,OAAO,OAAO;gBACnD,EAAE,UAAU,UAAU;cACxB;YACF;UACF,WAAW,aAAa,QAAQ;AAC9B,kBAAM,OAAO,kBAAkB,OAAO,QAAQ,QAAQ,EAAE,CAAC;AACzD,gBAAI,MAAM;AACR,sBAAQ;gBACN,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY;gBAChD,EAAE,IAAI,QAAQ,GAAG,IAAI,aAAa,GAAG,OAAO,OAAO;gBACnD,EAAE,UAAU,UAAU;cACxB;YACF;UACF;AACA;QACF;AAEA,YAAI,YAAY,YAAY;AAC1B,gBAAM,YAAY,SAAS,QAAQ,QAAQ;AAC3C,gBAAM,WAAW,OAAO,WAAW,QAAQ,EAAE,EAAE,KAAK;AACpD,gBAAM,SAAS,OAAO,QAAQ,MAAM,EAAE,EAAE,KAAK;AAE7C,cAAI,YAAY,UAAU,mBAAmB,IAAI,QAAQ,GAAG;AAC1D,+BAAmB,IAAI,MAAM;AAC7B,6BAAiB;AACjB;UACF;AAEA,cAAI,CAAC,aAAa,CAAC,UAAU,CAAC,SAAU;AAExC,gBAAM,UAAU,UAAU;AAC1B,gBAAM,iBAAiB,uBAAuB,OAAO;AACrD,gBAAM,SACJ,OAAO,YAAY,YAAY,OAAO,mBAAmB,WAAW,UAAU;AAEhF,gBAAMkB,YAAwB;YAC5B,MAAM;YACN,MAAM;YACN,QAAQ;YACR,OAAO,aAAa,QAAQ;YAC5B,OAAO,EAAE,QAAQ,WAAW,OAAO,gBAAgB,QAAQ,KAAK;YAChE,cAAc;UAChB;AAEA,kBAAQ;YACNA;YACA,EAAE,IAAI,QAAQ,GAAG,IAAI,aAAa,GAAG,OAAO,OAAO;YACnD,EAAE,gBAAgB,MAAM,QAAQ,UAAU;UAC5C;AACA,2BAAiB;AAEjB,cAAI,WAAW,MAAM;AACnB,mCAAuB,IAAI,QAAQ,MAAM;UAC3C;AACA;QACF;AAEA,YAAI,YAAY,gBAAgB;AAC9B,cAAI,kBAAkB,mBAAmB,IAAI,cAAc,EAAG;AAC9D,gBAAM,gBAAgB,OAAO,QAAQ,kBAAkB,EAAE;AACzD,eAAK;YACH;YACA;YACA;YACA;UACF;AACA;QACF;AAEA,YAAI,YAAY,cAAc;AAC5B,gBAAM,SAAS,OAAO,QAAQ,gBAAgB,EAAE,EAAE,KAAK;AACvD,cAAI,UAAU,mBAAmB,IAAI,MAAM,EAAG;AAC9C,gBAAM,cAAc,6BAA6B,QAAQ,cAAc,WAAW;AAClF,cAAI,UAAU,KAAK,mBAAmB,SAAS,QAAQ,WAAW,GAAG;AACnE;UACF;AACA,cAAI,YAAY,SAAS,GAAG;AAC1B,oBAAQ,cAAc;cACpB,IAAI,QAAQ,GAAG;cACf,MAAM;cACN;cACA,OAAO;YACT,CAAC;UACH;AACA;QACF;MAGF,QAAQ;MAER;IACF;AAEA,UAAM,QAAQ,KAAK,aAAa,KAAK,UAAU;AAC/C,WAAO,KAAK,iBAAiB,MAAM,SAAS,KAAK;EACnD;;EAIQ,kBAAkB,MAAoE;AAC5F,WAAO,KAAK,UAAU;MACpB,KAAK,gBAAgB,KAAK,QAAQ;MAClC,KAAK,gBAAgB,KAAK,WAAW;MACrC,KAAK,gBAAgB,KAAK,QAAQ;IACpC,CAAC;EACH;EAEQ,6BACN,QACA,KACA,oBACA,YAC+B;AAC/B,UAAM,QAAuB,CAAC;AAE9B,UAAM,UAAU,OAAO;AACvB,QAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,iBAAW,QAAQ,SAAS;AAC1B,cAAM,KAAK,SAAS,IAAI;AACxB,YAAI,CAAC,GAAI;AACT,cAAM,WAAW,OAAO,GAAG,QAAQ,EAAE;AAErC,YAAI,aAAa,SAAS;AACxB,gBAAM,OAAO,kBAAkB,OAAO,GAAG,SAAS,EAAE,CAAC;AACrD,cAAI,KAAM,OAAM,KAAK,EAAE,MAAM,aAAa,MAAM,cAAc,WAAW,CAAC;QAC5E,WAAW,aAAa,QAAQ;AAC9B,gBAAM,OAAO,kBAAkB,OAAO,GAAG,QAAQ,EAAE,CAAC;AACpD,cAAI,KAAM,OAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,cAAc,WAAW,CAAC;QACvE;MACF;IACF;AAEA,UAAM,YAAY,QAAQ,OAAO,UAAU;AAC3C,QAAI,WAAW;AACb,iBAAW,MAAM,WAAW;AAC1B,cAAM,WAAW,SAAS,EAAE;AAC5B,cAAM,YAAY,SAAS,UAAU,QAAQ;AAE7C,YAAI,CAAC,UAAW;AAChB,cAAM,WAAW,OAAO,UAAU,QAAQ,EAAE,EAAE,KAAK;AACnD,cAAM,SAAS,OAAO,UAAU,MAAM,EAAE,EAAE,KAAK;AAE/C,YAAI,YAAY,UAAU,mBAAmB,IAAI,QAAQ,GAAG;AAC1D,6BAAmB,IAAI,MAAM;AAC7B;QACF;AAEA,YAAI,CAAC,YAAY,CAAC,OAAQ;AAE1B,cAAM,OAAoB;UACxB,MAAM;UACN,MAAM;UACN,QAAQ;UACR,OAAO,aAAa,QAAQ;UAC5B,OAAO;YACL,QAAQ;YACR,OAAO,uBAAuB,UAAU,SAAS;YACjD,QAAQ;UACV;UACA,cAAc;QAChB;AACA,cAAM,KAAK,IAAI;MACjB;IACF;AAEA,QAAI,MAAM,WAAW,GAAG;AACtB,aAAO;IACT;AAEA,UAAM,WAAW,MAAM,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM;AACrD,WAAO;MACL,IAAI,WAAW,GAAG;MAClB,MAAM;MACN,aAAa;MACb;MACA,OAAO;MACP,MAAM,WAAW,SAAS;IAC5B;EACF;EAEQ,uBACN,eACA,YACA,QACA,SACM;AACN,QAAI,CAAC,WAAY;AAEjB,UAAM,WAAW,OAAO,IAAI,UAAU,KAAK;AAC3C,UAAM,WAAW,WAAW;AAE5B,QAAI;AACF,YAAM,SAAkB,KAAK,MAAM,QAAQ;AAC3C,UACE,QAAQ,eAAe,YAAY,CAAC,SAAS;AAC3C,aAAK,MAAM,QAAQ;MACrB,CAAC,GACD;AACA,eAAO,OAAO,UAAU;MAC1B;IACF,QAAQ;AACN,aAAO,IAAI,YAAY,QAAQ;IACjC;EACF;EAEQ,mBACN,SACA,QACA,aACS;AACT,QAAI,CAAC,YAAY,UAAU,CAAC,OAAQ,QAAO;AAE3C,WAAO,QAAQ,gBAAgB,QAAQ,EAAE,QAAQ,CAAC,GAAG,WAAW,EAAE,CAAC;EACrE;;EAGQ,gBAAgB,QAAiC,OAAqC;AAC5F,QAAI,OAAO,SAAS,SAAU;AAC9B,UAAM,aAAa,SAAS,OAAO,WAAW;AAC9C,QAAI,eAAe,QAAW;AAC5B,0BAAoB,QAAQ,mBAAmB;AAC/C;IACF;AACA,UAAM,eAAe;EACvB;EAEQ,aAAa,YAA4C;AAC/D,QAAI,YAAY;AAChB,UAAM,QAAgC;MACpC,YAAY;MACZ,oBAAoB;MACpB,qBAAqB;MACrB,cAAc;MACd,eAAe;IACjB;AAEA,UAAM,WAAWd,MAAK,YAAY,YAAY;AAC9C,QAAI,CAACJ,YAAW,QAAQ,EAAG,QAAO;AAKlC,UAAM,cAAcI,MAAK,YAAY,eAAe;AACpD,UAAM,aAAaJ,YAAW,WAAW;AAEzC,QAAI;AACF,iBAAW,UAAU,cAAc,QAAQ,GAAG;AAC5C,cAAM,aAAa,SAAS,SAAS,OAAO,OAAO,GAAG,KAAK;AAC3D,YAAI,YAAY;AACd,gBAAM,cAAc,kBAAkB,YAAY,cAAc;AAChE,gBAAM,eAAe,kBAAkB,YAAY,eAAe;AAClE,gBAAM,sBAAsB;AAC5B,gBAAM,uBAAuB;AAC7B,gBAAM,OAAO,kBAAkB,KAAK,cAAc;YAChD,OAAO;YACP,QAAQ;UACV,CAAC;AACD,cAAI,SAAS,KAAM,cAAa;QAClC;AACA,YAAI,CAAC,WAAY,MAAK,gBAAgB,QAAQ,KAAK;MACrD;IACF,QAAQ;IAER;AAEA,QAAI,YAAY;AACd,UAAI;AACF,mBAAW,UAAU,cAAc,WAAW,EAAG,MAAK,gBAAgB,QAAQ,KAAK;MACrF,QAAQ;MAER;IACF;AAEA,UAAM,aAAa,OAAO,UAAU,QAAQ,CAAC,CAAC;AAC9C,QAAI,MAAM,aAAa,GAAG;AACxB,YAAM,cAAc;IACtB;AAEA,WAAO;EACT;EAEQ,iBACN,MACA,SACA,OACe;AACf,UAAM,aAAa,QAAQ,OAAO,KAAK;AACvC,WAAO;MACL,WAAW,EAAE,WAAW,KAAK,MAAM,WAAW,KAAK,GAAG;MACtD,IAAI,KAAK;MACT,OAAO,KAAK;MACZ,MAAM,QAAQ,KAAK,EAAE;MACrB,WAAW,KAAK;MAChB,cAAc,KAAK;MACnB,cAAc,KAAK;MACnB,OAAO,WAAW;MAClB,UAAU,WAAW;IACvB;EACF;AACF;ACxwBA,IAAM,2BAAmD;EACvD,MAAM;EACN,OAAO;EACP,MAAM;EACN,MAAM;EACN,UAAU;EACV,iBAAiB;EACjB,eAAe;EACf,cAAc;EACd,UAAU;EACV,MAAM;EACN,gBAAgB;EAChB,MAAM;EACN,WAAW;EACX,OAAO;AACT;AAEA,IAAM,0BAA0B,oBAAI,IAAI,CAAC,aAAa,CAAC;AAEhD,SAAS,0BAAkC;AAChD,SAAO,gBAAgB,kBAAkB,YAAY;AACvD;AAkCA,SAASsB,cAAa,UAA0B;AAC9C,SAAO,yBAAyB,QAAQ,KAAK;AAC/C;AAEA,SAASC,wBAAuB,KAAuB;AACrD,MAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,MAAI;AACF,WAAO,KAAK,MAAM,GAAG;EACvB,QAAQ;AACN,WAAO;EACT;AACF;AAEA,SAAS,eAAe,KAA6B;AACnD,MAAI,OAAO,QAAQ,SAAU,QAAO,OAAO,SAAS,GAAG,IAAI,MAAM;AACjE,MAAI,OAAO,QAAQ,YAAY,IAAI,KAAK,MAAM,GAAI,QAAO;AAEzD,QAAM,UAAU,OAAO,GAAG;AAC1B,MAAI,OAAO,SAAS,OAAO,EAAG,QAAO;AACrC,QAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,SAAO,OAAO,SAAS,MAAM,IAAI,SAAS;AAC5C;AAEA,SAAS,oBAAoB,QAAyC;AACpE,SAAO,eAAe,OAAO,IAAI,KAAK;AACxC;AAEA,SAAS,YAAY,SAA0B;AAC7C,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,MAAI,CAAC,MAAM,QAAQ,OAAO,GAAG;AAC3B,UAAM,SAAS,SAAS,OAAO;AAC/B,WAAO,SAAS,OAAO,OAAO,QAAQ,EAAE,IAAI;EAC9C;AAEA,SAAO,QACJ,IAAI,CAAC,SAAS;AACb,QAAI,OAAO,SAAS,SAAU,QAAO;AACrC,UAAM,SAAS,SAAS,IAAI;AAC5B,WAAO,SAAS,OAAO,OAAO,QAAQ,EAAE,IAAI;EAC9C,CAAC,EACA,KAAK,GAAG;AACb;AAEA,SAAS,aAAa,SAAkB,aAAoC;AAC1E,QAAM,SAAS,MAAM,QAAQ,OAAO,IAAI,UAAU,CAAC,OAAO;AAC1D,QAAM,QAAuB,CAAC;AAE9B,aAAW,SAAS,QAAQ;AAC1B,QAAI,OAAO,UAAU,UAAU;AAC7B,YAAM,OAAO,kBAAkB,KAAK;AACpC,UAAI,KAAM,OAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC;AACtE;IACF;AAEA,UAAM,SAAS,SAAS,KAAK;AAC7B,QAAI,CAAC,OAAQ;AACb,UAAM,OAAO,SAAS,OAAO,IAAI,KAAK;AACtC,QAAI,SAAS,QAAQ;AACnB,YAAM,OAAO,kBAAkB,SAAS,OAAO,IAAI,KAAK,EAAE;AAC1D,UAAI,KAAM,OAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC;AACtE;IACF;AACA,QAAI,SAAS,SAAS;AACpB,YAAM,OAAO,kBAAkB,SAAS,OAAO,KAAK,KAAK,EAAE;AAC3D,UAAI,KAAM,OAAM,KAAK,EAAE,MAAM,aAAa,MAAM,cAAc,YAAY,CAAC;AAC3E;IACF;AACA,QAAI,SAAS,QAAQ;AACnB,YAAM,OAAO,kBAAkB,SAAS,OAAO,IAAI,KAAK,EAAE;AAC1D,UAAI,MAAM;AACR,cAAM,KAAK;UACT,MAAM;UACN;UACA,iBAAiB,OAAO,aAAa,QAAQ,SAAS;UACtD,cAAc;QAChB,CAAC;MACH;AACA;IACF;AACA,QAAI,SAAS,SAAS;AACpB,YAAM,SAAS,SAAS,OAAO,MAAM;AACrC,YAAM,WAAW,SAAS,OAAO,QAAQ;AACzC,YAAM,MACJ,SAAS,OAAO,GAAG,KACnB,SAAS,UAAU,GAAG,MACrB,QAAQ,SAAS,QAAQ,SAAS,OAAO,GAAG,IAAI;AACnD,YAAM,OACJ,SAAS,OAAO,IAAI,MAAM,QAAQ,SAAS,WAAW,SAAS,OAAO,IAAI,IAAI;AAChF,YAAM,WACJ,SAAS,OAAO,SAAS,KACzB,SAAS,OAAO,UAAU,MACzB,QAAQ,SAAS,WAAW,SAAS,OAAO,UAAU,IAAI,WAC3D;AACF,UAAI,IAAK,OAAM,KAAK,EAAE,MAAM,SAAS,KAAK,WAAW,UAAU,cAAc,YAAY,CAAC;eACjF,MAAM;AACb,cAAM,KAAK;UACT,MAAM;UACN;UACA,WAAW;UACX,cAAc;QAChB,CAAC;MACH;AACA;IACF;AACA,QAAI,SAAS,aAAa;AACxB,YAAM,WAAW,SAAS,OAAO,QAAQ;AACzC,YAAM,MAAM,SAAS,UAAU,GAAG,KAAK,SAAS,OAAO,GAAG;AAC1D,UAAI,IAAK,OAAM,KAAK,EAAE,MAAM,SAAS,KAAK,cAAc,YAAY,CAAC;IACvE;EACF;AAEA,SAAO;AACT;AAEA,SAAS,gBAAgB,QAAiB,aAAoC;AAC5E,MAAI,OAAO,WAAW,UAAU;AAC9B,UAAMJ,QAAO,kBAAkB,MAAM;AACrC,WAAOA,QAAO,CAAC,EAAE,MAAM,QAAQ,MAAAA,OAAM,cAAc,YAAY,CAAC,IAAI,CAAC;EACvE;AACA,MAAI,MAAM,QAAQ,MAAM,EAAG,QAAO,aAAa,QAAQ,WAAW;AAClE,MAAI,UAAU,KAAM,QAAO,CAAC;AAE5B,QAAM,SAAS,SAAS,MAAM;AAC9B,MAAI,QAAQ,SAAS,OAAQ,QAAO,aAAa,CAAC,MAAM,GAAG,WAAW;AAEtE,QAAM,OAAO,kBAAkB,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAC9D,SAAO,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC,IAAI,CAAC;AACvE;AAEA,SAAS,SAAS,UAAkB,QAAgB,OAAgB,aAA+B;AACjG,SAAO;IACL,MAAM;IACN,MAAM;IACN,QAAQ;IACR,OAAOG,cAAa,QAAQ;IAC5B,OAAO;MACL,QAAQ;MACR,GAAI,UAAU,SAAY,CAAC,IAAI,EAAE,MAAM;MACvC,QAAQ;IACV;IACA,cAAc;EAChB;AACF;AAEA,SAAS,cACP,SACA,aACA,oBACe;AACf,QAAM,QAAQ,QAAQ,QAAQ,SAAS,KAAK,CAAC;AAC7C,QAAM,QAAuB,CAAC;AAE9B,aAAW,QAAQ,OAAO;AACxB,UAAM,aAAa,SAAS,IAAI;AAChC,UAAM,iBAAiB,SAAS,YAAY,QAAQ,KAAK;AACzD,UAAM,WAAW,SAAS,gBAAgB,IAAI,GAAG,KAAK,KAAK;AAC3D,UAAM,SAAS,SAAS,YAAY,EAAE,GAAG,KAAK,KAAK;AACnD,QAAI,CAAC,YAAY,CAAC,OAAQ;AAC1B,QAAI,wBAAwB,IAAI,QAAQ,GAAG;AACzC,yBAAmB,IAAI,MAAM;AAC7B;IACF;AAEA,UAAM,eAAe,gBAAgB,aAAa,YAAY;AAC9D,UAAM,KAAK,SAAS,UAAU,QAAQC,wBAAuB,YAAY,GAAG,WAAW,CAAC;EAC1F;AAEA,SAAO;AACT;AAEA,SAAS,kBACP,SACA,QACA,QACA,aACA,UAAU,OACV,MACS;AACT,QAAM,cAAc,gBAAgB,QAAQ,WAAW;AACvD,SAAO,QAAQ,gBAAgB,QAAQ;IACrC,QAAQ;IACR,QAAQ,UAAU,UAAU;IAC5B,GAAI,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,IAAI,EAAE,EAAE,IAAI,CAAC;EAChE,CAAC;AACH;AAEA,SAAS,YAAY,OAAgC,OAAuB;AAC1E,SAAO,SAAS,MAAM,KAAK,CAAC,KAAK;AACnC;AAEA,SAAS,aAA2B;AAClC,SAAO;IACL,eAAe;IACf,oBAAoB;IACpB,qBAAqB;IACrB,YAAY;EACd;AACF;AAEA,SAAS,mBAAgC;AACvC,SAAO;IACL,WAAW;IACX,kBAAkB;IAClB,mBAAmB;IACnB,sBAAsB;IACtB,wBAAwB;IACxB,YAAY,CAAC;EACf;AACF;AAEA,SAAS,WACP,SACA,QACA,aACA,QACM;AACN,QAAM,QAAQ,SAAS,OAAO,KAAK;AACnC,MAAI,CAAC,MAAO;AAEZ,QAAM,YAAY,YAAY,OAAO,gBAAgB;AACrD,QAAM,cAAc,YAAY,OAAO,oBAAoB;AAC3D,QAAM,aAAa,YAAY,OAAO,YAAY;AAClD,QAAM,SAAS,YAAY,OAAO,QAAQ;AAC1C,QAAM,QAAQ,aAAa,YAAY;AACvC,QAAM,QAAQ,SAAS,OAAO,KAAK,KAAK;AACxC,QAAM,SAAS;IACb;IACA;IACA,YAAY;IACZ,cAAc;EAChB;AACA,QAAM,OAAO,kBAAkB,OAAO,MAAM;AAE5C,SAAO,oBAAoB;AAC3B,SAAO,qBAAqB;AAC5B,SAAO,wBAAwB;AAC/B,SAAO,0BAA0B;AACjC,MAAI,MAAO,QAAO,WAAW,KAAK,KAAK,OAAO,WAAW,KAAK,KAAK,KAAK,QAAQ;AAChF,MAAI,SAAS,KAAM,QAAO,aAAa;AAEvC,UAAQ,6BAA6B,QAAQ;IAC3C;IACA,MAAM,QAAQ;IACd,YAAY,SAAS,OAAO,SAAY;EAC1C,CAAC;AACH;AAEA,SAAS,UAAU,WAAmD;AACpE,MAAI;AACF,WAAO,SAAS,KAAK,MAAMrB,cAAa,WAAW,OAAO,CAAC,CAAC,KAAK;EACnE,QAAQ;AACN,WAAO;EACT;AACF;AAEO,IAAM,gBAAN,cAA4B,wBAAqC;EAC7D,OAAO;EACP,cAAc;EAEf,WAA0B;EAC1B,uBAAuB,oBAAI,IAAoB;EAE/C,eAA8B;AACpC,UAAM,eAAeE,MAAK,wBAAwB,GAAG,UAAU;AAC/D,WAAOJ,YAAW,YAAY,IAAI,eAAe;EACnD;EAEA,sBAAsB;AACpB,UAAM,WAAW,wBAAwB;AACzC,WAAO;MACL,QAAQ;MACR,SAAS;QACP,EAAE,MAAM,UAAU,MAAMI,MAAK,UAAU,UAAU,EAAE;QACnD,EAAE,MAAM,UAAU,MAAMA,MAAK,UAAU,qBAAqB,EAAE;MAChE;IACF;EACF;EAEA,cAAuB;AACrB,SAAK,WAAW,KAAK,aAAa;AAClC,QAAI,CAAC,KAAK,SAAU,QAAO;AAC3B,QAAI;AACF,aAAO,KAAK,gBAAgB,EAAE,SAAS;IACzC,QAAQ;AACN,aAAO;IACT;EACF;EAEQ,mBAAyB;AAC/B,SAAK,qBAAqB,MAAM;AAChC,QAAI,CAAC,KAAK,SAAU;AAEpB,UAAM,YAAYA,MAAKE,SAAQ,KAAK,QAAQ,GAAG,qBAAqB;AACpE,QAAI,CAACN,YAAW,SAAS,EAAG;AAC5B,eAAW,UAAU,cAAc,SAAS,GAAG;AAC7C,YAAM,cAAc,SAAS,OAAO,UAAU;AAC9C,YAAM,UAAU,SAAS,OAAO,OAAO;AACvC,UAAI,CAAC,eAAe,CAAC,QAAS;AAC9B,WAAK,qBAAqB,IAAI,QAAQ,WAAW,GAAG,OAAO;IAC7D;EACF;EAEQ,kBAA4B;AAClC,QAAI,CAAC,KAAK,SAAU,QAAO,CAAC;AAC5B,UAAM,OAAiB,CAAC;AAExB,QAAI;AACF,iBAAW,UAAUC,aAAY,KAAK,UAAU,EAAE,eAAe,KAAK,CAAC,GAAG;AACxE,YAAI,CAAC,OAAO,YAAY,EAAG;AAC3B,cAAM,aAAaG,MAAK,KAAK,UAAU,OAAO,IAAI;AAClD,mBAAW,WAAWH,aAAY,YAAY,EAAE,eAAe,KAAK,CAAC,GAAG;AACtE,cAAI,CAAC,QAAQ,YAAY,EAAG;AAC5B,gBAAM,cAAcG,MAAK,YAAY,QAAQ,IAAI;AACjD,cACEJ,YAAWI,MAAK,aAAa,YAAY,CAAC,KAC1CJ,YAAWI,MAAK,aAAa,UAAU,QAAQ,YAAY,CAAC,GAC5D;AACA,iBAAK,KAAK,WAAW;UACvB;QACF;MACF;IACF,QAAQ;AACN,aAAO;IACT;AAEA,WAAO;EACT;EAEQ,2BAA2B,YAAuD;AACxF,QAAI;AACF,YAAM,YAAYA,MAAK,YAAY,YAAY;AAC/C,YAAM,WAAWA,MAAK,YAAY,UAAU,QAAQ,YAAY;AAChE,UAAI,CAACJ,YAAW,SAAS,KAAK,CAACA,YAAW,QAAQ,EAAG,QAAO,eAAe,cAAc;AAEzF,YAAM,QAAQ,UAAU,SAAS;AACjC,UAAI,CAAC,MAAO,QAAO,eAAe,iBAAiB;AAEnD,YAAM,aAAaG,UAAS,SAAS,EAAE;AACvC,YAAM,YAAYA,UAAS,QAAQ,EAAE;AACrC,YAAM,YACJ,eAAe,MAAM,SAAS,KAAK,eAAe,MAAM,UAAU,KAAK;AACzE,YAAM,YAAY,KAAK;QACrB,eAAe,MAAM,SAAS,KAAK,eAAe,MAAM,UAAU,KAAK;QACvE;MACF;AACA,YAAM,SAAS,SAAS,MAAM,MAAM;AACpC,YAAM,UACJ,SAAS,MAAM,OAAO,KACtB,SAAS,QAAQ,GAAG,KACpB,KAAK,qBAAqB,IAAI,QAAQ,UAAU,CAAC,KACjD;AACF,YAAM,gBAAgB,SAAS,MAAM,KAAK,KAAK,SAAS,MAAM,WAAW,KAAK;AAE9E,aAAO,cAAc;QACnB,IAAIE,UAAS,UAAU;QACvB,YAAY;QACZ;QACA;QACA;QACA;QACA;QACA;MACF,CAAC;IACH,QAAQ;AACN,aAAO,eAAe,mBAAmB;IAC3C;EACF;EAEQ,kBACN,QACQ;AACR,WAAO,KAAK,UAAU;MACpB,KAAK,gBAAgB,OAAO,SAAS;MACrC,KAAK,gBAAgB,OAAO,QAAQ;MACpC,OAAO;IACT,CAAC;EACH;EAEA,mBAAmB,SAAgD;AACjE,QAAI,CAAC,KAAK,SAAU,QAAO,CAAC;AAC5B,SAAK,iBAAiB;AACtB,UAAM,OAA2B,CAAC;AAElC,eAAW,cAAc,KAAK,gBAAgB,GAAG;AAC/C,YAAM,SAAS,iBAAiB,KAAK,2BAA2B,UAAU,CAAC;AAC3E,UAAI,CAAC,UAAU,CAAC,kBAAkB,OAAO,WAAW,OAAO,EAAG;AAC9D,WAAK,KAAK;QACR,WAAW,OAAO;QAClB,YAAY,OAAO;QACnB,aAAa,KAAK,kBAAkB,MAAM;MAC5C,CAAC;IACH;AAEA,WAAO;EACT;EAEA,gBAAgB,gBAAwB,gBAA+B;AACrE,UAAM,SAAS,MAAM,gBAAgB,gBAAgB,cAAc;AACnE,UAAM,kBAAkB,eACrB,OAAO,CAAC,YAAY,CAAC,KAAK,YAAY,OAAO,CAAC,EAC9C,IAAI,CAAC,YAAY,QAAQ,EAAE;AAC9B,QAAI,gBAAgB,WAAW,EAAG,QAAO;AAEzC,WAAO;MACL,GAAG;MACH,YAAY;MACZ,YAAY,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAI,OAAO,cAAc,CAAC,GAAI,GAAG,eAAe,CAAC,CAAC;IAC7E;EACF;EAEA,qBAAqB,UAAwC;AAC3D,WAAO,KAAK,0BAA0B,QAAQ;EAChD;EAEA,gBACE,gBACA,YACA,MACe;AACf,UAAM,kBAAkB,KAAK,0BAA0B,cAAc;AACrE,WAAO,MAAM,gBAAgB,iBAAiB,YAAY,IAAI;EAChE;EAEQ,YAAY,SAA+B;AACjD,WAAO,QAAQ,MAAM,gBAAgB;EACvC;EAEQ,0BAA0B,UAAwC;AACxE,WAAO,SAAS,OAAO,CAAC,YAAY;AAClC,UAAI,KAAK,YAAY,OAAO,EAAG,QAAO;AACtC,WAAK,eAAe,OAAO,QAAQ,EAAE;AACrC,aAAO;IACT,CAAC;EACH;EAEA,kBAAkB,YAAwC;AACxD,SAAK,iBAAiB;AACtB,UAAM,SAAS,iBAAiB,KAAK,2BAA2B,UAAU,CAAC;AAC3E,QAAI,CAAC,OAAQ,QAAO;AAEpB,UAAM,SAAS,KAAK,UAAU,MAAM;AACpC,UAAM,aAAa,OAAO,QAAQ,OAAO,OAAO,KAAK;AACrD,QAAI,WAAW,SAAS,WAAW,GAAG;AACpC,WAAK,eAAe,OAAO,OAAO,EAAE;AACpC,aAAO;IACT;AAEA,UAAM,QAAQ,oBAAoB,OAAO,eAAe,OAAO,gBAAgB,IAAI;AACnF,UAAM,OAAoB;MACxB,GAAG;MACH;MACA,eAAe,OAAO;MACtB,mBAAmB,KAAK,kBAAkB,MAAM;IAClD;AACA,SAAK,eAAe,IAAI,KAAK,IAAI,IAAI;AACrC,WAAO;MACL,IAAI,KAAK;MACT,MAAM,GAAG,KAAK,IAAI,IAAI,KAAK,EAAE;MAC7B,OAAO,KAAK;MACZ,WAAW,KAAK;MAChB,cAAc,KAAK;MACnB,cAAc,KAAK;MACnB,OAAO,WAAW;MAClB,GAAI,OAAO,KAAK,OAAO,UAAU,EAAE,SAAS,IAAI,EAAE,aAAa,OAAO,WAAW,IAAI,CAAC;IACxF;EACF;EAEA,eAAe,WAAkC;AAC/C,UAAM,OAAO,KAAK,eAAe,IAAI,SAAS;AAC9C,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,sBAAsB,SAAS,EAAE;AAE5D,UAAM,SAAS,KAAK,UAAU,IAAI;AAClC,UAAM,aAAa,OAAO,QAAQ,OAAO,OAAO,KAAK;AACrD,WAAO;MACL,WAAW,EAAE,WAAW,KAAK,MAAM,WAAW,KAAK,GAAG;MACtD,IAAI,KAAK;MACT,OAAO,KAAK;MACZ,MAAM,GAAG,KAAK,IAAI,IAAI,KAAK,EAAE;MAC7B,WAAW,KAAK;MAChB,cAAc,KAAK;MACnB,cAAc,KAAK;MACnB,OAAO,WAAW;MAClB,UAAU,WAAW;IACvB;EACF;EAEQ,UAAU,QAAmC;AACnD,UAAM,UAAU,IAAI,kBAAkB;AACtC,UAAM,SAAS,iBAAiB;AAChC,UAAM,qBAAqB,oBAAI,IAAY;AAC3C,QAAI,cAA6B;AACjC,QAAI,iBAAgC;AACpC,QAAI,iBAAgC;AACpC,QAAI,WAAW;AAEf,eAAW,UAAU,cAAc,OAAO,QAAQ,GAAG;AACnD,kBAAY;AACZ,UAAI;AACF,cAAM,cAAc,oBAAoB,MAAM;AAC9C,cAAM,aAAa,SAAS,OAAO,IAAI,KAAK;AAE5C,YAAI,eAAe,eAAe;AAChC,wBAAc,SAAS,OAAO,KAAK,KAAK;AACxC,2BAAiB,SAAS,OAAO,QAAQ,KAAK;AAC9C;QACF;AACA,YAAI,eAAe,iBAAiB;AAClC,wBAAc,SAAS,OAAO,UAAU,KAAK;AAC7C;QACF;AACA,YAAI,eAAe,gBAAgB;AACjC,qBAAW,SAAS,QAAQ,aAAa,MAAM;AAC/C;QACF;AACA,YAAI,eAAe,0BAA0B;AAC3C,gBAAM,UAAU,SAAS,OAAO,OAAO;AACvC,cAAI,CAAC,QAAS;AACd,gBAAM,OAAO,SAAS,QAAQ,IAAI,KAAK;AACvC,gBAAM,mBAAmB;AAEzB,cAAI,SAAS,QAAQ;AACnB,kBAAM,OAAO,mBAAmB,YAAY,QAAQ,OAAO,CAAC;AAC5D,gBAAI,CAAC,kBAAkB,KAAM,kBAAiB;UAChD;AAEA,cAAI,SAAS,QAAQ;AACnB,kBAAM,SAAS,SAAS,QAAQ,UAAU,GAAG,KAAK,KAAK;AACvD,kBAAM,SAAS,QAAQ;AACvB,gBAAI,UAAU,mBAAmB,IAAI,MAAM,EAAG;AAC9C,gBAAI,UAAU,kBAAkB,SAAS,QAAQ,QAAQ,gBAAgB,EAAG;AAC5E,kBAAM,cAAc,gBAAgB,QAAQ,gBAAgB;AAC5D,gBAAI,YAAY,SAAS,GAAG;AAC1B,sBAAQ,cAAc;gBACpB,IAAI,QAAQ,QAAQ;gBACpB,MAAM;gBACN,aAAa;gBACb,OAAO;cACT,CAAC;YACH;AACA;UACF;AAEA,cAAI,SAAS,UAAU,SAAS,YAAa;AAC7C,gBAAM,QAAQ;YACZ,GAAG,aAAa,QAAQ,SAAS,gBAAgB;YACjD,GAAI,SAAS,cACT,cAAc,SAAS,kBAAkB,kBAAkB,IAC3D,CAAC;UACP;AACA,cAAI,MAAM,WAAW,EAAG;AACxB,gBAAM,WAAW,MAAM,MAAM,CAAC,SAAS,KAAK,SAAS,MAAM;AAC3D,gBAAM,QAAgC;YACpC,IAAI,QAAQ,QAAQ;YACpB;YACA,aAAa;YACb;YACA,GAAI,SAAS,cACT;cACE,OAAO,KAAK;cACZ,MAAM,WAAW,SAAS;cAC1B,OAAO;cACP,UAAU;YACZ,IACA,CAAC;UACP;AACA,kBAAQ,cAAc,KAAK;AAC3B;QACF;AACA,YAAI,eAAe,6BAA6B;AAC9C,gBAAM,QAAQ,SAAS,OAAO,KAAK;AACnC,cAAI,CAAC,MAAO;AACZ,gBAAM,YAAY,SAAS,MAAM,IAAI,KAAK;AAC1C,gBAAM,WAAW;YACf,IAAI,QAAQ,QAAQ;YACpB;YACA,OAAO,KAAK;YACZ,OAAO;YACP,UAAU;UACZ;AAEA,cAAI,cAAc,cAAc;AAC9B,oBAAQ,UAAU;AAClB;UACF;AACA,cAAI,cAAc,gBAAgB;AAChC,kBAAM,OAAO,SAAS,MAAM,IAAI;AAChC,gBAAI,CAAC,KAAM;AACX,kBAAM,QAAQ,aAAa,CAAC,IAAI,GAAG,WAAW;AAC9C,uBAAW,eAAe,OAAO;AAC/B,kBAAI,YAAY,SAAS,OAAQ;AACjC,kBAAI,YAAY,SAAS,WAAW,QAAQ,yBAAyB,WAAW,GAAG;AACjF;cACF;AACA,sBAAQ,oBAAoB,aAAa,UAAU,EAAE,UAAU,UAAU,CAAC;YAC5E;AACA;UACF;AACA,cAAI,cAAc,aAAa;AAC7B,kBAAM,WAAW,SAAS,MAAM,IAAI,GAAG,KAAK,KAAK;AACjD,kBAAM,SAAS,SAAS,MAAM,UAAU,GAAG,KAAK,KAAK;AACrD,gBAAI,CAAC,YAAY,CAAC,OAAQ;AAC1B,gBAAI,wBAAwB,IAAI,QAAQ,GAAG;AACzC,iCAAmB,IAAI,MAAM;AAC7B;YACF;AACA,oBAAQ,eAAe,SAAS,UAAU,QAAQ,MAAM,MAAM,WAAW,GAAG,UAAU;cACpF,gBAAgB;cAChB,QAAQ;YACV,CAAC;AACD;UACF;AACA,cAAI,cAAc,eAAe;AAC/B,kBAAM,SAAS,SAAS,MAAM,UAAU,GAAG,KAAK,KAAK;AACrD,kBAAM,SAAS,SAAS,MAAM,MAAM;AACpC,gBAAI,CAAC,UAAU,mBAAmB,IAAI,MAAM,EAAG;AAC/C,kBAAM,SAAS,QAAQ;AACvB,kBAAM,UAAU,QAAQ,YAAY;AACpC,kBAAM,OAAO,SAAS,QAAQ,IAAI;AAClC,gBAAI,kBAAkB,SAAS,QAAQ,QAAQ,aAAa,SAAS,IAAI,EAAG;AAC5E,kBAAM,cAAc,gBAAgB,QAAQ,WAAW;AACvD,gBAAI,YAAY,SAAS,GAAG;AAC1B,sBAAQ,cAAc;gBACpB,IAAI,QAAQ,QAAQ;gBACpB,MAAM;gBACN;gBACA,OAAO;cACT,CAAC;YACH;UACF;AACA;QACF;AACA,YAAI,eAAe,4BAA4B;AAC7C,gBAAM,UAAU,kBAAkB,SAAS,OAAO,OAAO,KAAK,EAAE;AAChE,cAAI,SAAS;AACX,oBAAQ,cAAc;cACpB,IAAI,QAAQ,QAAQ;cACpB,MAAM;cACN;cACA,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,SAAS,cAAc,YAAY,CAAC;YACpE,CAAC;UACH;QACF;MACF,QAAQ;AACN;MACF;IACF;AAEA,UAAM,QAAsB;MAC1B,GAAG,WAAW;MACd,oBAAoB,OAAO;MAC3B,qBAAqB,OAAO;MAC5B,YAAY,OAAO,OAAO,UAAU,QAAQ,CAAC,CAAC;MAC9C,cAAc,OAAO,mBAAmB,OAAO;MAC/C,GAAI,OAAO,uBAAuB,IAC9B,EAAE,yBAAyB,OAAO,qBAAqB,IACvD,CAAC;MACL,GAAI,OAAO,yBAAyB,IAChC,EAAE,2BAA2B,OAAO,uBAAuB,IAC3D,CAAC;MACL,GAAI,OAAO,YAAY,IAAI,EAAE,aAAa,YAAqB,IAAI,CAAC;IACtE;AACA,WAAO,EAAE,SAAS,OAAO,gBAAgB,YAAY,OAAO,WAAW;EACzE;AACF;AEvtBA,IAAM,aAAa,uBAAO,YAAY;AAEtC,IAAM,0BAA0B;AAGzB,SAAS,wBAAwB,MAAsB;AAC5D,SAAO,KAAK,QAAQ,yBAAyB,EAAE;AACjD;AAMO,SAAS,kBAAkB,MAAoD;AACpF,MAAI,KAAK,WAAW,OAAO,GAAG;AAC5B,UAAM,YAAY,KAAK,YAAY,IAAI;AACvC,QAAI,YAAY,KAAK,YAAY,IAAI,KAAK,QAAQ;AAChD,aAAO,EAAE,MAAM,KAAK,MAAM,YAAY,CAAC,GAAG,WAAW,KAAK,MAAM,GAAG,YAAY,CAAC,EAAE;IACpF;EACF;AACA,SAAO,EAAE,KAAK;AAChB;AAOO,SAAS,qBAAqB,OAAgC;AACnE,WAAS,QAAQ,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;AACzD,UAAM,EAAE,KAAK,IAAI,kBAAkB,MAAM,KAAK,EAAG,IAAI;AACrD,QAAI,SAAS,iBAAiB,SAAS,cAAe,QAAO;EAC/D;AACA,SAAO,MAAM,SAAS;AACxB;AAGO,SAAS,iBAAiB,MAAuB;AACtD,MAAI,OAAO,SAAS,SAAU,QAAO;AACrC,MAAI,QAAQ,OAAO,SAAS,UAAU;AACpC,UAAM,QAAS,KAAiC,OAAO;AACvD,QAAI,OAAO,UAAU,SAAU,QAAO;EACxC;AACA,SAAO;AACT;AAGO,SAAS,gBAAgB,OAAiC;AAC/D,MAAI,OAAO,UAAU,YAAY,CAAC,MAAM,SAAS,QAAQ,EAAG,QAAO,CAAC;AAEpE,QAAM,QAAQ,kBAAkB,KAAK;AACrC,QAAM,QAAyB,CAAC;AAChC,QAAM,SAAS;AACf,MAAI;AACJ,UAAQ,QAAQ,OAAO,KAAK,KAAK,OAAO,MAAM;AAC5C,UAAM,SAAS,IAAI,cAAc,OAAO,OAAO,WAAW,KAAK;AAC/D,UAAM,OAAO,OAAO,WAAW;AAC/B,QAAI,SAAS,YAAY;AACvB,YAAM,KAAK,EAAE,MAAM,MAAM,CAAC,GAAI,KAAK,CAAC;AACpC,aAAO,YAAY,OAAO;IAC5B;EACF;AACA,SAAO;AACT;AAGA,SAAS,kBAAkB,OAAqC;AAC9D,QAAM,QAAQ,oBAAI,IAAqB;AACvC,QAAM,WAAW;AACjB,MAAI;AACJ,UAAQ,QAAQ,SAAS,KAAK,KAAK,OAAO,MAAM;AAC9C,UAAM,SAAS,IAAI,cAAc,OAAO,SAAS,WAAW,KAAK;AACjE,UAAM,QAAQ,OAAO,WAAW;AAChC,QAAI,UAAU,YAAY;AACxB,UAAI,OAAO,UAAU,SAAU,OAAM,IAAI,MAAM,CAAC,GAAI,KAAK;AACzD,eAAS,YAAY,OAAO;IAC9B;EACF;AACA,SAAO;AACT;AAEA,IAAM,iBAAiB;AACvB,IAAM,gBAAgB;AAGtB,IAAM,gBAAN,MAAoB;EAClB;EACiB;EACA;EAEjB,YAAY,KAAa,OAAe,OAA6B;AACnE,SAAK,MAAM;AACX,SAAK,MAAM;AACX,SAAK,QAAQ;EACf;EAEA,aAA0C;AACxC,SAAK,WAAW;AAChB,UAAM,OAAO,KAAK,IAAI,KAAK,GAAG;AAC9B,QAAI,SAAS,OAAW,QAAO;AAC/B,QAAI,SAAS,IAAK,QAAO,KAAK,YAAY;AAC1C,QAAI,SAAS,IAAK,QAAO,KAAK,WAAW;AACzC,QAAI,SAAS,OAAO,SAAS,OAAO,SAAS,IAAK,QAAO,KAAK,YAAY,IAAI;AAC9E,QAAI,SAAS,OAAO,SAAS,OAAQ,QAAQ,OAAO,QAAQ,IAAM,QAAO,KAAK,YAAY;AAC1F,QAAI,eAAe,KAAK,IAAI,EAAG,QAAO,KAAK,qBAAqB;AAChE,WAAO;EACT;EAEQ,cAA2C;AACjD,SAAK;AACL,UAAM,SAAkC,CAAC;AACzC,SAAK,WAAW;AAChB,QAAI,KAAK,IAAI,KAAK,GAAG,MAAM,KAAK;AAC9B,WAAK;AACL,aAAO;IACT;AACA,WAAO,KAAK,MAAM,KAAK,IAAI,QAAQ;AACjC,WAAK,WAAW;AAChB,YAAM,MAAM,KAAK,SAAS;AAC1B,UAAI,QAAQ,WAAY,QAAO;AAC/B,WAAK,WAAW;AAChB,UAAI,KAAK,IAAI,KAAK,GAAG,MAAM,KAAK;AAC9B,aAAK;AACL,cAAM,QAAQ,KAAK,WAAW;AAC9B,YAAI,UAAU,WAAY,QAAO;AACjC,eAAO,GAAG,IAAI;MAChB,OAAO;AACL,eAAO,GAAG,IAAI,KAAK,kBAAkB,GAAG;MAC1C;AACA,WAAK,WAAW;AAChB,YAAM,OAAO,KAAK,IAAI,KAAK,GAAG;AAC9B,UAAI,SAAS,KAAK;AAChB,aAAK;AACL,aAAK,WAAW;AAChB,YAAI,KAAK,IAAI,KAAK,GAAG,MAAM,KAAK;AAC9B,eAAK;AACL,iBAAO;QACT;AACA;MACF;AACA,UAAI,SAAS,KAAK;AAChB,aAAK;AACL,eAAO;MACT;AACA,aAAO;IACT;AACA,WAAO;EACT;EAEQ,aAA0C;AAChD,SAAK;AACL,UAAM,SAAoB,CAAC;AAC3B,SAAK,WAAW;AAChB,QAAI,KAAK,IAAI,KAAK,GAAG,MAAM,KAAK;AAC9B,WAAK;AACL,aAAO;IACT;AACA,WAAO,KAAK,MAAM,KAAK,IAAI,QAAQ;AACjC,YAAM,QAAQ,KAAK,WAAW;AAC9B,UAAI,UAAU,WAAY,QAAO;AACjC,aAAO,KAAK,KAAK;AACjB,WAAK,WAAW;AAChB,YAAM,OAAO,KAAK,IAAI,KAAK,GAAG;AAC9B,UAAI,SAAS,KAAK;AAChB,aAAK;AACL,aAAK,WAAW;AAChB,YAAI,KAAK,IAAI,KAAK,GAAG,MAAM,KAAK;AAC9B,eAAK;AACL,iBAAO;QACT;AACA;MACF;AACA,UAAI,SAAS,KAAK;AAChB,aAAK;AACL,eAAO;MACT;AACA,aAAO;IACT;AACA,WAAO;EACT;EAEQ,WAAuC;AAC7C,UAAM,OAAO,KAAK,IAAI,KAAK,GAAG;AAC9B,QAAI,SAAS,OAAO,SAAS,OAAO,SAAS,KAAK;AAChD,YAAM,QAAQ,KAAK,YAAY,IAAI;AACnC,aAAO,OAAO,UAAU,WAAW,QAAQ;IAC7C;AACA,QAAI,SAAS,UAAa,eAAe,KAAK,IAAI,EAAG,QAAO,KAAK,eAAe;AAChF,WAAO;EACT;EAEQ,YAAY,OAAuB;AACzC,SAAK;AACL,QAAI,MAAM;AACV,WAAO,KAAK,MAAM,KAAK,IAAI,QAAQ;AACjC,YAAM,OAAO,KAAK,IAAI,KAAK,KAAK;AAChC,UAAI,SAAS,MAAM;AACjB,eAAO,KAAK,WAAW;AACvB;MACF;AACA,UAAI,SAAS,MAAO;AACpB,aAAO;IACT;AACA,WAAO;EACT;EAEQ,aAAqB;AAC3B,UAAM,OAAO,KAAK,IAAI,KAAK,KAAK;AAChC,YAAQ,MAAM;MACZ,KAAK;AACH,eAAO;MACT,KAAK;AACH,eAAO;MACT,KAAK;AACH,eAAO;MACT,KAAK;AACH,eAAO;MACT,KAAK;AACH,eAAO;MACT,KAAK;AACH,eAAO;MACT,KAAK;AACH,eAAO;MACT,KAAK,KAAK;AACR,cAAM,MAAM,KAAK,IAAI,MAAM,KAAK,KAAK,KAAK,MAAM,CAAC;AACjD,YAAI,mBAAmB,KAAK,GAAG,GAAG;AAChC,eAAK,OAAO;AACZ,iBAAO,OAAO,aAAa,SAAS,KAAK,EAAE,CAAC;QAC9C;AACA,eAAO;MACT;MACA,KAAK,KAAK;AACR,cAAM,MAAM,KAAK,IAAI,MAAM,KAAK,KAAK,KAAK,MAAM,CAAC;AACjD,YAAI,mBAAmB,KAAK,GAAG,GAAG;AAChC,eAAK,OAAO;AACZ,iBAAO,OAAO,aAAa,SAAS,KAAK,EAAE,CAAC;QAC9C;AACA,eAAO;MACT;MACA;AACE,eAAO,QAAQ;IACnB;EACF;EAEQ,cAA0C;AAChD,UAAM,WAAW;AACjB,aAAS,YAAY,KAAK;AAC1B,UAAM,QAAQ,SAAS,KAAK,KAAK,GAAG;AACpC,QAAI,CAAC,MAAO,QAAO;AACnB,SAAK,OAAO,MAAM,CAAC,EAAE;AACrB,WAAO,OAAO,MAAM,CAAC,CAAC;EACxB;EAEQ,uBAAgC;AACtC,UAAM,OAAO,KAAK,eAAe;AACjC,QAAI,SAAS,OAAQ,QAAO;AAC5B,QAAI,SAAS,QAAS,QAAO;AAC7B,QAAI,SAAS,OAAQ,QAAO;AAC5B,QAAI,SAAS,YAAa,QAAO;AACjC,WAAO,KAAK,kBAAkB,IAAI;EACpC;EAEQ,kBAAkB,MAAuB;AAC/C,WAAO,KAAK,MAAM,IAAI,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,IAAI;EACvD;EAEQ,iBAAyB;AAC/B,UAAM,QAAQ,KAAK;AACnB,WAAO,KAAK,MAAM,KAAK,IAAI,UAAU,cAAc,KAAK,KAAK,IAAI,KAAK,GAAG,CAAE,EAAG,MAAK;AACnF,WAAO,KAAK,IAAI,MAAM,OAAO,KAAK,GAAG;EACvC;EAEQ,aAAmB;AACzB,WAAO,KAAK,MAAM,KAAK,IAAI,QAAQ;AACjC,YAAM,OAAO,KAAK,IAAI,KAAK,GAAG;AAC9B,UAAI,SAAS,OAAO,SAAS,OAAQ,SAAS,QAAQ,SAAS,MAAM;AACnE,aAAK;AACL;MACF;AACA,UAAI,SAAS,OAAO,KAAK,IAAI,KAAK,MAAM,CAAC,MAAM,KAAK;AAClD,cAAM,UAAU,KAAK,IAAI,QAAQ,MAAM,KAAK,MAAM,CAAC;AACnD,aAAK,MAAM,YAAY,KAAK,KAAK,IAAI,SAAS,UAAU;AACxD;MACF;AACA,UAAI,SAAS,OAAO,KAAK,IAAI,KAAK,MAAM,CAAC,MAAM,KAAK;AAClD,cAAM,QAAQ,KAAK,IAAI,QAAQ,MAAM,KAAK,MAAM,CAAC;AACjD,aAAK,MAAM,UAAU,KAAK,KAAK,IAAI,SAAS,QAAQ;AACpD;MACF;AACA;IACF;EACF;AACF;ADjRA,IAAM,wBAAwB;AAC9B,IAAM,uBAAuB;AAC7B,IAAM,gCACJ;AACF,IAAMmB,sBAAqB;AAC3B,IAAM,iBAAiB;AAEhB,SAAS,uBAA+B;AAC7C,SAAO,gBAAgB,cAAc,QAAQ;AAC/C;AAEA,IAAM,8BAA8B;EAClC;EACA;EACA;EACA;EACA;AACF;AAEA,SAAS,2BAA2B,MAAuB;AACzD,QAAM,QAAQ,KAAK,YAAY;AAC/B,SAAO,4BAA4B,KAAK,CAAC,MAAM,MAAM,SAAS,CAAC,CAAC;AAClE;AAEA,IAAM,uBAA+C;EACnD,cAAc;EACd,aAAa;EACb,OAAO;EACP,aAAa;EACb,UAAU;AACZ;AAWA,SAAS,iBAAiB,UAA0B;AAClD,QAAM,OAAOnB,UAAS,UAAU,QAAQ;AACxC,QAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,MAAI,MAAM,UAAU,GAAG;AACrB,WAAO,MAAM,MAAM,EAAE,EAAE,KAAK,GAAG;EACjC;AACA,SAAO;AACT;AAMA,SAASoB,kBAAiB,MAAuC;AAC/D,QAAM,KAAK,OAAO,KAAK,WAAW,KAAK,EAAE,EAAE,KAAK;AAChD,MAAI,CAAC,GAAI,QAAO;AAChB,MAAI;AACF,WAAO,IAAI,KAAK,GAAG,SAAS,GAAG,IAAI,KAAK,GAAG,QAAQ,KAAK,GAAG,IAAI,GAAG,EAAE,QAAQ;EAC9E,QAAQ;AACN,WAAO;EACT;AACF;AAEA,SAAS,iBAAiB,KAA6B;AACrD,SAAO,OAAO,QAAQ,YAAY,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI;AAC9D;AAEA,SAAS,yBAAyB,OAAoD;AACpF,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,OAAO,MAAM,qBAAqB,KAAK,MAAM,yBAAyB,KAAK,CAAC;AACrF;AAEA,SAAS,kBAAkB,OAAgB,OAAoD;AAC7F,SAAO,YAAY,SAAS,OAAO,OAAO,QAAQ;AACpD;AAEA,SAAS,eAAe,MAAwD;AAC9E,SAAO,kBAAkB,KAAK,SAAS,GAAG,SAAS,KAAK,CAAC;AAC3D;AAQA,SAAS,kBAAkB,aAAyD;AAClF,MAAI,YAAY,MAAM,MAAM,eAAgB,QAAO;AACnD,QAAM,UAAU,eAAe,WAAW;AAC1C,QAAM,eAAe,SAAS,QAAQ,eAAe,CAAC,KAAK;AAC3D,QAAM,iBAAiB,SAAS,QAAQ,kBAAkB,CAAC,KAAK;AAChE,QAAM,gBAAgB,SAAS,QAAQ,gBAAgB,CAAC,KAAK;AAC7D,SAAO,EAAE,cAAc,gBAAgB,cAAc;AACvD;AAEA,SAAS,kBAAkB,SAGzB;AACA,QAAM,OAAO,kBAAkB,QAAQ,MAAM,GAAG,kBAAkB;AAClE,SAAO;IACL,YAAY,OACR,kBAAkB,KAAK,mBAAmB,GAAG,+BAA+B,IAC5E;IACJ,WAAW,OACP,kBAAkB,KAAK,kBAAkB,GAAG,8BAA8B,IAC1E;EACN;AACF;AAMA,SAAS,oBACP,MACA,WACkE;AAClE,QAAM,aAAa,qBAAqB,IAAI;AAC5C,MAAI,WAAY,QAAO,EAAE,MAAM,WAAW;AAE1C,QAAM,gBAAgB,OAAO,cAAc,WAAW,UAAU,KAAK,IAAI;AACzE,MAAI,CAAC,cAAe,QAAO,EAAE,MAAM,KAAK;AAExC,QAAM,gBAAgB,cAAc,MAAM,IAAI,EAAE,GAAG,EAAE,KAAK;AAC1D,QAAM,WAAW,KAAK,QAAQ,UAAU,EAAE;AAC1C,MAAI,CAAC,eAAe;AAClB,WAAO;MACL,MAAM,YAAY;MAClB,UAAU,EAAE,MAAM,WAAW,cAAc;IAC7C;EACF;AAEA,SAAO;IACL,MAAM,GAAG,aAAa,IAAI,YAAY,IAAI;IAC1C,UAAU,EAAE,MAAM,WAAW,cAAc;EAC7C;AACF;AAEA,SAASF,wBAAuB,KAAuB;AACrD,MAAI,OAAO,QAAQ,UAAU;AAC3B,QAAI;AACF,aAAO,KAAK,MAAM,GAAG;IACvB,QAAQ;AACN,aAAO;IACT;EACF;AACA,SAAO;AACT;AAEA,SAAS,6BAA6B,UAAkB,OAAyB;AAC/E,MAAI,aAAa,eAAe;AAC9B,WAAO,qBAAqB,KAAK;EACnC;AACA,SAAO;AACT;AAMA,SAAS,kBAAkB,QAAyB;AAClD,MAAI,OAAO,WAAW,SAAU,QAAO;AACvC,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,WAAO,OACJ,IAAI,CAAC,SAAS;AACb,UAAI,OAAO,SAAS,SAAU,QAAO;AACrC,YAAM,SAAS,SAAS,IAAI;AAC5B,aAAO,SAAU,SAAS,OAAO,MAAM,CAAC,KAAK,KAAM;IACrD,CAAC,EACA,KAAK,EAAE;EACZ;AACA,SAAO;AACT;AAEA,SAAS,2BAA2B,SAA0C;AAC5E,QAAM,UAAU,QAAQ,SAAS;AACjC,MAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,WAAO,QACJ,IAAI,CAAC,SAAS;AACb,YAAM,SAAS,SAAS,IAAI;AAC5B,aAAO,UAAU,OAAO,OAAO,MAAM,KAAK,EAAE,MAAM,gBAC9C,OAAO,OAAO,MAAM,KAAK,EAAE,IAC3B;IACN,CAAC,EACA,OAAO,OAAO,EACd,KAAK,IAAI;EACd;AACA,SAAO;AACT;AAaA,IAAM,iBAAiB;AACvB,IAAM,eAAe;AACrB,IAAM,kBAAkB;AACxB,IAAM,mBAAmB;AAEzB,SAAS,qBAAqB,OAA8B;AAC1D,QAAM,OAAO,OAAO,UAAU,WAAW,QAAQ;AACjD,MAAI,CAAC,KAAM,QAAO,CAAC;AAEnB,QAAM,SAAuB,CAAC;AAC9B,QAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,MAAI,UAAU;AACd,MAAI,IAAI;AAER,SAAO,IAAI,MAAM,QAAQ;AACvB,UAAM,OAAO,MAAM,CAAC;AAEpB,QAAI,CAAC,WAAW,eAAe,KAAK,IAAI,GAAG;AACzC,gBAAU;AACV;AACA;IACF;AAEA,QAAI,WAAW,aAAa,KAAK,IAAI,GAAG;AACtC,gBAAU;AACV;AACA;IACF;AAEA,QAAI,SAAS;AACX,YAAM,cAAc,KAAK,MAAM,eAAe;AAC9C,UAAI,aAAa;AACf,cAAM,SAAS,YAAY,CAAC;AAC5B,cAAM,WAAW,YAAY,CAAC,EAAG,KAAK;AACtC;AAEA,YAAI,WAAW,OAAO;AACpB,gBAAM,UAAU,oBAAoB,OAAO,CAAC;AAC5C,cAAI,QAAQ;AACZ,iBAAO,KAAK,EAAE,MAAM,cAAc,MAAM,UAAU,SAAS,QAAQ,KAAK,CAAC;QAC3E,WAAW,WAAW,UAAU;AAE9B,cAAI,eAA8B;AAClC,cAAI,eAAe;AACnB,mBAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,kBAAM,IAAI,MAAM,CAAC;AACjB,gBAAI,CAAC,EAAE,KAAK,EAAG;AACf,kBAAM,YAAY,EAAE,MAAM,gBAAgB;AAC1C,gBAAI,WAAW;AACb,6BAAe,UAAU,CAAC,EAAG,KAAK;AAClC,6BAAe,IAAI;AACnB;YACF;AACA;UACF;AACA,cAAI,cAAc;AAChB,kBAAM,UAAU,oBAAoB,OAAO,YAAY;AACvD,gBAAI,QAAQ;AACZ,mBAAO,KAAK;cACV,MAAM;cACN,MAAM;cACN,YAAY;cACZ,SAAS,QAAQ;YACnB,CAAC;UACH,OAAO;AACL,kBAAM,UAAU,oBAAoB,OAAO,CAAC;AAC5C,gBAAI,QAAQ;AACZ,mBAAO,KAAK,EAAE,MAAM,aAAa,MAAM,UAAU,SAAS,QAAQ,KAAK,CAAC;UAC1E;QACF,WAAW,WAAW,UAAU;AAC9B,iBAAO,KAAK,EAAE,MAAM,eAAe,MAAM,SAAS,CAAC;QAErD;AACA;MACF;IACF;AAEA;EACF;AAEA,SAAO;AACT;AAEA,SAAS,oBACP,OACA,YACyC;AACzC,QAAM,eAAyB,CAAC;AAChC,MAAI,IAAI;AACR,SAAO,IAAI,MAAM,QAAQ;AACvB,UAAM,OAAO,MAAM,CAAC;AAEpB,QAAI,gBAAgB,KAAK,IAAI,KAAK,aAAa,KAAK,IAAI,EAAG;AAC3D,iBAAa,KAAK,IAAI;AACtB;EACF;AACA,SAAO,EAAE,MAAM,aAAa,KAAK,IAAI,GAAG,eAAe,EAAE;AAC3D;AA6BA,SAAS,0BAA0B,MAAyB,OAAkC;AAC5F,QAAM,gBAAgB,gBAAgB,KAAK,MAAM,KAAK,KAAK,OAAO;AAClE,QAAM,iBAAiB,gBAAgB,MAAM,MAAM,MAAM,KAAK,OAAO;AACrE,SAAO,iBAAiB,iBAAiB,KAAK,KAAK,cAAc,MAAM,IAAI;AAC7E;AAEA,SAAS,gBAAgB,UAAkB,UAA0B;AAEnE,QAAM,QAAQlB,UAAS,QAAQ,EAAE,MAAM,iDAAiD;AACxF,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,YAAY,MAAM,CAAC,EAAG,QAAQ,qBAAqB,QAAQ;AACjE,QAAM,SAAS,KAAK,MAAM,SAAS;AACnC,SAAO,OAAO,SAAS,MAAM,IAAI,SAAS;AAC5C;AAMO,IAAM,aAAN,cAAyB,wBAAqC;EAC1D,OAAO;EACP,cAAc;EAEf,WAA0B;EAC1B,oBAAoB,oBAAI,IAAoB;EAC5C;EACA;EACA,gBAAsC;EACtC,wBAAwB,oBAAI,IAAoC;;EAIhE,eAA8B;AACpC,WAAO,cAAcD,OAAK,qBAAqB,GAAG,UAAU,CAAC;EAC/D;EAEA,sBAAsB;AACpB,UAAM,WAAW,qBAAqB;AACtC,WAAO;MACL,QAAQ;MACR,SAAS;QACP,EAAE,MAAMA,OAAK,UAAU,UAAU,EAAE;QACnC,EAAE,MAAMA,OAAK,UAAU,qBAAqB,EAAE;MAChD;IACF;EACF;EAEA,cAAuB;AACrB,SAAK,WAAW,KAAK,aAAa;AAClC,QAAI,CAAC,KAAK,SAAU,QAAO;AAC3B,WAAO,KAAK,iBAAiB,EAAE,SAAS;EAC1C;EAEA,mBAAmB,SAAgD;AACjE,QAAI,CAAC,KAAK,SAAU,QAAO,CAAC;AAC5B,SAAK,iBAAiB;AACtB,WAAO,KAAK,gBAAgB,OAAO,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,OAAO;MAC5D,WAAW,iBAAiB,IAAI;MAChC,YAAY;MACZ,aAAa,KAAK,kBAAkB,MAAM,IAAI;IAChD,EAAE;EACJ;EAEA,kBAAkB,MAA2C;AAC3D,UAAM,kBAAkB,IAAI;AAC5B,SAAK,gBAAgB;AACrB,SAAK,sBAAsB,MAAM;EACnC;;;;;EAMA,wBAAwB,YAAsB,MAAqC;AACjF,QAAI,WAAW,WAAW,EAAG,QAAO;AACpC,UAAM,WAAW,IAAI,KAAK,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,WAAW,IAAI,UAAU,CAAC,CAAC;AACnF,UAAM,WAAW,IAAI,IAAI,UAAU;AACnC,eAAW,MAAM,YAAY;AAC3B,YAAM,aAAa,SAAS,IAAI,EAAE,KAAK,KAAK,eAAe,IAAI,EAAE,GAAG;AACpE,YAAM,aAAa,aAAa,KAAK,eAAe,UAAU,IAAI;AAElE,YAAM,WAAW,aACb,WAAW,iBAAiB,aAC1B,WAAW,iBACX,OACD,KAAK,eAAe,IAAI,EAAE,GAAG,kBAAkB;AACpD,UAAI,CAAC,SAAU;AACf,eAAS,IAAI,QAAQ;AACrB,WAAK,gBAAgB;AACrB,WAAK,sBAAsB,OAAO,QAAQ;IAC5C;AACA,WAAO,CAAC,GAAG,QAAQ;EACrB;EAEQ,eAAe,UAAqC;AAC1D,QAAI;AACF,YAAM,YAAY,KAAK,eAAe,QAAQ,EAC3C,MAAM,IAAI,EACV,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC;AAC5B,UAAI,CAAC,UAAW,QAAO;AACvB,aAAO,kBAAkB,KAAK,MAAM,SAAS,CAAC;IAChD,QAAQ;AACN,aAAO;IACT;EACF;EAEQ,gBAAgB,UAAwC;AAC9D,QAAI,mBAAmB;AACvB,QAAI,oBAAoB;AACxB,QAAI,uBAAuB;AAC3B,QAAI,YAAY;AAChB,QAAI,cAA6B;AAEjC,QAAI,sBAAsB;AAC1B,QAAI,YAAY;AAChB,QAAI,aAAa;AACjB,QAAI,gBAAgB;AACpB,QAAI,kBAAkB;AAEtB,eAAW,QAAQ,mBAAmB,QAAQ,GAAG;AAC/C,UAAI;AACF,cAAM,OAAO,KAAK,MAAM,IAAI;AAC5B,cAAM,aAAa,OAAO,KAAK,MAAM,KAAK,EAAE;AAC5C,cAAM,UAAU,eAAe,IAAI;AAEnC,YAAI,eAAe,kBAAkB,eAAe,gBAAgB;AAClE,gBAAM,YAAY,iBAAiB,QAAQ,OAAO,CAAC;AACnD,cAAI,UAAW,eAAc;AAC7B;QACF;AAEA,YAAI,eAAe,eAAe,OAAO,QAAQ,MAAM,KAAK,EAAE,MAAM,eAAe;AACjF,gBAAM,EAAE,YAAY,UAAU,IAAI,kBAAkB,OAAO;AAC3D,gBAAM,kBAAkB,OAAO,aAAa,cAAc,KAAK,CAAC;AAChE,cAAI,mBAAmB,KAAK,oBAAoB,oBAAqB;AACrE,gCAAsB;AAEtB,cAAI,cAAc;AAClB,cAAI,eAAe;AACnB,cAAI,kBAAkB;AACtB,cAAI,kBAAkB;AAEtB,cAAI,WAAW;AACb,0BAAc,OAAO,UAAU,cAAc,KAAK,CAAC;AACnD,2BAAe,OAAO,UAAU,eAAe,KAAK,CAAC;AACrD,8BAAkB,OAAO,UAAU,yBAAyB,KAAK,CAAC;AAClE,8BAAkB,yBAAyB,SAAS;UACtD,WAAW,YAAY;AACrB,0BAAc,OAAO,WAAW,cAAc,KAAK,CAAC,IAAI;AACxD,2BAAe,OAAO,WAAW,eAAe,KAAK,CAAC,IAAI;AAC1D,8BAAkB,OAAO,WAAW,yBAAyB,KAAK,CAAC,IAAI;AACvE,8BAAkB,yBAAyB,UAAU,IAAI;AACzD,wBAAY,OAAO,WAAW,cAAc,KAAK,CAAC;AAClD,yBAAa,OAAO,WAAW,eAAe,KAAK,CAAC;AACpD,4BAAgB,OAAO,WAAW,yBAAyB,KAAK,CAAC;AACjE,8BAAkB,yBAAyB,UAAU;UACvD;AAEA,gBAAM,aAAa,KAAK,IAAI,GAAG,WAAW;AAC1C,gBAAM,iBAAiB,KAAK,IAAI,GAAG,eAAe;AAClD,8BAAoB;AACpB,+BAAqB,eAAe;AACpC,kCAAwB;AACxB,uBACE,kBAAkB,aAAa;YAC7B,OAAO;YACP,QAAQ;YACR,WAAW,mBAAmB;YAC9B,YAAY,kBAAkB;UAChC,CAAC,KAAK;QACV;MACF,QAAQ;MAER;IACF;AAEA,WAAO;MACL,eAAe;MACf,oBAAoB;MACpB,qBAAqB;MACrB,yBAAyB,wBAAwB;MACjD,YAAY;MACZ,aAAa,YAAY,IAAI,cAAc;IAC7C;EACF;EAEA,eAAe,WAAkC;AAC/C,UAAM,OAAO,KAAK,eAAe,IAAI,SAAS;AAC9C,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,sBAAsB,SAAS,EAAE;AAC5D,QAAI,CAACJ,YAAW,KAAK,UAAU,EAAG,OAAM,IAAI,MAAM,yBAAyB,KAAK,UAAU,EAAE;AAC5F,SAAK,aAAa,KAAK,aAAa;AAEpC,UAAM,aAAa,IAAI,kBAAkB;AAEzC,QAAI,mBAAmB;AACvB,QAAI,oBAAoB;AACxB,QAAI,uBAAuB;AAC3B,QAAI,YAAY;AAEhB,QAAI,cAAkC;AACtC,QAAI,cAA6B,KAAK;AAGtC,QAAI,sBAAsB;AAC1B,QAAI,YAAY;AAChB,QAAI,aAAa;AACjB,QAAI,gBAAgB;AACpB,QAAI,kBAAkB;AAEtB,eAAW,UAAU,cAAc,KAAK,UAAU,GAAG;AACnD,UAAI;AACF,cAAM,aAAa,OAAO,OAAO,MAAM,KAAK,EAAE;AAC9C,YAAI,eAAe,gBAAgB;AACjC,gBAAM,UAAU,eAAe,MAAM;AACrC,wBAAc,iBAAiB,QAAQ,OAAO,CAAC,KAAK;QACtD;AAEA,sBAAc,KAAK,cAAc,QAAQ,YAAY,aAAa,WAAW;AAG7E,YAAI,eAAe,aAAa;AAC9B,gBAAM,UAAU,eAAe,MAAM;AACrC,cAAI,OAAO,QAAQ,MAAM,KAAK,EAAE,MAAM,eAAe;AACnD,kBAAM,EAAE,YAAY,UAAU,IAAI,kBAAkB,OAAO;AAC3D,kBAAM,kBAAkB,OAAO,aAAa,cAAc,KAAK,CAAC;AAEhE,gBAAI,kBAAkB,KAAK,oBAAoB,qBAAqB;YAEpE,OAAO;AACL,oCAAsB;AAEtB,kBAAI,cAAc;AAClB,kBAAI,eAAe;AACnB,kBAAI,kBAAkB;AACtB,kBAAI,kBAAkB;AAEtB,kBAAI,WAAW;AACb,8BAAc,OAAO,UAAU,cAAc,KAAK,CAAC;AACnD,+BAAe,OAAO,UAAU,eAAe,KAAK,CAAC;AACrD,kCAAkB,OAAO,UAAU,yBAAyB,KAAK,CAAC;AAClE,kCAAkB,yBAAyB,SAAS;cACtD,WAAW,kBAAkB,KAAK,YAAY;AAC5C,8BAAc,OAAO,WAAW,cAAc,KAAK,CAAC,IAAI;AACxD,+BAAe,OAAO,WAAW,eAAe,KAAK,CAAC,IAAI;AAC1D,kCACE,OAAO,WAAW,yBAAyB,KAAK,CAAC,IAAI;AACvD,kCAAkB,yBAAyB,UAAU,IAAI;AAEzD,4BAAY,OAAO,WAAW,cAAc,KAAK,CAAC;AAClD,6BAAa,OAAO,WAAW,eAAe,KAAK,CAAC;AACpD,gCAAgB,OAAO,WAAW,yBAAyB,KAAK,CAAC;AACjE,kCAAkB,yBAAyB,UAAU;cACvD;AAEA,oBAAM,aAAa,KAAK,IAAI,GAAG,WAAW;AAC1C,oBAAM,iBAAiB,KAAK,IAAI,GAAG,eAAe;AAClD,kBAAI,cAAc,gBAAgB,iBAAiB;AACjD,oCAAoB;AACpB,qCAAqB,eAAe;AACpC,wCAAwB;AAExB,sBAAM,SAAS;kBACb,OAAO;kBACP,QAAQ;kBACR,WAAW,mBAAmB;kBAC9B,YAAY,kBAAkB;gBAChC;AACA,sBAAM,OAAO,kBAAkB,aAAa,MAAM;AAClD,2BAAW,6BAA6B,QAAQ;kBAC9C,OAAO;kBACP,MAAM,QAAQ;kBACd,YAAY,SAAS,OAAO,SAAY;gBAC1C,CAAC;AACD,6BAAa,QAAQ;cACvB;YACF;UACF;QACF;MACF,QAAQ;MAER;IACF;AAEA,QAAI,YAAa,YAAW,yBAAyB,WAAW;AAChE,UAAM,SAAS,WAAW,OAAO;MAC/B,eAAe;MACf,oBAAoB;MACpB,qBAAqB;MACrB,yBAAyB,wBAAwB;MACjD,YAAY;MACZ,aAAa,YAAY,IAAI,cAAc;IAC7C,CAAC;AAED,SAAK,gBAAgB,OAAO,OAAO,KAAK,EAAE;AAE1C,UAAM,gBAAgB,KAAK,qBAAqB,KAAK,EAAE;AACvD,eAAW,WAAW,eAAe;AACnC,YAAM,cAAc,QAAQ,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,MAAM,GAAG;AACxE,YAAM,iBAAiB,OAAO,SAAS;QACrC,CAAC,aACE,QAAQ,gBAAgB,UAAa,SAAS,gBAAgB,QAAQ,eACtE,SAAS,gBAAgB,UACxB,QAAQ,aAAa,UACrB,gBAAgB,UAChB,SAAS,aAAa,QAAQ,YAC9B,SAAS,MAAM,KAAK,CAAC,SAAS,KAAK,SAAS,UAAU,KAAK,SAAS,WAAW;MACrF;AACA,UAAI,CAAC,eAAgB,QAAO,SAAS,KAAK,OAAO;IACnD;AACA,WAAO,MAAM,gBAAgB,OAAO,SAAS;AAE7C,WAAO;MACL,WAAW,EAAE,WAAW,KAAK,MAAM,WAAW,KAAK,GAAG;MACtD,IAAI,KAAK;MACT,OAAO,KAAK;MACZ,MAAM,SAAS,KAAK,EAAE;MACtB,WAAW,KAAK;MAChB,kBACE,KAAK,kBAAkB,OACnB,SACA,EAAE,WAAW,KAAK,MAAM,WAAW,KAAK,eAAe;MAC7D,cAAc,KAAK;MACnB,cAAc,KAAK;MACnB,OAAO,OAAO;MACd,UAAU,OAAO;IACnB;EACF;;;;;;EAOQ,sBAAqC;AAC3C,QAAI,KAAK,cAAe,QAAO,KAAK;AACpC,SAAK,aAAa,KAAK,aAAa;AACpC,UAAM,QAAuB,EAAE,oBAAoB,oBAAI,IAAI,GAAG,eAAe,oBAAI,IAAI,EAAE;AACvF,eAAW,QAAQ,KAAK,qBAAqB,GAAG;AAC9C,YAAM,aAAa,KAAK,eAAe,IAAI;AAC3C,UAAI,YAAY,iBAAiB,WAAY;AAC7C,YAAM,cAAc,IAAI,IAAI;AAC5B,UAAI,CAAC,WAAW,eAAgB;AAChC,YAAM,QAAQ,MAAM,mBAAmB,IAAI,WAAW,cAAc;AACpE,UAAI,MAAO,OAAM,KAAK,IAAI;UACrB,OAAM,mBAAmB,IAAI,WAAW,gBAAgB,CAAC,IAAI,CAAC;IACrE;AACA,SAAK,gBAAgB;AACrB,WAAO;EACT;EAEQ,gBAAgB,QAA8B,WAAyB;AAC7E,eAAW,SAAS,KAAK,kBAAkB,SAAS,GAAG;AACrD,aAAO,sBAAsB,MAAM,sBAAsB;AACzD,aAAO,uBAAuB,MAAM,uBAAuB;AAC3D,aAAO,cAAc,MAAM,cAAc;AACzC,UAAI,MAAM,yBAAyB;AACjC,eAAO,2BACJ,OAAO,2BAA2B,KAAK,MAAM;MAClD;IACF;EACF;EAEQ,kBAAkB,iBAAiD;AACzE,UAAM,QAAQ,KAAK,kBAAkB,eAAe;AACpD,QAAI,MAAM,WAAW,EAAG,QAAO,CAAC;AAChC,UAAM,SAAS,KAAK,sBAAsB,IAAI,eAAe;AAC7D,QAAI,OAAQ,QAAO;AAEnB,UAAM,QAAQ,MAAM,IAAI,CAAC,SAAS,KAAK,gBAAgB,IAAI,CAAC;AAC5D,SAAK,sBAAsB,IAAI,iBAAiB,KAAK;AACrD,WAAO;EACT;EAEQ,kBAAkB,iBAAmC;AAC3D,WAAO,KAAK,oBAAoB,EAAE,mBAAmB,IAAI,eAAe,KAAK,CAAC;EAChF;EAEQ,qBAAqB,iBAAoC;AAC/D,WAAO,KAAK,kBAAkB,eAAe,EAC1C,QAAQ,CAAC,SAAS;AACjB,YAAM,UAAU,KAAK,uBAAuB,IAAI;AAChD,aAAO,UAAU,CAAC,OAAO,IAAI,CAAC;IAChC,CAAC,EACA,KAAK,CAAC,MAAM,UAAU,KAAK,eAAe,MAAM,YAAY;EACjE;EAEQ,uBAAuB,UAAkC;AAC/D,UAAM,YAAY,iBAAiB,QAAQ;AAC3C,UAAM,aAAa,KAAK,eAAe,QAAQ;AAE/C,QAAI,eAAmC;AACvC,QAAI,cAAkC;AAEtC,eAAW,UAAU,cAAc,QAAQ,GAAG;AAC5C,UAAI;AACF,cAAM,aAAa,OAAO,OAAO,MAAM,KAAK,EAAE;AAC9C,YAAI,eAAe,gBAAiB;AACpC,cAAM,UAAU,eAAe,MAAM;AACrC,YAAI,OAAO,QAAQ,MAAM,KAAK,EAAE,MAAM,UAAW;AACjD,YAAI,OAAO,QAAQ,MAAM,KAAK,EAAE,MAAM,YAAa;AAEnD,cAAM,OAAO,kBAAkB,2BAA2B,OAAO,CAAC;AAClE,YAAI,CAAC,KAAM;AAEX,cAAM,YAAyB;UAC7B,IAAI,SAAS,QAAQ,IAAI,CAAC,KAAK,kBAAkB,SAAS;UAC1D;UACA,aACEyB,kBAAiB,MAAM,KAAKA,kBAAiB,OAAO,KAAKtB,UAAS,QAAQ,EAAE;UAC9E,SACE,OAAO,OAAO,OAAO,KAAK,EAAE,MAAM,kBAClC,OAAO,QAAQ,OAAO,KAAK,EAAE,MAAM;QACvC;AACA,uBAAe;AACf,YAAI,UAAU,QAAS,eAAc;MACvC,QAAQ;MAER;IACF;AAEA,UAAM,WAAW,eAAe;AAChC,QAAI,CAAC,SAAU,QAAO;AAEtB,WAAO;MACL,IAAI,SAAS;MACb,MAAM;MACN,OAAO;MACP,cAAc,SAAS;MACvB,MAAM;MACN,OAAO;MACP,UAAU;MACV,MAAM;MACN,aAAa;MACb,UAAU,YAAY,iBAAiB;MACvC,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,SAAS,MAAM,cAAc,SAAS,YAAY,CAAC;IACnF;EACF;;EAIQ,iBAAiB,SAAiD;AACxE,QAAI,CAAC,KAAK,SAAU,QAAO,CAAC;AAC5B,WAAO,KAAK;MACV,KAAK;MACL,CAAC,UAAU,MAAM,KAAK,SAAS,QAAQ,KAAK,MAAM,KAAK,WAAW,UAAU;MAC5E,EAAE,YAAY,QAAQ;IACxB;EACF;;EAGQ,uBAAiC;AACvC,QAAI,CAAC,KAAK,SAAU,QAAO,CAAC;AAC5B,UAAM,QAAkB,CAAC;AACzB,UAAM,OAAO,CAAC,cAA4B;AACxC,UAAI;AACJ,UAAI;AACF,kBAAUF,aAAY,WAAW,EAAE,eAAe,KAAK,CAAC;MAC1D,QAAQ;AACN;MACF;AACA,iBAAW,SAAS,SAAS;AAC3B,cAAM,WAAWG,OAAK,WAAW,MAAM,IAAI;AAC3C,YAAI,MAAM,YAAY,EAAG,MAAK,QAAQ;iBAC7B,MAAM,KAAK,WAAW,UAAU,KAAK,MAAM,KAAK,SAAS,QAAQ,GAAG;AAC3E,gBAAM,KAAK,QAAQ;QACrB;MACF;IACF;AACA,SAAK,KAAK,QAAQ;AAClB,WAAO;EACT;EAEQ,gBAAgB,SAAiD;AACvE,UAAM,WAAW,KAAK,iBAAiB,OAAO,EAAE,KAAK,yBAAyB;AAC9E,QAAI,SAAS,QAAQ,QAAQ,SAAS,MAAM,KAAM,QAAO;AAEzD,UAAM,EAAE,oBAAoB,cAAc,IAAI,KAAK,oBAAoB;AACvE,UAAM,YAAY,SAAS,OAAO,CAAC,WAAW,CAAC,cAAc,IAAI,OAAO,IAAI,CAAC;AAC7E,UAAM,UAAU,IAAI,IAAI,UAAU,IAAI,CAAC,EAAE,KAAK,MAAM,iBAAiB,IAAI,CAAC,CAAC;AAC3E,QAAI,QAAQ,SAAS,EAAG,QAAO;AAE/B,UAAM,WAAW,IAAI,IAAI,UAAU,IAAI,CAAC,WAAW,CAAC,OAAO,MAAM,MAAM,CAAC,CAAC;AACzE,UAAMW,WAAU,CAAC,GAAG,OAAO;AAC3B,UAAM,cAAc,oBAAI,IAAY;AACpC,WAAOA,SAAQ,SAAS,GAAG;AACzB,YAAM,WAAWA,SAAQ,IAAI;AAC7B,UAAI,YAAY,IAAI,QAAQ,EAAG;AAC/B,kBAAY,IAAI,QAAQ;AACxB,iBAAW,QAAQ,mBAAmB,IAAI,QAAQ,KAAK,CAAC,GAAG;AACzD,YAAI,SAAS,IAAI,IAAI,EAAG;AACxB,YAAI;AACF,mBAAS,IAAI,MAAM,KAAK,kBAAkB,IAAI,CAAC;QACjD,QAAQ;AACN;QACF;AACAA,iBAAQ,KAAK,iBAAiB,IAAI,CAAC;MACrC;IACF;AACA,WAAO,CAAC,GAAG,SAAS,OAAO,CAAC,EAAE,KAAK,yBAAyB;EAC9D;EAEU,sBAAsB,MAAmB,QAAwC;AACzF,UAAM,YAAY,KAAK,oBAAoB;AAC3C,UAAM,aAAa,KAAK,qBAAqB;AAC7C,WAAO,KAAK,qBAAqB;MAC/B;MACA;MACA,aAAa,KAAK,kBAAkB,OAAO,MAAM,OAAO,IAAI;MAC5D,QAAQ;QACN,WAAW,eAAe,OAAO,OAAO;QACxC,cAAc;QACd,kBAAkBS;QAClB,eAAe;QACf,OAAO;QACP,gBAAgB,KAAK,kBAAkB,aAAa;MACtD;IACF,CAAC;EACH;;EAGQ,kBAAkB,MAAc,MAAiD;AACvF,UAAM,YAAY,iBAAiB,IAAI;AACvC,WAAO,KAAK,UAAU;MACpBA;MACA;MACA,KAAK;MACL,KAAK;MACL,KAAK,mBAAmB,SAAS;IACnC,CAAC;EACH;EAEQ,sBAA8B;AACpC,SAAK,qBAAqBpB,OAAK,qBAAqB,GAAG,qBAAqB;AAC5E,WAAO,KAAK;EACd;;EAIQ,mBAAyB;AAC/B,UAAM,YAAY,KAAK,oBAAoB;AAC3C,UAAM,QAAQ,KAAK,gBAAgB,SAAS;AAI5C,QAAI,KAAK,sBAAsB,UAAa,KAAK,sBAAsB,MAAO;AAE9E,QAAI,UAAU,MAAM;AAClB,WAAK,kBAAkB,MAAM;AAC7B,WAAK,oBAAoB;AACzB;IACF;AAEA,QAAI;AACF,YAAM,UAAUF,cAAa,WAAW,OAAO;AAC/C,YAAM,QAAQ,oBAAI,IAAoB;AACtC,iBAAW,UAAU,gBAAgB,OAAO,GAAG;AAC7C,cAAM,MAAM,OAAO,OAAO,IAAI,KAAK,EAAE,EAAE,KAAK;AAC5C,cAAM,aAAa,OAAO,OAAO,aAAa,KAAK,EAAE,EAAE,KAAK;AAC5D,YAAI,OAAO,YAAY;AACrB,gBAAM,IAAI,KAAK,UAAU;QAC3B;MACF;AACA,WAAK,oBAAoB;AACzB,WAAK,oBAAoB;IAC3B,QAAQ;AACN,WAAK,kBAAkB,MAAM;AAC7B,WAAK,oBAAoB;IAC3B;EACF;EAEQ,mBAAmB,WAAkC;AAC3D,WAAO,KAAK,kBAAkB,IAAI,SAAS,KAAK;EAClD;;EAIQ,eAAe,UAAkB,QAAQ,KAAK,MAAc;AAClE,UAAM,KAAKO,UAAS,UAAU,GAAG;AACjC,QAAI;AACF,YAAM,SAAS,OAAO,MAAM,KAAK;AACjC,YAAM,YAAYC,UAAS,IAAI,QAAQ,GAAG,OAAO,CAAC;AAClD,aAAO,OAAO,SAAS,GAAG,SAAS,EAAE,SAAS,OAAO;IACvD,UAAA;AACEF,iBAAU,EAAE;IACd;EACF;EAEU,qBAAqB,UAAkB,SAAgD;AAC/F,SAAK,iBAAiB;AACtB,UAAM,OAAO,KAAK,iBAAiB,UAAU,OAAO;AACpD,QAAI,KAAM,MAAK,gBAAgB,KAAK,OAAO,KAAK,EAAE;AAClD,WAAO;EACT;EAEQ,iBAAiB,UAAkB,SAAgD;AACzF,WAAO,iBAAiB,KAAK,uBAAuB,UAAU,OAAO,CAAC;EACxE;EAEQ,uBACN,UACA,SACiC;AACjC,QAAI,SAAS,MAAM;AACjB,aAAO,KAAK,2BAA2B,QAAQ;IACjD;AAEA,UAAM,YAAY,iBAAiB,QAAQ;AAE3C,QAAI,eAAwC,CAAC;AAC7C,QAAI,iBAAgC;AACpC,QAAI,YAAY;AAChB,QAAI,YAAY;AAChB,QAAI,eAA8B;AAIlC,QAAI,YAAY;AAChB,QAAI,eAAe;AACnB,QAAI,QAAuB;AAC3B,QAAI,cAA6B;AACjC,UAAM,gBAAwC,CAAC;AAC/C,QAAI,mBAAmB;AACvB,QAAI,oBAAoB;AACxB,QAAI,uBAAuB;AAC3B,QAAI,YAAY;AAEhB,QAAI,0BAA0B;AAC9B,QAAI,gBAAgB;AACpB,QAAI,iBAAiB;AACrB,QAAI,oBAAoB;AACxB,QAAI,sBAAsB;AAE1B,UAAM,gBAAgB,oBAAI,IAAI,CAAC,WAAW,iBAAiB,sBAAsB,CAAC;AAElF,QAAI,uBAAuB;AAE3B,eAAW,QAAQ,mBAAmB,QAAQ,GAAG;AAC/C,mBAAa;AACb,UAAI,cAAc,GAAG;AACnB,YAAI;AACJ,YAAI;AACF,wBAAc,KAAK,MAAM,IAAI;QAC/B,QAAQ;AACN,iBAAO,eAAe,wBAAwB;QAChD;AACA,uBAAe,eAAe,WAAW;AACzC,cAAM,aAAa,kBAAkB,WAAW;AAChD,yBAAiB,YAAY,iBAAiB,aAAa,WAAW,iBAAiB;AACvF,oBACEiB,kBAAiB,WAAW,KAC5BA,kBAAiB,YAAY,KAC7BtB,UAAS,QAAQ,EAAE;AACrB,oBAAY;MACd;AAEA,UAAI;AACF,cAAM,OAAO,KAAK,MAAM,IAAI;AAC5B,cAAM,aAAa,OAAO,KAAK,MAAM,KAAK,EAAE;AAC5C,cAAM,UAAU,eAAe,IAAI;AACnC,cAAM,cAAc,OAAO,QAAQ,MAAM,KAAK,EAAE;AAChD,YAAIa,qBAAoB,UAAU,KAAKA,qBAAoB,WAAW,EAAG;AACzE,+BAAuB;AACvB,cAAM,WAAWS,kBAAiB,IAAI,KAAKA,kBAAiB,OAAO;AACnE,YAAI,WAAW,UAAW,aAAY;AAItC,YAAI,iBAAiB,QAAQ,aAAa,IAAI;AAC5C,gBAAM,YAAY,KAAK,wBAAwB,IAAI;AACnD,cAAI,UAAW,gBAAe;QAChC;AAEA,YAAI,eAAe,kBAAkB,eAAe,gBAAgB;AAClE,gBAAM,YAAY,iBAAiB,QAAQ,OAAO,CAAC;AACnD,cAAI,WAAW;AACb,0BAAc;AACd,sBAAU;UACZ;AACA;QACF;AAEA,YAAI,eAAe,iBAAiB;AAClC,gBAAM,IAAI;AACV,gBAAM,QAAQ,OAAO,EAAE,MAAM,KAAK,EAAE;AACpC,cAAI,cAAc,IAAI,KAAK,GAAG;AAC5B;UACF;AAEA,gBAAM,OAAO,kBAAkB,EAAE,MAAM,GAAG,oBAAoB;AAC9D,gBAAM,IAAI,OAAO,OAAO,KAAK,EAAE,OAAO;AACtC,cAAI,OAAO,MAAM,YAAY,EAAE,KAAK,GAAG;AACrC,0BAAc,EAAE,KAAK;AACrB,sBAAU;UACZ;QACF;AAEA,YAAI,eAAe,aAAa;AAC9B,cAAI,OAAO,QAAQ,MAAM,KAAK,EAAE,MAAM,eAAe;AACnD,kBAAM,EAAE,YAAY,UAAU,IAAI,kBAAkB,OAAO;AAC3D,kBAAM,kBAAkB,OAAO,aAAa,cAAc,KAAK,CAAC;AAEhE,gBAAI,kBAAkB,KAAK,oBAAoB,yBAAyB;AACtE,wCAA0B;AAE1B,kBAAI,cAAc;AAClB,kBAAI,eAAe;AACnB,kBAAI,kBAAkB;AACtB,kBAAI,kBAAkB;AAEtB,kBAAI,WAAW;AACb,8BAAc,OAAO,UAAU,cAAc,KAAK,CAAC;AACnD,+BAAe,OAAO,UAAU,eAAe,KAAK,CAAC;AACrD,kCAAkB,OAAO,UAAU,yBAAyB,KAAK,CAAC;AAClE,kCAAkB,yBAAyB,SAAS;cACtD,WAAW,kBAAkB,KAAK,YAAY;AAC5C,8BAAc,OAAO,WAAW,cAAc,KAAK,CAAC,IAAI;AACxD,+BAAe,OAAO,WAAW,eAAe,KAAK,CAAC,IAAI;AAC1D,kCACE,OAAO,WAAW,yBAAyB,KAAK,CAAC,IAAI;AACvD,kCAAkB,yBAAyB,UAAU,IAAI;AAEzD,gCAAgB,OAAO,WAAW,cAAc,KAAK,CAAC;AACtD,iCAAiB,OAAO,WAAW,eAAe,KAAK,CAAC;AACxD,oCAAoB,OAAO,WAAW,yBAAyB,KAAK,CAAC;AACrE,sCAAsB,yBAAyB,UAAU;cAC3D;AAEA,oBAAM,aAAa,KAAK,IAAI,GAAG,WAAW;AAC1C,oBAAM,iBAAiB,KAAK,IAAI,GAAG,eAAe;AAClD,kCAAoB;AACpB,mCAAqB,eAAe;AACpC,sCAAwB;AACxB,oBAAM,gBAAgB,aAAa,eAAe;AAClD,kBAAI,eAAe,gBAAgB,GAAG;AACpC,8BAAc,WAAW,KAAK,cAAc,WAAW,KAAK,KAAK;cACnE;AACA,oBAAM,OAAO,kBAAkB,aAAa;gBAC1C,OAAO;gBACP,QAAQ;gBACR,WAAW,mBAAmB;gBAC9B,YAAY,kBAAkB;cAChC,CAAC;AACD,kBAAI,SAAS,KAAM,cAAa;YAClC;UACF;QACF;MACF,QAAQ;MAER;IACF;AAEA,QAAI,cAAc,EAAG,QAAO,eAAe,YAAY;AACvD,QAAI,CAAC,qBAAsB,QAAO,gBAAgB,sBAAsB;AAExE,UAAM,aAAa,KAAK,mBAAmB,SAAS;AACpD,UAAM,YAAY,aAAa,KAAK,IAAI,OAAO,aAAa,KAAK,CAAC,IAAI;AACtE,UAAM,QAAQ,oBAAoB,YAAY,cAAc,cAAc,aAAa,IAAI,CAAC;AAE5F,WAAO,cAAc;MACnB,IAAI;MACJ,MAAM,SAAS,SAAS;MACxB;MACA;MACA,kBACE,kBAAkB,OAAO,SAAY,EAAE,WAAW,KAAK,MAAM,WAAW,eAAe;MACzF,cAAc;MACd,cAAc;MACd,OAAO;QACL,eAAe;QACf,oBAAoB;QACpB,qBAAqB;QACrB,yBAAyB,wBAAwB;QACjD,YAAY;QACZ,aAAa,YAAY,IAAI,cAAc;MAC7C;MACA,aAAa,OAAO,KAAK,aAAa,EAAE,SAAS,IAAI,gBAAgB;IACvE,CAAC;EACH;EAEQ,2BAA2B,UAAmD;AACpF,UAAM,SAAS,KAAK,eAAe,QAAQ;AAC3C,UAAM,QAAQ,OAAO,MAAM,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC;AACvD,QAAI,MAAM,WAAW,EAAG,QAAO,eAAe,YAAY;AAE1D,UAAM,YAAY,iBAAiB,QAAQ;AAE3C,QAAI;AACJ,QAAI;AACF,oBAAc,KAAK,MAAM,MAAM,CAAC,CAAE;IACpC,QAAQ;AACN,aAAO,eAAe,wBAAwB;IAChD;AAEA,UAAM,aAAa,kBAAkB,WAAW;AAChD,UAAM,iBACJ,YAAY,iBAAiB,aAAa,WAAW,iBAAiB;AAExE,UAAM,UAAU,eAAe,WAAW;AAC1C,UAAM,OAAOtB,UAAS,QAAQ;AAC9B,UAAM,YAAYsB,kBAAiB,WAAW,KAAKA,kBAAiB,OAAO,KAAK,KAAK;AACrF,UAAM,aAAa,KAAK,mBAAmB,SAAS;AACpD,UAAM,eAAe,KAAK,sBAAsB,KAAK;AACrD,UAAM,YAAY,QAAQ,KAAK,IAAI,OAAO,QAAQ,KAAK,CAAC,IAAI;AAC5D,UAAM,iBAAiB,cAAc,aAAa,IAAI;AACtD,UAAM,QAAQ,oBAAoB,YAAY,cAAc,cAAc;AAE1E,WAAO,cAAc;MACnB,IAAI;MACJ,MAAM,SAAS,SAAS;MACxB;MACA;MACA,kBACE,kBAAkB,OAAO,SAAY,EAAE,WAAW,KAAK,MAAM,WAAW,eAAe;MACzF,cAAc;MACd,cAAc,KAAK;MACnB,OAAO;QACL,eAAe;QACf,oBAAoB;QACpB,qBAAqB;QACrB,YAAY;MACd;IACF,CAAC;EACH;;EAGQ,sBAAsB,OAAgC;AAC5D,eAAW,QAAQ,MAAM,MAAM,GAAG,EAAE,GAAG;AACrC,UAAI;AACF,cAAM,QAAQ,KAAK,wBAAwB,KAAK,MAAM,IAAI,CAAC;AAC3D,YAAI,MAAO,QAAO;MACpB,QAAQ;MAER;IACF;AACA,WAAO;EACT;;;;;;EAOQ,wBAAwB,MAA8C;AAC5E,UAAM,aAAa,OAAO,KAAK,MAAM,KAAK,EAAE;AAC5C,QAAI,eAAe,mBAAmBT,qBAAoB,UAAU,EAAG,QAAO;AAE9E,UAAM,UAAU,eAAe,IAAI;AACnC,UAAM,QAAQ,OAAO,QAAQ,MAAM,KAAK,EAAE;AAC1C,QAAI,UAAU,aAAaA,qBAAoB,KAAK,EAAG,QAAO;AAC9D,QAAI,OAAO,QAAQ,MAAM,KAAK,EAAE,MAAM,OAAQ,QAAO;AAErD,UAAM,UAAU,QAAQ,SAAS;AACjC,QAAI,OAAsB;AAC1B,QAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,aAAO,QACJ,IAAI,CAAC,SAAS;AACb,cAAM,SAAS,SAAS,IAAI;AAC5B,eAAO,SAAS,OAAO,OAAO,MAAM,KAAK,EAAE,IAAI;MACjD,CAAC,EACA,KAAK,GAAG;IACb,WAAW,OAAO,YAAY,UAAU;AACtC,aAAO;IACT;AACA,QAAI,CAAC,QAAQ,2BAA2B,IAAI,EAAG,QAAO;AACtD,WAAO,mBAAmB,IAAI,KAAK;EACrC;;EAIQ,cACN,MACA,YACA,aACA,aACoB;AACpB,UAAM,aAAa,OAAO,KAAK,MAAM,KAAK,EAAE;AAC5C,QAAIA,qBAAoB,UAAU,EAAG,QAAO;AAE5C,QAAI,eAAe,kBAAkB,eAAe,aAAa;AAC/D,aAAO;IACT;AAEA,QAAI,eAAe,gBAAiB,QAAO;AAE3C,UAAM,UAAU,eAAe,IAAI;AACnC,UAAM,cAAc,OAAO,QAAQ,MAAM,KAAK,EAAE;AAChD,QAAIA,qBAAoB,WAAW,EAAG,QAAO;AAC7C,UAAM,cAAcS,kBAAiB,IAAI,KAAKA,kBAAiB,OAAO;AAEtE,YAAQ,aAAa;MACnB,KAAK,WAAW;AACd,cAAM,OAAO,OAAO,QAAQ,MAAM,KAAK,EAAE;AACzC,YAAI,SAAS,aAAa;AACxB,iBAAO,KAAK;YACV;YACA;YACA;YACA;YACA;UACF;QACF;AACA,YAAI,SAAS,QAAQ;AACnB,iBAAO,KAAK,mBAAmB,SAAS,YAAY,aAAa,WAAW;QAC9E;AACA;MACF;MAEA,KAAK;AACH,aAAK,iBAAiB,SAAS,YAAY,aAAa,WAAW;AACnE,eAAO;MAET,KAAK;AACH,aAAK,oBAAoB,SAAS,YAAY,aAAa,WAAW;AACtE,eAAO;MAET,KAAK;AACH,aAAK,sBAAsB,SAAS,YAAY,WAAW;AAC3D,eAAO;MAET,KAAK;AACH,aAAK,sBAAsB,SAAS,YAAY,aAAa,WAAW;AACxE,eAAO;MAET,KAAK;AACH,aAAK,sBAAsB,SAAS,YAAY,WAAW;AAC3D,eAAO;IACX;AAEA,WAAO;EACT;;EAIQ,wBACN,SACA,YACA,aACA,aACA,aACoB;AACpB,UAAM,WAAW,2BAA2B,OAAO;AACnD,QAAI,CAAC,SAAU,QAAO;AAEtB,UAAM,YAAY,SAAS,MAAM,qBAAqB;AACtD,QAAI,WAAW;AACb,YAAMC,YAAW,UAAU,CAAC,EAAG,KAAK;AACpC,YAAM,WAAwB;QAC5B,MAAM;QACN,MAAMA;QACN,iBAAiB;QACjB,cAAc;MAChB;AACA,oBAAc;IAChB;AAEA,UAAM,cAAc,kBAAkB,SAAS,QAAQ,uBAAuB,EAAE,CAAC;AACjF,QAAI,CAAC,YAAa,QAAO;AAEzB,UAAM,WAAwB,EAAE,MAAM,QAAQ,MAAM,aAAa,cAAc,YAAY;AAC3F,eAAW,oBAAoB,UAAU;MACvC,IAAI;MACJ;MACA,OAAO;MACP,OAAO;IACT,CAAC;AACD,WAAO;EACT;;EAIQ,mBACN,SACA,YACA,aACA,aACoB;AACpB,UAAM,UAAU,QAAQ,SAAS;AACjC,UAAM,OAAO,MAAM,QAAQ,OAAO,IAC9B,QACG,IAAI,CAAC,MAAM;AACV,UAAI,MAAM,QAAQ,CAAC,EAAG,QAAO;AAC7B,YAAM,SAAS,SAAS,CAAC;AACzB,aAAO,SAAS,OAAO,OAAO,MAAM,KAAK,EAAE,IAAI,OAAO,KAAK,EAAE;IAC/D,CAAC,EACA,KAAK,GAAG,IACX,OAAO,WAAW,EAAE;AAExB,UAAM,cAAc,kBAAkB,IAAI;AAC1C,QAAI,CAAC,YAAa,QAAO;AAEzB,QAAI,2BAA2B,WAAW,EAAG,QAAO;AAEpD,QAAI,YAAY,UAAU,EAAE,WAAW,oBAAoB,GAAG;AAC5D,UAAI,YAAa,YAAW,yBAAyB,WAAW;AAChE,iBAAW,cAAc;QACvB,IAAI;QACJ,MAAM;QACN;QACA,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,aAAa,cAAc,YAAY,CAAC;MACxE,CAAC;AACD,aAAO;IACT;AAEA,UAAM,gBAAgB,YAAY,MAAM,6BAA6B;AACrE,QAAI,eAAe;AAGjB,UAAI;AACJ,UAAI;AACF,uBAAe,SAAS,KAAK,MAAM,cAAc,CAAC,CAAE,CAAC;MACvD,QAAQ;AACN,uBAAe;MACjB;AAEA,UAAI,cAAc;AAChB,cAAM,UAAU,OAAO,aAAa,UAAU,KAAK,EAAE;AACrD,cAAM,WAAW,OAAO,aAAa,UAAU,KAAK,EAAE;AACtD,cAAM,gBAAgB,OAAO,aAAa,WAAW,KAAK,EAAE;AAE5D,cAAM,WAAwB;UAC5B,MAAM;UACN,MAAM,iBAAiB,YAAY,QAAQ;UAC3C,cAAc;QAChB;AAEA,mBAAW,cAAc;UACvB,IAAI;UACJ,MAAM;UACN;UACA,OAAO,CAAC,QAAQ;UAChB,OAAO;UACP,YAAY,WAAW;UACvB,UAAU,YAAY;QACxB,CAAC;AACD,mBAAW,UAAU;AACrB,eAAO;MACT;IACF;AAEA,eAAW,cAAc;MACvB,IAAI;MACJ,MAAM;MACN;MACA,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,aAAa,cAAc,YAAY,CAAC;IACxE,CAAC;AACD,WAAO;EACT;;EAIQ,iBACN,SACA,YACA,aACA,aACM;AACN,UAAM,UAAU,QAAQ,SAAS;AACjC,QAAI,CAAC,MAAM,QAAQ,OAAO,EAAG;AAE7B,UAAM,QAAkB,CAAC;AACzB,eAAW,QAAQ,SAAS;AAC1B,YAAM,KAAK,SAAS,IAAI;AACxB,UAAI,CAAC,GAAI;AACT,UAAI,OAAO,GAAG,MAAM,KAAK,EAAE,MAAM,gBAAgB;AAC/C,cAAM,OAAO,OAAO,GAAG,MAAM,KAAK,EAAE;AACpC,YAAI,KAAK,KAAK,EAAG,OAAM,KAAK,IAAI;MAClC;IACF;AAEA,QAAI,MAAM,WAAW,EAAG;AAExB,UAAM,gBAAgB,MAAM,KAAK,IAAI;AACrC,UAAM,OAAoB,EAAE,MAAM,aAAa,MAAM,eAAe,cAAc,YAAY;AAC9F,eAAW;MACT;MACA;QACE,IAAI;QACJ;QACA,OAAO;QACP,OAAO;MACT;MACA,EAAE,iBAAiB,KAAK;IAC1B;EACF;;EAIQ,oBACN,SACA,YACA,aACA,aACM;AACN,UAAM,SAAS,OAAO,QAAQ,SAAS,KAAK,EAAE,EAAE,KAAK;AACrD,UAAM,OAAO,OAAO,QAAQ,MAAM,KAAK,EAAE,EAAE,KAAK;AAChD,QAAI,CAAC,KAAM;AAEX,UAAM,eAAe,oBAAoB,MAAM,QAAQ,WAAW,CAAC;AACnE,UAAM,aAAaH,wBAAuB,QAAQ,WAAW,CAAC;AAE9D,UAAML,YAAwB;MAC5B,MAAM;MACN,MAAM,aAAa;MACnB,QAAQ;MACR,OAAO,SAAS,aAAa,IAAI;MACjC,OAAO;QACL,QAAQ;QACR,OAAO;QACP,QAAQ;QACR,UAAU,aAAa;MACzB;MACA,cAAc;IAChB;AAEA,eAAW;MACTA;MACA,EAAE,IAAI,IAAI,aAAa,OAAO,SAAS,OAAO,YAAY;MAC1D,EAAE,gBAAgB,KAAK;IACzB;EACF;;EAIQ,sBACN,SACA,YACA,aACM;AACN,UAAM,SAAS,OAAO,QAAQ,SAAS,KAAK,EAAE,EAAE,KAAK;AACrD,QAAI,CAAC,OAAQ;AAEb,UAAM,aAAa;MACjB,wBAAwB,kBAAkB,QAAQ,QAAQ,CAAC,CAAC;IAC9D;AACA,UAAM,cAA6B,aAC/B,CAAC,EAAE,MAAM,QAAQ,MAAM,YAAY,cAAc,YAAY,CAAC,IAC9D,CAAC;AAEL,QAAI,YAAY,SAAS,GAAG;AAC1B,iBAAW,gBAAgB,QAAQ,EAAE,QAAQ,aAAa,QAAQ,YAAY,CAAC;IACjF;EACF;;EAIQ,sBACN,SACA,YACA,aACA,aACM;AACN,UAAM,SAAS,OAAO,QAAQ,SAAS,KAAK,EAAE,EAAE,KAAK;AACrD,UAAM,OAAO,OAAO,QAAQ,MAAM,KAAK,EAAE,EAAE,KAAK;AAChD,QAAI,CAAC,KAAM;AAKX,QAAI,SAAS,QAAQ;AACnB,YAAM,UAAU,gBAAgB,QAAQ,OAAO,CAAC;AAChD,UAAI,QAAQ,SAAS,GAAG;AACtB,aAAK,uBAAuB,SAAS,QAAQ,YAAY,aAAa,WAAW;AACjF;MACF;IACF;AAEA,UAAM,eAAe,oBAAoB,MAAM,QAAQ,WAAW,CAAC;AACnE,UAAM,WAAW,QAAQ,OAAO;AAChC,UAAM,kBAAkB,6BAA6B,MAAM,QAAQ;AAEnE,UAAMA,YAAwB;MAC5B,MAAM;MACN,MAAM,aAAa;MACnB,QAAQ;MACR,OAAO,SAAS,aAAa,IAAI;MACjC,OAAO;QACL,QAAQ;QACR,OAAO;QACP,QAAQ;QACR,UAAU,aAAa;MACzB;MACA,cAAc;IAChB;AAEA,eAAW;MACTA;MACA,EAAE,IAAI,IAAI,aAAa,OAAO,SAAS,OAAO,YAAY;MAC1D,EAAE,gBAAgB,KAAK;IACzB;EACF;;EAIQ,uBACN,OACA,QACA,YACA,aACA,aACM;AAIN,UAAM,cAAc,qBAAqB,KAAK;AAC9C,UAAM,QAAQ,CAAC,MAAM,UAAU;AAC7B,YAAM,aAAa,UAAU,cAAc,SAAS,GAAG,MAAM,IAAI,KAAK;AACtE,WAAK,sBAAsB,MAAM,YAAY,YAAY,aAAa,WAAW;IACnF,CAAC;EACH;EAEQ,sBACN,MACA,QACA,YACA,aACA,aACM;AACN,UAAM,EAAE,MAAM,UAAU,IAAI,kBAAkB,KAAK,IAAI;AACvD,UAAM,eAAe,oBAAoB,MAAM,SAAS;AACxD,UAAM,aACJ,SAAS,gBAAgB,qBAAqB,iBAAiB,KAAK,IAAI,CAAC,IAAI,KAAK;AAEpF,UAAMA,YAAwB;MAC5B,MAAM;MACN,MAAM,aAAa;MACnB,QAAQ;MACR,OAAO,SAAS,aAAa,IAAI;MACjC,OAAO;QACL,QAAQ;QACR,OAAO;QACP,QAAQ;QACR,UAAU,aAAa;MACzB;MACA,cAAc;IAChB;AAEA,eAAW;MACTA;MACA,EAAE,IAAI,IAAI,aAAa,OAAO,SAAS,OAAO,YAAY;MAC1D,EAAE,gBAAgB,KAAK;IACzB;EACF;AACF;AG9jDA,IAAM,aAAN,MAAiB;EACP,cAA4B,CAAC;EAC7B,cAA4B,CAAC;EAC7B,UAAU;EAElB,SAAS;AACP,SAAK,UAAU;EACjB;EAEA,MAAM,MAA0B;AAC9B,UAAM,SAAqB;MACzB;MACA,WAAW,YAAY,IAAI;MAC3B,UAAU,CAAC;IACb;AAEA,QAAI,CAAC,KAAK,QAAS,QAAO;AAE1B,UAAM,SAAS,KAAK,YAAY,KAAK,YAAY,SAAS,CAAC;AAC3D,QAAI,QAAQ;AACV,aAAO,SAAS;AAChB,aAAO,SAAS,KAAK,MAAM;IAC7B,OAAO;AACL,WAAK,YAAY,KAAK,MAAM;IAC9B;AAEA,SAAK,YAAY,KAAK,MAAM;AAC5B,WAAO;EACT;EAEA,IAAI,QAA2B;AAC7B,QAAI,CAAC,KAAK,QAAS;AAEnB,UAAM,SAAS,UAAU,KAAK,YAAY,KAAK,YAAY,SAAS,CAAC;AACrE,QAAI,CAAC,OAAQ;AAEb,WAAO,UAAU,YAAY,IAAI;AACjC,WAAO,WAAW,OAAO,UAAU,OAAO;AAG1C,WAAO,KAAK,YAAY,SAAS,GAAG;AAClC,YAAM,SAAS,KAAK,YAAY,IAAI;AACpC,UAAI,WAAW,OAAQ;IACzB;EACF;EAEA,QAAW,MAAc,IAAgB;AACvC,UAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,QAAI;AACF,aAAO,GAAG;IACZ,UAAA;AACE,WAAK,IAAI,MAAM;IACjB;EACF;EAEA,MAAM,aAAgB,MAAc,IAAkC;AACpE,UAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,QAAI;AACF,aAAO,MAAM,GAAG;IAClB,UAAA;AACE,WAAK,IAAI,MAAM;IACjB;EACF;EAEA,YAAoB;AAClB,QAAI,CAAC,KAAK,QAAS,QAAO;AAE1B,UAAM,QAAkB,CAAC;AACzB,UAAM,KAAK,gCAAgC;AAE3C,eAAW,UAAU,KAAK,aAAa;AACrC,WAAK,aAAa,QAAQ,GAAG,KAAK;IACpC;AAEA,WAAO,MAAM,KAAK,IAAI;EACxB;EAEQ,aAAa,QAAoB,OAAe,OAAuB;AAC7E,UAAM,SAAS,KAAK,OAAO,KAAK;AAChC,UAAM,WAAW,OAAO,UAAU,QAAQ,CAAC,KAAK;AAChD,UAAM,KAAK,GAAG,MAAM,GAAG,OAAO,IAAI,KAAK,QAAQ,IAAI;AAEnD,eAAW,SAAS,OAAO,UAAU;AACnC,WAAK,aAAa,OAAO,QAAQ,GAAG,KAAK;IAC3C;EACF;EAEA,QAAc;AACZ,SAAK,cAAc,CAAC;AACpB,SAAK,cAAc,CAAC;EACtB;AACF;AAEO,IAAM,OAAO,IAAI,WAAW;AD7D5B,SAAS,wBAAuC;AACrD,QAAM,WAAW,YAAY,kBAAkB;AAC/C,MAAI,SAAU,QAAO;AAErB,QAAM,kBAAkBP,UAAS;AACjC,MAAI,oBAAoB,UAAU;AAChC,WAAO,cAAcP,OAAKG,SAAQ,GAAG,WAAW,uBAAuB,UAAU,MAAM,CAAC;EAC1F;AACA,MAAI,oBAAoB,SAAS;AAC/B,UAAM,aAAa,YAAY,iBAAiB,KAAKH,OAAKG,SAAQ,GAAG,SAAS;AAC9E,WAAO,cAAcH,OAAK,YAAY,UAAU,MAAM,CAAC;EACzD;AACA,MAAI,oBAAoB,SAAS;AAC/B,UAAM,UAAU,YAAY,SAAS,KAAKA,OAAKG,SAAQ,GAAG,WAAW,SAAS;AAC9E,WAAO,cAAcH,OAAK,SAAS,UAAU,MAAM,CAAC;EACtD;AACA,SAAO;AACT;AA+FA,SAAS,aAAa,OAAe,OAAoC;AACvE,SAAO,YAAY,UAAU,OAAO,OAAO,QAAQ;AACrD;AAEA,SAAS,aAAa,OAAe,OAAoC;AACvE,SAAO,YAAY,UAAU,OAAO,OAAO,QAAQ;AACrD;AAEA,SAAS,mBAAmB,OAA4C;AACtE,QAAM,MAAM,QAAQ,KAAK;AACzB,MAAI,QAAQ,OAAW,QAAO;AAC9B,QAAM,QAAwB,CAAC;AAC/B,aAAW,QAAQ,KAAK;AACtB,UAAM,SAAS,SAAS,IAAI;AAC5B,QAAI,CAAC,OAAQ;AACb,UAAM,KAAK;MACT,IAAI,aAAa,mBAAmB,OAAO,EAAE;MAC7C,YAAY,aAAa,2BAA2B,OAAO,UAAU;MACrE,OAAO,aAAa,sBAAsB,OAAO,KAAK;MACtD,UAAU,aAAa,yBAAyB,OAAO,QAAQ;IACjE,CAAC;EACH;AACA,SAAO;AACT;AAEA,SAAS,kBAAkB,OAA2C;AACpE,QAAM,MAAM,QAAQ,KAAK;AACzB,MAAI,QAAQ,OAAW,QAAO;AAC9B,QAAM,WAA0B,CAAC;AACjC,aAAW,QAAQ,KAAK;AACtB,UAAM,SAAS,SAAS,IAAI;AAC5B,QAAI,CAAC,OAAQ;AACb,UAAM,OAAO,aAAa,oBAAoB,OAAO,IAAI;AACzD,QAAI,SAAS,OAAW;AACxB,aAAS,KAAK,EAAE,GAAG,QAAQ,MAAM,MAAM,aAAa,oBAAoB,OAAO,IAAI,EAAE,CAAC;EACxF;AACA,SAAO;AACT;AAGA,SAAS,iBAAiB,OAAoC;AAC5D,QAAM,SAAS,oBAAoB,KAAK;AACxC,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,cAAc,SAAS,OAAO,WAAW;AAE/C,SAAO;IACL,IAAI,aAAa,eAAe,OAAO,EAAE;IACzC,YAAY,aAAa,uBAAuB,OAAO,UAAU;IACjE,MAAM,aAAa,iBAAiB,OAAO,IAAI;IAC/C,MAAM,aAAa,iBAAiB,OAAO,IAAI;IAC/C,OAAO,aAAa,kBAAkB,OAAO,KAAK;IAClD,WAAW,aAAa,sBAAsB,OAAO,SAAS;IAC9D,WAAW,aAAa,sBAAsB,OAAO,SAAS;IAC9D,cAAc,aAAa,yBAAyB,OAAO,YAAY;IACvE,eAAe,aAAa,0BAA0B,OAAO,aAAa;IAC1E,OAAO,aAAa,kBAAkB,OAAO,KAAK;IAClD,aAAa,cACT,EAAE,WAAW,aAAa,kCAAkC,YAAY,SAAS,EAAE,IACnF;IACJ,iBAAiB,aAAa,4BAA4B,OAAO,eAAe;IAChF,kBAAkB,aAAa,6BAA6B,OAAO,gBAAgB;IACnF,eAAe,mBAAmB,OAAO,aAAa;IACtD,cAAc,kBAAkB,OAAO,YAAY;EACrD;AACF;AAmCA,SAAS,wBAAwB,KAAqB;AACpD,QAAM,QAAQ,IAAI,QAAQ,GAAG,IAAI;AACjC,QAAM,MAAM,IAAI,QAAQ,KAAK,KAAK;AAClC,SAAO,QAAQ,KAAK,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,OAAO,GAAG;AAC7D;AAEA,SAAS,gBAAgB,MAAoC;AAC3D,QAAM,QAAuB,CAAC;AAC9B,aAAW,OAAO,MAAM;AACtB,UAAM,SAAS,eAAe,IAAI,KAAK;AACvC,QAAI,OAAQ,OAAM,KAAK,EAAE,OAAO,IAAI,QAAQ,KAAK,IAAI,KAAK,OAAO,CAAC;EACpE;AACA,QAAM,KAAK,CAAC,MAAM,UAAU,KAAK,IAAI,cAAc,MAAM,GAAG,CAAC;AAC7D,SAAO;IACL,YAAY,KAAK,SAAS,IAAI,wBAAwB,KAAK,CAAC,EAAG,GAAG,IAAI;IACtE;IACA,SAAS,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,MAAM,UAAU,KAAK,QAAQ,MAAM,KAAK;EACpE;AACF;AAGA,SAAS,eAAe,OAAkC;AACxD,QAAM,SAAS,oBAAoB,KAAK;AACxC,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,aAAa,SAAS,OAAO,UAAU;AAC7C,QAAM,aAAa,SAAS,OAAO,UAAU;AAC7C,QAAM,YAAY,SAAS,OAAO,SAAS;AAC3C,QAAM,iBAAiB,SAAS,OAAO,cAAc;AAErD,SAAO;IACL,GAAG;IACH,IAAI,aAAa,aAAa,OAAO,EAAE;IACvC,YAAY,aAAa,qBAAqB,OAAO,UAAU;IAC/D,cAAc,kBAAkB,OAAO,YAAY;IACnD,MAAM,aAAa,eAAe,OAAO,IAAI;IAC7C,MAAM,aAAa,eAAe,OAAO,IAAI;IAC7C,WAAW,aAAa,oBAAoB,OAAO,SAAS;IAC5D,WAAW,aAAa,oBAAoB,OAAO,SAAS;IAC5D,WAAW,aAAa,oBAAoB,OAAO,SAAS;IAC5D,YAAY,aACR;MACE,mBAAmB;QACjB;QACA,WAAW;MACb;MACA,kBAAkB;QAChB;QACA,WAAW;MACb;MACA,eAAe,aAAa,mCAAmC,WAAW,aAAa;IACzF,IACA;IACJ,YAAY,aACR;MACE,aAAa,aAAa,iCAAiC,WAAW,WAAW;MACjF,cAAc,aAAa,kCAAkC,WAAW,YAAY;IACtF,IACA;IACJ,WAAW,YACP,EAAE,WAAW,aAAa,8BAA8B,UAAU,SAAS,EAAE,IAC7E;IACJ,gBAAgB,iBACZ;MACE,MAAM,aAAa,8BAA8B,eAAe,IAAI;MACpE,YAAY,aAAa,oCAAoC,eAAe,UAAU;MACtF,QAAQ,aAAa,gCAAgC,eAAe,MAAM;MAC1E,QAAQ,eAAe;MACvB,QAAQ,eAAe;MACvB,gBAAgB,SAAS,eAAe,cAAc;IACxD,IACA;EACN;AACF;AAMA,IAAM,wBAAgD;EACpD,cAAc;EACd,cAAc;EACd,yBAAyB;EACzB,oBAAoB;EACpB,kBAAkB;AACpB;AAEA,SAASkB,cAAa,UAA0B;AAC9C,SAAO,sBAAsB,QAAQ,KAAK;AAC5C;AAGA,SAASK,0BAAyB,QAAiB,aAAoC;AACrF,MAAI,UAAU,KAAM,QAAO,CAAC;AAE5B,MAAI,OAAO,WAAW,UAAU;AAC9B,UAAMR,QAAO,kBAAkB,MAAM;AACrC,WAAOA,QAAO,CAAC,EAAE,MAAM,QAAiB,MAAAA,OAAM,cAAc,YAAY,CAAC,IAAI,CAAC;EAChF;AAEA,MAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,UAAM,QAAuB,CAAC;AAC9B,eAAW,QAAQ,QAAQ;AACzB,UAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAC7C,cAAM,SAAS,SAAS,IAAI;AAC5B,cAAMA,QAAO,OAAO,QAAQ,QAAQ,QAAQ,WAAW,EAAE;AACzD,cAAM,UAAU,kBAAkBA,KAAI;AACtC,YAAI,QAAS,OAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,SAAS,cAAc,YAAY,CAAC;MACpF,WAAW,OAAO,SAAS,UAAU;AACnC,cAAMA,QAAO,kBAAkB,IAAI;AACnC,YAAIA,MAAM,OAAM,KAAK,EAAE,MAAM,QAAQ,MAAAA,OAAM,cAAc,YAAY,CAAC;MACxE;IACF;AACA,WAAO;EACT;AAGA,QAAM,OAAO,kBAAkB,OAAO,MAAM,CAAC;AAC7C,SAAO,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC,IAAI,CAAC;AACvE;AAGA,SAAS,iBAAiB,KAA0B;AAClD,MAAI,IAAI,aAAa,OAAO,IAAI,cAAc,YAAY,IAAI,YAAY,GAAG;AAC3E,WAAO,IAAI;EACb;AACA,MAAI,IAAI,aAAa,OAAO,IAAI,cAAc,YAAY,IAAI,YAAY,GAAG;AAC3E,WAAO,IAAI;EACb;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,QAA6B;AACrD,SAAO,CAAC,aAAa,QAAQ,WAAW,MAAM,EAAE,KAAK,CAAC,QAAQ,oBAAoB,OAAO,GAAG,CAAC,CAAC;AAChG;AAGA,SAAS,eAAe,QAAoC;AAC1D,MAAI,SAAS,OAAO;AACpB,MAAI,OAAO,UAAU,MAAM;AACzB,UAAM,KAAK;AACX,UAAM,cAAcQ,0BAAyB,OAAO,QAAQ,EAAE;AAC9D,aAAS,YAAY,SAAS,IAAI,cAAc,OAAO;EACzD;AAEA,QAAM,CAAC,IAAI,IAAI,sBAAsB;IACnC;MACE,MAAM;MACN,MAAM,OAAO,QAAQ;MACrB,OAAO,OAAO;MACd;MACA,OAAO,OAAO;IAChB;EACF,CAAC;AACD,SAAO,MAAM,SAAS,SAAS,KAAK,QAAQ,EAAE,QAAQ,UAAU;AAClE;AAGA,SAAS,cAAc,QAAqB,aAAkC;AAC5E,QAAM,WAAW,OAAO,QAAQ;AAChC,SAAO;IACL,MAAM;IACN,MAAML,cAAa,QAAQ;IAC3B,QAAQ,OAAO,OAAO,GAAG,OAAO,IAAI,IAAI,OAAO,OAAO,OAAO,MAAM,EAAE,CAAC,KAAK;IAC3E,OAAO,SAASA,cAAa,QAAQ,CAAC;IACtC,OAAO,eAAe,MAAM;IAC5B,cAAc;EAChB;AACF;AAGA,SAAS,sBAAsB,QAAqB,aAAkC;AACpF,QAAM,UAAU,OAAO,OAAO,OAAO,WAAW,EAAE;AAClD,QAAM,cAAc,kBAAkB,OAAO,OAAO,OAAO,sBAAsB,EAAE,CAAC;AAEpF,QAAM,QAAQ,eAAe,MAAM;AACnC,QAAM,QAAQ,EAAE,QAAQ;AACxB,QAAM,SACJ,OAAO,OAAO,WAAW,WACrB,CAAC,EAAE,MAAM,QAAiB,MAAM,OAAO,QAAQ,cAAc,YAAY,CAAC,IAC1EK,0BAAyB,OAAO,QAAQ,WAAW;AAEzD,SAAO;IACL,MAAM;IACN,MAAM;IACN,QAAQ;IACR,OAAO,eAAe,SAAS,QAAQ,MAAM,GAAG,EAAE,CAAC;IACnD;IACA,cAAc;EAChB;AACF;AAGA,SAAS,oBAAoB,QAAqB,aAAyC;AACzF,QAAM,WAAW,OAAO,QAAQ;AAGhC,MAAI,aAAa,2BAA2B;AAC1C,WAAO,sBAAsB,QAAQ,WAAW;EAClD;AAGA,MAAI,YAAY,OAAO,SAAS,QAAQ;AACtC,WAAO,cAAc,QAAQ,WAAW;EAC1C;AAEA,SAAO;AACT;AAMO,IAAM,cAAN,cAA0B,sBAAsB;EAC5C,OAAO;EACP,cAAc;EAEf,SAAwB;;EAGxB,gBAAgB,oBAAI,IAA0B;EAE5C,kBAAiC;AACzC,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,SAAS,KAAK,WAAW;IAChC;AACA,WAAO,KAAK;EACd;EAEQ,aAA4B;AAClC,QAAI,CAAC,kBAAkB,EAAG,QAAO;AACjC,UAAM,WAAW,sBAAsB;AACvC,QAAI,CAAC,SAAU,QAAO;AACtB,WAAOvB,OAAK,UAAU,iBAAiB,aAAa;EACtD;EAEA,sBAAsB;AACpB,UAAM,WAAW,sBAAsB;AACvC,WAAO;MACL,QAAQ;MACR,SAAS,WACL;QACE;UACE,MAAM;UACN,MAAMA,OAAK,UAAU,iBAAiB,aAAa;QACrD;QACA,EAAE,MAAM,UAAU,MAAMA,OAAK,UAAU,kBAAkB,EAAE;MAC7D,IACA,CAAC;IACP;EACF;;;;;EAMQ,wBAA6C;AACnD,UAAM,MAAM,oBAAI,IAAoB;AACpC,UAAM,WAAW,sBAAsB;AACvC,QAAI,CAAC,SAAU,QAAO;AAEtB,UAAM,gBAAgBA,OAAK,UAAU,kBAAkB;AACvD,QAAI,CAACJ,aAAW,aAAa,EAAG,QAAO;AAEvC,QAAI;AACJ,QAAI;AACF,mBAAaC,aAAY,aAAa;IACxC,QAAQ;AACN,aAAO;IACT;AAEA,eAAW,QAAQ,YAAY;AAC7B,YAAM,QAAQG,OAAK,eAAe,IAAI;AACtC,UAAI;AACF,YAAI,CAACD,UAAS,KAAK,EAAE,YAAY,EAAG;MACtC,QAAQ;AACN;MACF;AACA,YAAM,aAAaC,OAAK,OAAO,gBAAgB;AAC/C,UAAI,CAACJ,aAAW,UAAU,EAAG;AAG7B,UAAI;AACJ,UAAI;AACF,cAAM,OAAO,SAAS,KAAK,MAAME,cAAa,YAAY,OAAO,CAAC,CAAC;AACnE,cAAM,MACJ,aAAa,wBAAwB,MAAM,MAAM,KACjD,aAAa,2BAA2B,MAAM,SAAS,KACvD;AACF,YAAI,CAAC,IAAK;AACV,wBAAgB,UAAU,mBAAmB,IAAI,QAAQ,cAAc,EAAE,CAAC,CAAC;MAC7E,QAAQ;AACN;MACF;AAGA,YAAM,WAAWE,OAAK,OAAO,aAAa;AAC1C,UAAI,CAACJ,aAAW,QAAQ,EAAG;AAE3B,YAAM,OAAO,eAAe,QAAQ;AACpC,UAAI,CAAC,KAAM;AAEX,UAAI;AACF,cAAM,MAAM,KACT,QAAQ,iEAAiE,EACzE,IAAI;AACP,YAAI,CAAC,KAAK,MAAO;AAEjB,cAAM,SAAkB,KAAK,MAAM,IAAI,KAAK;AAC5C,cAAM,YAAY,QAAQ,SAAS,MAAM,GAAG,YAAY,KAAK,QAAQ,MAAM,KAAK,CAAC;AAEjF,mBAAW,QAAQ,WAAW;AAC5B,gBAAM,WAAW,SAAS,IAAI;AAC9B,cAAI,CAAC,SAAU;AACf,gBAAM,KACJ,aAAa,gCAAgC,SAAS,UAAU,KAChE,aAAa,wBAAwB,SAAS,EAAE;AAClD,cAAI,GAAI,KAAI,IAAI,IAAI,aAAa;QACnC;MACF,QAAQ;MAER,UAAA;AACE,aAAK,MAAM;MACb;IACF;AAEA,WAAO;EACT;EAEA,cAAuB;AACrB,SAAK,SAAS,KAAK,WAAW;AAC9B,WAAO,KAAK,WAAW,QAAQA,aAAW,KAAK,MAAM;EACvD;EAEA,KAAK,SAA2C;AAC9C,QAAI,CAAC,KAAK,OAAQ,QAAO,CAAC;AAE1B,UAAM,aAAa,KAAK,MAAM,aAAa;AAE3C,UAAM,WAAW,KAAK,MAAM,cAAc;AAC1C,UAAM,KAAK,KAAK,aAAa;AAC7B,SAAK,IAAI,QAAQ;AAEjB,QAAI,CAAC,GAAI,OAAM,IAAI,iBAAiB,KAAK,MAAM,sBAAsB;AAGrE,UAAM,WAAW,KAAK,MAAM,uBAAuB;AACnD,UAAM,mBAAmB,KAAK,sBAAsB;AACpD,SAAK,IAAI,QAAQ;AAEjB,QAAI;AACF,YAAM,OAAO,GACV,QAAQ,qEAAqE,EAC7E,IAAI;AAIP,YAAM,UAAU,oBAAI,IAAyB;AAC7C,YAAMe,WAA6B,CAAC;AACpC,UAAI,QAAQ;AACZ,eAAS,aAAa,EAAE,OAAO,KAAK,QAAQ,WAAW,GAAG,UAAU,EAAE,CAAC;AACvE,UAAI,YAAY;AAEhB,iBAAW,OAAO,MAAM;AACtB,YAAI;AACF,gBAAM,WAAW,iBAAiB,IAAI,KAAK;AAC3C,cAAI,CAAC,YAAa,CAAC,SAAS,MAAM,CAAC,SAAS,WAAa;AAEzD,gBAAM,aAAa,SAAS,MAAM,SAAS,cAAc;AACzD,gBAAM,YAAY,SAAS,aAAa;AACxC,gBAAM,YACJ,SAAS,aAAa,SAAS,iBAAiB,SAAS,gBAAgB;AAC3E,cAAI,CAAC,kBAAkB,WAAW,OAAO,EAAG;AAE5C,gBAAM,YAAY,KAAK,aAAa,QAAQ;AAC5C,gBAAM,kBAAkB,MAAM,QAAQ,SAAS,YAAY;AAC3D,gBAAM,mBAAmB,SAAS,cAAc,UAAU;AAC1D,gBAAM,eACJ,MAAM,QAAQ,SAAS,aAAa,KAAK,SAAS,cAAc,SAAS;AAC3E,cAAI,SAAS,MAAM;AACjB,kBAAM,YAAY,iBAAiB,IAAI,UAAU,KAAK;AACtD,kBAAM,YACJ,kBAAkB,SAAS,aAAa,aAAa,SAAS,OAAO;cACnE,OAAO,SAAS,mBAAmB;cACnC,QAAQ,SAAS,oBAAoB;YACvC,CAAC,KAAK;AACR,kBAAM,OAAO;cACX,mBAAmB,qBAAqB,KAAK,CAAC,eAC1C,gBAA6B,qBAAqB,IAClD,cAA2B;gBACzB,IAAI;gBACJ,MAAM,UAAU,UAAU;gBAC1B,OAAO;gBACP;gBACA,cAAc;gBACd,cAAc,aAAa;gBAC3B,OAAO;kBACL,eAAe;kBACf,oBAAoB,SAAS,mBAAmB;kBAChD,qBAAqB,SAAS,oBAAoB;kBAClD,YAAY;kBACZ,aAAa,YAAY,IAAI,cAAc;gBAC7C;cACF,CAAC;YACP;AACA,gBAAI,CAAC,KAAM;AACX,oBAAQ,IAAI,OAAO,IAAI;AACvB,qBAAS;AACT,iBAAK,cAAc,IAAI,YAAY,QAAQ;AAC3C,iBAAK,eAAe,IAAI,YAAY;cAClC,IAAI;cACJ,YAAY,KAAK,UAAU;YAC7B,CAAC;AACD;UACF;AAEAA,mBAAQ,KAAK,EAAE,UAAU,YAAY,WAAW,WAAW,cAAc,MAAM,CAAC;AAChF,mBAAS;QACX,QAAQ;QAER,UAAA;AACE,uBAAa;AACb,mBAAS,aAAa,EAAE,OAAO,KAAK,QAAQ,WAAW,UAAU,QAAQ,KAAK,CAAC;QACjF;MACF;AAKA,YAAM,eAAe,KAAK,MAAM,gBAAgB;AAChD,YAAM,SAAS,IAAI,IAAIA,SAAQ,IAAI,CAAC,UAAU,CAAC,MAAM,YAAY,KAAK,CAAC,CAAC;AACxE,WAAK,uBAAuB,IAAI,QAAQ,CAAC,YAAY;AACnD,cAAM,QAAQ,OAAO,IAAI,QAAQ,UAAU;AAC3C,YAAI,CAAC,MAAO;AACZ,eAAO,OAAO,QAAQ,UAAU;AAChC,cAAM,OAAO,KAAK,cAAc,OAAO,SAAS,gBAAgB;AAChE,YAAI,KAAM,SAAQ,IAAI,MAAM,OAAO,IAAI;MACzC,CAAC;AAED,iBAAW,SAAS,OAAO,OAAO,GAAG;AACnC,cAAM,OAAO,KAAK;UAChB;UACA,EAAE,YAAY,MAAM,YAAY,OAAO,CAAC,GAAG,SAAS,CAAC,EAAE;UACvD;QACF;AACA,YAAI,KAAM,SAAQ,IAAI,MAAM,OAAO,IAAI;MACzC;AACA,WAAK,IAAI,YAAY;AAErB,YAAM,QAAQ,CAAC,GAAG,QAAQ,QAAQ,CAAC,EAChC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,MAAM,OAAO,KAAK,EACtC,IAAI,CAAC,CAAC,EAAE,IAAI,MAAM,IAAI;AACzB,eAAS,aAAa,EAAE,OAAO,KAAK,QAAQ,WAAW,UAAU,MAAM,OAAO,CAAC;AAE/E,WAAK,IAAI,UAAU;AACnB,aAAO;IACT,SAAS,OAAO;AACd,YAAM,IAAI,iBAAiB,KAAK,MAAM,qBAAqB,EAAE,OAAO,MAAM,CAAC;IAC7E,UAAA;AACE,SAAG,MAAM;IACX;EACF;EAEA,eAAe,WAAkC;AAE/C,QAAI,CAAC,KAAK,QAAQ;AAChB,WAAK,SAAS,KAAK,WAAW;IAChC;AACA,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,IAAI,MAAM,4BAA4B;IAC9C;AAEA,UAAM,KAAK,KAAK,aAAa;AAC7B,QAAI,CAAC,IAAI;AACP,YAAM,IAAI,MAAM,4BAA4B;IAC9C;AAEA,QAAI;AAEF,UAAI,WAAW,KAAK,cAAc,IAAI,SAAS;AAC/C,UAAI,oBAAoB;AAExB,UAAI,CAAC,UAAU;AAEb,mBAAW,KAAK,aAAa,IAAI,SAAS,KAAK;MACjD;AAEA,UAAI,CAAC,UAAU;AAEb,cAAMa,cAAa,KAAK,0BAA0B,IAAI,SAAS;AAC/D,YAAIA,aAAY;AACd,qBAAW,KAAK,aAAa,IAAIA,WAAU,KAAK;AAChD,8BAAoB;QACtB;MACF;AAEA,UAAI,CAAC,UAAU;AACb,cAAM,IAAI,MAAM,sBAAsB,SAAS,EAAE;MACnD;AAEA,YAAM,aAAa,SAAS,MAAM,SAAS,cAAc;AACzD,YAAM,YAAY,SAAS,aAAa;AACxC,YAAM,YAAY,SAAS,aAAa;AAGxC,YAAM,WAAW,KAAK;QACpB;QACA;QACA;QACA,SAAS,aAAa,aAAa,SAAS,SAAS;MACvD;AAGA,WAAK,uBAAuB,IAAI,UAAU,QAAQ;AAClD,YAAM,kBAAkB,oBAAoB,QAAQ;AACpD,YAAM,QAAQ,KAAK,aAAa,UAAU,eAAe;AAGzD,UAAI,mBAAmB;AACvB,UAAI,oBAAoB;AACxB,UAAI,YAAY;AAEhB,iBAAW,OAAO,iBAAiB;AACjC,4BAAoB,IAAI,QAAQ,SAAS;AACzC,6BAAqB,IAAI,QAAQ,UAAU;AAC3C,qBAAa,IAAI,QAAQ;MAC3B;AAGA,UAAI,qBAAqB,EAAG,oBAAmB,SAAS,mBAAmB;AAC3E,UAAI,sBAAsB,EAAG,qBAAoB,SAAS,oBAAoB;AAC9E,UAAI,cAAc,GAAG;AACnB,oBACE,kBAAkB,SAAS,aAAa,aAAa,SAAS,OAAO;UACnE,OAAO;UACP,QAAQ;QACV,CAAC,KAAK;MACV;AAGA,YAAM,YAAY,KAAK,cAAc,IAAI,UAAU,UAAU,EAAE;AAC/D,YAAM,YACH,WAAiD,aAClD,KAAK,sBAAsB,EAAE,IAAI,UAAU,KAC3C;AAEF,aAAO;QACL,WAAW,EAAE,WAAW,KAAK,MAAM,WAAW,kBAAkB;QAChE,IAAI;QACJ;QACA,MAAM,UAAU,iBAAiB;QACjC;QACA,cAAc;QACd,cAAc,aAAa;QAC3B,OAAO;UACL,eAAe,gBAAgB;UAC/B,oBAAoB;UACpB,qBAAqB;UACrB,YAAY;UACZ,aAAa,YAAY,IAAI,cAAc;QAC7C;QACA,UAAU;MACZ;IACF,UAAA;AACE,SAAG,MAAM;IACX;EACF;;EAIQ,eAAsC;AAC5C,QAAI,CAAC,KAAK,OAAQ,QAAO;AACzB,WAAO,eAAe,KAAK,MAAM;EACnC;;;;;;EAOQ,uBACN,IACA,QACA,SACM;AACN,QAAI,OAAO,SAAS,EAAG;AAEvB,QAAI,YAA2B;AAC/B,QAAI,QAAqB,CAAC;AAC1B,UAAM,QAAQ,MAAM;AAClB,UAAI,aAAa,QAAQ,MAAM,SAAS,EAAG,SAAQ,gBAAgB,KAAK,CAAC;AACzE,cAAQ,CAAC;IACX;AAEA,UAAM,OAAO,GACV;MACC;IACF,EACC,QAAQ;AACX,eAAW,OAAO,MAAM;AACtB,YAAM,aAAa,wBAAwB,IAAI,GAAG;AAClD,UAAI,eAAe,WAAW;AAC5B,cAAM;AACN,oBAAY;MACd;AACA,UAAI,OAAO,IAAI,UAAU,EAAG,OAAM,KAAK,GAAG;IAC5C;AACA,UAAM;EACR;;EAGQ,cACN,OACA,SACA,kBACoB;AACpB,UAAM,EAAE,UAAU,YAAY,WAAW,WAAW,aAAa,IAAI;AACrE,UAAM,YAAY,KAAK,qBAAqB,OAAO;AACnD,UAAM,YAAY,aAAa;AAE/B,UAAM,iBAAiB;MACrB,KAAK,oBAAoB,SAAS,SAAS,aAAa,aAAa,SAAS,SAAS,IAAI;IAC7F;AACA,UAAM,WAAW;MACf,eAAe,WAAW,KAAK,CAAC,eAC5B,gBAA2B,qBAAqB,IAChD,cAAc,cAAc;IAClC;AACA,QAAI,CAAC,SAAU,QAAO;AAEtB,UAAM,QAAQ,KAAK,aAAa,UAAU,QAAQ;AAClD,UAAM,YAAY,iBAAiB,IAAI,UAAU,KAAK;AAEtD,UAAM,gBAAwC,CAAC;AAC/C,QAAI,YAAY;AAChB,eAAW,OAAO,UAAU;AAC1B,mBAAa,IAAI,QAAQ;AACzB,UAAI,IAAI,OAAO;AACb,cAAM,aAAa,IAAI,QAAQ,SAAS,MAAM,IAAI,QAAQ,UAAU;AACpE,YAAI,YAAY,GAAG;AACjB,wBAAc,IAAI,KAAK,KAAK,cAAc,IAAI,KAAK,KAAK,KAAK;QAC/D;MACF;IACF;AACA,UAAM,gBAAgB,OAAO,KAAK,aAAa,EAAE,SAAS;AAE1D,SAAK,cAAc,IAAI,WAAW,QAAQ;AAC1C,SAAK,cAAc,IAAI,cAAc,UAAU,IAAI;MACjD;IACF,CAA4B;AAC5B,QAAI,WAAW;AACb,WAAK,cAAc,IAAI,UAAU,UAAU,IAAI;QAC7C;MACF,CAA4B;IAC9B;AACA,SAAK,eAAe,IAAI,WAAW,EAAE,IAAI,WAAW,YAAY,KAAK,UAAU,GAAG,CAAC;AAEnF,WAAO;MACL,IAAI;MACJ,MAAM,UAAU,SAAS;MACzB;MACA;MACA,cAAc;MACd,cAAc,aAAa;MAC3B,OAAO;QACL,eAAe,SAAS;QACxB,oBAAoB,SAAS,mBAAmB;QAChD,qBAAqB,SAAS,oBAAoB;QAClD,YAAY;QACZ,aAAa,YAAY,IAAI,cAAc;MAC7C;MACA,aAAa,gBAAgB,gBAAgB;IAC/C;EACF;;EAGQ,qBAAqB,SAAyC;AACpE,eAAW,SAAS,QAAQ,OAAO;AACjC,YAAM,YAAY,MAAM,OAAO,WAAW,KAAK;AAC/C,UAAI,UAAW,QAAO;IACxB;AACA,WAAO;EACT;;EAGQ,0BAA0B,IAAoB,WAAkC;AACtF,QAAI;AACF,YAAM,OAAO,GACV,QAAQ,kFAAkF,EAC1F,IAAI,iBAAiB,SAAS,IAAI;AAErC,iBAAW,OAAO,MAAM;AACtB,YAAI;AACF,gBAAM,SAAS,eAAe,IAAI,KAAK;AACvC,cAAI,QAAQ,cAAc,WAAW;AAEnC,kBAAM,WAAW,IAAI,IAAI,MAAM,GAAG;AAClC,gBAAI,SAAS,UAAU,KAAK,SAAS,CAAC,GAAG;AACvC,qBAAO,SAAS,CAAC;YACnB;UACF;QACF,QAAQ;QAER;MACF;IACF,QAAQ;IAER;AACA,WAAO;EACT;;EAGQ,aAAa,UAAwB,WAAsB,CAAC,GAAW;AAC7E,UAAM,WAAW,SAAS,QAAQ,SAAS;AAC3C,UAAM,eAAe,sBAAsB,QAAQ,KAAK,SAAS;AACjE,WAAO,oBAAoB,UAAU,cAAc,IAAI;EACzD;;EAGQ,yBAAyB,IAAoB,YAA4B;AAC/E,QAAI;AACF,YAAM,OAAO,GACV,QAAQ,iDAAiD,EACzD,IAAI,YAAY,UAAU,IAAI;AAEjC,UAAI,QAAQ;AACZ,iBAAW,OAAO,MAAM;AACtB,YAAI;AACF,gBAAM,SAAS,eAAe,IAAI,KAAK;AAEvC,cAAI,QAAQ,SAAS,KAAK,QAAQ,SAAS,GAAG;AAC5C;UACF;QACF,QAAQ;QAER;MACF;AACA,aAAO;IACT,QAAQ;AACN,aAAO;IACT;EACF;;EAGQ,wBACN,IACA,YACA,YACA,kBACW;AACX,QAAI;AACF,YAAM,OAAO,GACV,QAAQ,uEAAuE,EAC/E,IAAI,YAAY,UAAU,IAAI;AACjC,aAAO,KAAK,oBAAoB,gBAAgB,IAAI,GAAG,gBAAgB;IACzE,QAAQ;AACN,aAAO,CAAC;IACV;EACF;;EAGQ,oBACN,SACA,kBACW;AACX,UAAM,WAAsB,CAAC;AAE7B;AACE,UAAI,kBAAiC;AACrC,UAAI,eAAe;AAEnB,iBAAW,SAAS,QAAQ,SAAS;AACnC;AACE,gBAAM,SAAS,MAAM;AACrB,cAAI,iBAAiB,MAAM,EAAG;AAC9B,gBAAM,WAAW,MAAM,IAAI,MAAM,GAAG,EAAE,IAAI,KAAK,OAAO,YAAY;AAGlE,gBAAM,OAAO,OAAO,SAAS,IAAI,cAAc;AAG/C,cAAI,cAAc;AAClB,cAAI,OAAO,YAAY,mBAAmB;AACxC,0BAAc,KAAK,MAAM,OAAO,WAAW,iBAAiB;UAC9D,WAAW,OAAO,WAAW;AAC3B,0BAAc,OAAO;UACvB,WAAW,OAAO,WAAW;AAC3B,0BAAc,OAAO;UACvB;AAGA,cAAI,OAAO,WAAW,WAAW;AAC/B,8BAAkB,OAAO,UAAU;UACrC;AAGA,gBAAM,cAAc,OAAO,YAAY,eAAe;AACtD,gBAAM,eAAe,OAAO,YAAY,gBAAgB;AAGxD,gBAAM,QAAuB,CAAC;AAG9B,gBAAM,OAAO,kBAAkB,OAAO,QAAQ,EAAE;AAChD,cAAI,MAAM;AACR,kBAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC;UAC9D;AAGA,cAAI,OAAO,gBAAgB;AACzB,kBAAMV,YAAW,KAAK,sBAAsB,OAAO,gBAAgB,WAAW;AAC9E,gBAAIA,WAAU;AACZ,oBAAM,KAAKA,SAAQ;YACrB;UACF;AAGA,cAAI,MAAM,WAAW,EAAG;AAExB,gBAAM,YAAY,OAAO,WAAW,aAAa;AACjD,gBAAM,SAAS,EAAE,OAAO,aAAa,QAAQ,aAAa;AAC1D,gBAAM,OAAO,kBAAkB,WAAW,MAAM;AAEhD,mBAAS,KAAK;YACZ,IAAI,UAAU,QAAQ,UAAU,IAAI,QAAQ;YAC5C;YACA,OAAO;YACP,cAAc;YACd,gBAAgB;YAChB,MAAM,SAAS,eAAe,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM,IAAI,SAAS;YAC9E,OAAO;YACP,UAAU;YACV;YACA,MAAM,QAAQ;YACd,aAAa,SAAS,OAAO,cAAc;YAC3C;UACF,CAAC;AAED;QACF;MACF;IACF;AAEA,WAAO;EACT;;EAGQ,sBACN,UACA,aACoB;AACpB,QAAI,CAAC,YAAY,CAAC,SAAS,KAAM,QAAO;AAExC,UAAM,WAAW,SAAS;AAC1B,UAAM,iBAAiB,aAAa,gBAAgB,SAASI,cAAa,QAAQ;AAGlF,UAAM,QAAuB;MAC3B,QAAQ,SAAS,WAAW,cAAc,cAAc;IAC1D;AAGA,QAAI,SAAS,QAAQ;AACnB,UAAI,OAAO,SAAS,WAAW,UAAU;AACvC,YAAI;AACF,gBAAM,QAAQ,KAAK,MAAM,SAAS,MAAM;QAC1C,QAAQ;AACN,gBAAM,QAAQ,EAAE,MAAM,SAAS,OAAO;QACxC;MACF,OAAO;AACL,cAAM,QAAQ,SAAS;MACzB;IACF;AAGA,QAAI,SAAS,WAAW,QAAW;AACjC,UAAI,OAAO,SAAS,WAAW,UAAU;AACvC,YAAI;AACF,gBAAM,SAAS,KAAK,MAAM,SAAS,MAAM;AACzC,gBAAM,SAAS;AACf,cAAI,OAAO,SAAS,OAAO,WAAW,OAAO,QAAQ;AACnD,kBAAM,QAAQ,OAAO,SAAS,OAAO,WAAW,OAAO;AACvD,kBAAM,SAAS;UACjB;QACF,QAAQ;AACN,gBAAM,SAAS,SAAS;QAC1B;MACF,OAAO;AACL,cAAM,SAAS,SAAS;MAC1B;IACF;AAGA,QAAI,aAAa,eAAe;AAC9B,YAAMI,YAAW,OAAO,SAAS,MAAM,KAAK,GAAG,QAAQ,EAAE,EAAE,KAAK;AAChE,UAAIA,WAAU;AACZ,eAAO;UACL,MAAM;UACN,MAAMA;UACN,iBAAiB,MAAM,WAAW,cAAc,YAAY;UAC5D,cAAc;QAChB;MACF;IACF;AAEA,WAAO;MACL,MAAM;MACN,MAAM;MACN,QAAQ,SAAS,cAAc;MAC/B,OAAO,SAAS,cAAc;MAC9B;MACA,cAAc;IAChB;EACF;EAEQ,aAAa,IAAoB,WAAwC;AAC/E,UAAM,MAAM,GACT,QAAQ,8CAA8C,EACtD,IAAI,gBAAgB,SAAS,EAAE;AAElC,QAAI,CAAC,IAAK,QAAO;AAEjB,WAAO,iBAAiB,IAAI,KAAK;EACnC;EAEQ,WAAW,IAAoB,WAAsC;AAC3E,UAAM,MAAM,GACT,QAAQ,8CAA8C,EACtD,IAAI,UAAU,SAAS,EAAE;AAE5B,QAAI,CAAC,IAAK,QAAO;AAEjB,WAAO,eAAe,IAAI,KAAK;EACjC;EAEQ,uBACN,IACA,UACA,UACM;AACN,UAAM,gBAAgB,SAAS;AAC/B,QAAI,CAAC,MAAM,QAAQ,aAAa,KAAK,cAAc,WAAW,EAAG;AAEjE,eAAW,WAAW,eAAe;AACnC,UAAI,CAAC,QAAQ,GAAI;AAEjB,YAAM,SAAS,KAAK,WAAW,IAAI,QAAQ,EAAE;AAC7C,UAAI,CAAC,UAAU,CAAC,MAAM,QAAQ,OAAO,YAAY,EAAG;AAEpD,iBAAW,WAAW,OAAO,cAAc;AACzC,cAAM,OAAO,QAAQ,MAAM,KAAK,EAAE,YAAY;AAC9C,YAAI,SAAS,UAAU,SAAS,YAAa;AAE7C,cAAM,cAAc,iBAAiB,OAAO;AAC5C,cAAM,QAAuB,CAAC;AAE9B,cAAM,OAAO,kBAAkB,QAAQ,QAAQ,EAAE;AACjD,YAAI,MAAM;AACR,gBAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC;QAC9D;AAEA,YAAI,SAAS,eAAe,MAAM,QAAQ,QAAQ,OAAO,GAAG;AAC1D,qBAAW,UAAU,QAAQ,SAAS;AACpC,gBAAI,oBAAoB,OAAO,IAAI,KAAK,oBAAoB,OAAO,IAAI,EAAG;AAC1E,kBAAM,OAAO,oBAAoB,QAAQ,WAAW;AACpD,gBAAI,KAAM,OAAM,KAAK,IAAI;UAC3B;QACF;AAEA,YAAI,MAAM,WAAW,EAAG;AAExB,iBAAS,KAAK;UACZ,IAAI,cAAc,QAAQ,EAAE;UAC5B;UACA,OAAO;UACP,cAAc;UACd,gBAAgB;UAChB,MAAM;UACN,OAAO;UACP,UAAU;UACV,QAAQ;UACR,MAAM;UACN,aAAa,QAAQ;UACrB,UAAU,QAAQ,YAAY,QAAQ;UACtC;QACF,CAAC;MACH;IACF;EACF;AACF;AEtsCA,IAAMF,sBAAqB;AAC3B,IAAMK,kBAAiB;AAEhB,SAAS,oBAA4B;AAC1C,SAAO,gBAAgB,WAAW,KAAK;AACzC;AAgBA,SAASJ,kBAAiB,OAAwB;AAChD,MAAI,OAAO,UAAU,SAAU,QAAO,OAAO,SAAS,KAAK,IAAI,QAAQ;AACvE,QAAM,OAAO,OAAO,SAAS,EAAE,EAAE,KAAK;AACtC,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,KAAK,KAAK,MAAM,IAAI;AAC1B,SAAO,OAAO,MAAM,EAAE,IAAI,IAAI;AAChC;AAEA,SAAS,cACP,OACA,OACA,QACe;AACf,SAAO,YAAY,MAAM,OAAO,OAAO,MAAM;AAC/C;AAOA,SAAS,kBAAkB,OAAe,OAAwB;AAChE,QAAM,SAAS;IAAc;IAAO;IAAO,CAAC,MAC1C,OAAO,MAAM,YAAY,OAAO,MAAM,WAAW,IAAI;EACvD;AACA,SAAO,WAAW,SAAY,IAAIA,kBAAiB,MAAM;AAC3D;AAEA,SAAS,6BAA6B,UAA0B;AAC9D,QAAM,OAAOpB,UAAS,UAAU,QAAQ;AACxC,QAAM,aAAa,KAAK,QAAQ,GAAG;AACnC,SAAO,cAAc,IAAI,KAAK,MAAM,aAAa,CAAC,KAAK,OAAO;AAChE;AAEA,SAAS,SAAS,OAAkD;AAClE,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEA,SAAS,cAAc,SAA0B;AAC/C,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,MAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,QAAO;AACpC,SAAO,QACJ,IAAI,CAAC,SAAS;AACb,QAAI,CAAC,SAAS,IAAI,EAAG,QAAO;AAC5B,QAAI,KAAK,MAAM,MAAM,OAAQ,QAAO,OAAO,KAAK,MAAM,KAAK,EAAE;AAC7D,QAAI,KAAK,MAAM,MAAM,QAAS,QAAO;AACrC,WAAO;EACT,CAAC,EACA,OAAO,OAAO,EACd,KAAK,IAAI;AACd;AAEA,SAAS,mBAAmB,SAAkB,aAAoC;AAChF,QAAM,OAAO,kBAAkB,cAAc,OAAO,CAAC;AACrD,SAAO,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC,IAAI,CAAC;AACvE;AAEA,SAAS,kBAAkB,OAAwC;AACjE,SAAO,kBAAkB,mBAAmB,MAAM,WAAW,CAAC;AAChE;AAEA,SAAS,gBAAgB,SAAoE;AAC3F,WAAS,QAAQ,QAAQ,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;AAC3D,QAAI,OAAO,QAAQ,KAAK,IAAI,IAAI,MAAM,SAAU,QAAO,QAAQ,KAAK;EACtE;AACA,SAAO;AACT;AAEA,SAAS,wBAAwB,SAA+D;AAC9F,QAAM,OAAO,oBAAI,IAAqC;AACtD,aAAW,SAAS,SAAS;AAC3B,UAAM,KAAK,MAAM,IAAI;AACrB,QAAI,OAAO,OAAO,YAAY,GAAI,MAAK,IAAI,IAAI,KAAK;EACtD;AAEA,QAAM,OAAO,gBAAgB,OAAO;AACpC,MAAI,CAAC,KAAM,QAAO,CAAC;AAEnB,QAAMS,QAAkC,CAAC;AACzC,QAAM,OAAO,oBAAI,IAAY;AAC7B,MAAI,UAA+C;AACnD,SAAO,SAAS;AACd,UAAM,KAAK,OAAO,QAAQ,IAAI,KAAK,EAAE;AACrC,QAAI,CAAC,MAAM,KAAK,IAAI,EAAE,EAAG;AACzB,SAAK,IAAI,EAAE;AACXA,UAAK,KAAK,OAAO;AACjB,UAAM,WAAoB,QAAQ,UAAU;AAC5C,cAAU,OAAO,aAAa,WAAW,KAAK,IAAI,QAAQ,IAAI;EAChE;AAEA,SAAOA,MAAK,QAAQ;AACtB;AAEO,IAAM,UAAN,cAAsB,wBAAqC;EACvD,OAAO;EACP,cAAc;EAEf,WAA0B;EAE1B,eAA8B;AACpC,WAAO,cAAcV,OAAK,kBAAkB,GAAG,SAAS,UAAU,GAAG,SAAS;EAChF;EAEA,sBAAsB;AACpB,UAAM,WAAW,kBAAkB;AACnC,WAAO;MACL,QAAQ;MACR,SAAS;QACP,EAAE,MAAM,UAAU,MAAMA,OAAK,UAAU,SAAS,UAAU,EAAE;QAC5D,EAAE,MAAM,WAAW,MAAM,UAAU;MACrC;IACF;EACF;EAEA,cAAuB;AACrB,SAAK,WAAW,KAAK,aAAa;AAClC,QAAI,CAAC,KAAK,SAAU,QAAO;AAC3B,WAAO,KAAK,iBAAiB,EAAE,SAAS;EAC1C;EAEA,mBAAmB,SAAgD;AACjE,QAAI,CAAC,KAAK,SAAU,QAAO,CAAC;AAC5B,WAAO,KAAK,iBAAiB,OAAO,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,OAAO;MAC7D,WAAW,6BAA6B,IAAI;MAC5C,YAAY;MACZ,aAAa,KAAK,kBAAkB,IAAI;IAC1C,EAAE;EACJ;EAEA,eAAe,WAAkC;AAC/C,UAAM,OAAO,KAAK,eAAe,IAAI,SAAS;AAC9C,QAAI,CAAC,KAAM,OAAM,IAAI,MAAM,sBAAsB,SAAS,EAAE;AAC5D,QAAI,CAACJ,aAAW,KAAK,UAAU,EAAG,OAAM,IAAI,MAAM,yBAAyB,KAAK,UAAU,EAAE;AAE5F,UAAM,SAAS,KAAK,YAAY,KAAK,UAAU;AAC/C,UAAM,QAAQ,KAAK,eAAe,OAAO,WAAW;AAEpD,WAAO;MACL,WAAW,EAAE,WAAW,KAAK,MAAM,WAAW,KAAK,GAAG;MACtD,IAAI,KAAK;MACT,OAAO,KAAK;MACZ,MAAM,MAAM,KAAK,EAAE;MACnB,WAAW,KAAK;MAChB,cAAc,KAAK;MACnB,cAAc,KAAK;MACnB,OAAO;QACL,eAAe,MAAM,SAAS;QAC9B,oBAAoB,MAAM;QAC1B,qBAAqB,MAAM;QAC3B,yBAAyB,MAAM,wBAAwB;QACvD,2BAA2B,MAAM,0BAA0B;QAC3D,YAAY,MAAM;QAClB,aAAa,MAAM,YAAY,IAAI,aAAa;MAClD;MACA,UAAU,MAAM;IAClB;EACF;EAEQ,iBAAiB,SAAiD;AACxE,QAAI,CAAC,KAAK,SAAU,QAAO,CAAC;AAC5B,WAAO,KAAK;MACV,KAAK;MACL,CAAC,UAAU,MAAM,OAAO,KAAK,MAAM,KAAK,SAAS,QAAQ;MACzD,EAAE,YAAY,QAAQ;IACxB;EACF;EAEU,sBAAsB,MAAmB,QAAwC;AACzF,WAAO,KAAK,qBAAqB;MAC/B;MACA;MACA,aAAa,KAAK,kBAAkB,OAAO,IAAI;MAC/C,QAAQ;QACN,kBAAkBwB;QAClB,eAAeK;MACjB;IACF,CAAC;EACH;;EAGQ,kBAAkB,MAAiD;AACzE,WAAO,KAAK,UAAU,CAACL,qBAAoBK,iBAAgB,KAAK,SAAS,KAAK,IAAI,CAAC;EACrF;EAEU,qBAAqB,UAAsC;AACnE,WAAO,iBAAiB,KAAK,uBAAuB,QAAQ,CAAC;EAC/D;EAEQ,uBAAuB,UAAmD;AAChF,UAAM,SAAS,KAAK,YAAY,QAAQ;AACxC,UAAM,QAAQ,KAAK,eAAe,OAAO,WAAW;AACpD,UAAM,eAAe,MAAM,SAAS;AACpC,QAAI,iBAAiB,EAAG,QAAO,gBAAgB,qBAAqB;AAEpE,UAAM,aAAa,OAAO,KAAK,MAAM,UAAU,EAAE,SAAS,IAAI,MAAM,aAAa;AACjF,WAAO,cAAc;MACnB,IAAI,OAAO;MACX,MAAM,MAAM,OAAO,SAAS;MAC5B,OAAO,OAAO;MACd,WAAW,OAAO;MAClB,cAAc,OAAO;MACrB,cAAc,OAAO;MACrB,OAAO;QACL,eAAe;QACf,oBAAoB,MAAM;QAC1B,qBAAqB,MAAM;QAC3B,yBAAyB,MAAM,wBAAwB;QACvD,2BAA2B,MAAM,0BAA0B;QAC3D,YAAY,MAAM;QAClB,aAAa,MAAM,YAAY,IAAI,aAAa;MAClD;MACA,aAAa;IACf,CAAC;EACH;EAEQ,YAAY,UAAgC;AAGlD,QAAI,SAAyC;AAC7C,QAAI,cAAc;AAClB,UAAM,UAAqC,CAAC;AAE5C,eAAW,UAAU,cAAc,QAAQ,GAAG;AAC5C,qBAAe;AACf,UAAI,OAAO,MAAM,MAAM,WAAW;AAChC,mBAAW;AACX;MACF;AACA,cAAQ,KAAK,MAAM;IACrB;AAEA,QAAI,gBAAgB,EAAG,OAAM,IAAI,MAAM,YAAY;AACnD,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,wBAAwB;AAErD,UAAM,cAAc,wBAAwB,OAAO;AACnD,QAAI,YAAY,WAAW,EAAG,OAAM,IAAI,MAAM,oBAAoB;AAElE,UAAM,YAAY,OAAO,OAAO,IAAI,KAAK,6BAA6B,QAAQ,CAAC,EAAE,KAAK;AACtF,QAAI,CAAC,UAAW,OAAM,IAAI,MAAM,oBAAoB;AAEpD,UAAM,OAAO,KAAK,kBAAkB,QAAQ,EAAE;AAC9C,UAAM,YAAY,OAAO,OAAO,KAAK,KAAK,EAAE,EAAE,KAAK,KAAKxB,UAAS,UAAU,QAAQ;AACnF,UAAM,YAAY,kBAAkB,qBAAqB,OAAO,WAAW,CAAC,KAAK,KAAK;AACtF,UAAM,YAAY,YAAY;MAC5B,CAAC,KAAK,UAAU,KAAK,IAAI,KAAK,kBAAkB,KAAK,CAAC;MACtD;IACF;AACA,UAAM,gBAAgB,KAAK,mBAAmB,WAAW;AACzD,UAAM,eAAe,KAAK,aAAa,WAAW;AAClD,UAAM,iBAAiB,cAAc,SAAS;AAE9C,WAAO;MACL;MACA;MACA;MACA;MACA,OAAO,oBAAoB,eAAe,cAAc,cAAc;MACtE;IACF;EACF;EAEQ,mBAAmB,SAAmD;AAC5E,aAAS,QAAQ,QAAQ,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;AAC3D,YAAM,QAAQ,QAAQ,KAAK;AAC3B,UAAI,MAAM,MAAM,MAAM,eAAgB;AACtC,YAAM,OAAO,mBAAmB,OAAO,MAAM,MAAM,KAAK,EAAE,CAAC;AAC3D,UAAI,KAAM,QAAO;IACnB;AACA,WAAO;EACT;EAEQ,aAAa,SAAmD;AACtE,eAAW,SAAS,SAAS;AAC3B,UAAI,MAAM,MAAM,MAAM,UAAW;AACjC,YAAM,UAAU,MAAM,SAAS;AAC/B,UAAI,CAAC,SAAS,OAAO,KAAK,QAAQ,MAAM,MAAM,OAAQ;AACtD,YAAM,QAAQ,mBAAmB,cAAc,QAAQ,SAAS,CAAC,CAAC;AAClE,UAAI,MAAO,QAAO;IACpB;AACA,WAAO;EACT;EAEQ,eAAe,SAQrB;AACA,UAAM,UAAU,IAAI,kBAAkB,EAAE,iBAAiB,SAAS,CAAC;AACnE,UAAM,aAAqC,CAAC;AAE5C,eAAW,SAAS,SAAS;AAC3B,YAAM,cAAc,kBAAkB,KAAK;AAC3C,YAAM,OAAO,OAAO,MAAM,MAAM,KAAK,EAAE;AAEvC,UAAI,SAAS,WAAW;AACtB,cAAM,UAAU,cAAc,iBAAiB,MAAM,SAAS,GAAG,QAAQ;AACzE,YAAI,CAAC,QAAS;AACd,cAAMyB,UAAS,KAAK,oBAAoB,OAAO,SAAS,aAAa,OAAO;AAC5E,YAAI,CAACA,QAAQ;AACb,YAAIA,QAAO,QAAS,SAAQ,cAAcA,QAAO,OAAO;AACxD,YAAIA,QAAO,SAASA,QAAO,cAAc,GAAG;AAC1C,qBAAWA,QAAO,KAAK,KAAK,WAAWA,QAAO,KAAK,KAAK,KAAKA,QAAO;QACtE;AACA;MACF;AAEA,YAAM,UAAU,KAAK,oBAAoB,OAAO,WAAW;AAC3D,UAAI,QAAS,SAAQ,cAAc,OAAO;IAC5C;AAEA,UAAM,SAAS,QAAQ,OAAO;AAE9B,WAAO;MACL,UAAU,OAAO;MACjB,kBAAkB,OAAO,MAAM;MAC/B,mBAAmB,OAAO,MAAM;MAChC,sBAAsB,OAAO,MAAM,2BAA2B;MAC9D,wBAAwB,OAAO,MAAM,6BAA6B;MAClE,WAAW,OAAO,MAAM;MACxB;IACF;EACF;EAEQ,oBACN,OACA,SACA,aACA,SAKO;AACP,UAAM,KAAK,cAAc,cAAc,MAAM,IAAI,GAAG,QAAQ,KAAK;AACjE,UAAM,OAAO,cAAc,gBAAgB,QAAQ,MAAM,GAAG,QAAQ,KAAK;AAEzE,QAAI,SAAS,QAAQ;AACnB,YAAM,QAAQ,mBAAmB,QAAQ,SAAS,GAAG,WAAW;AAChE,UAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,aAAO,KAAK,iBAAiB,EAAE,IAAI,MAAM,QAAQ,aAAa,MAAM,CAAC;IACvE;AAEA,QAAI,SAAS,aAAa;AACxB,YAAM,QAAQ,KAAK,wBAAwB,QAAQ,SAAS,GAAG,WAAW;AAC1E,UAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,YAAM,QAAQ,KAAK,eAAe,QAAQ,OAAO,CAAC;AAClD,YAAM,QAAQ,OAAO,QAAQ,OAAO,MAAM,WAAW,QAAQ,OAAO,EAAE,KAAK,IAAI;AAC/E,YAAM,OAAO,MAAM,QAAQ,kBAAkB,OAAO,MAAM,MAAM,KAAK;AACrE,aAAO;QACL,SAAS;UACP;UACA,MAAM;UACN,OAAO;UACP;UACA;UACA,UAAU,OAAO,QAAQ,UAAU,MAAM,WAAW,QAAQ,UAAU,IAAI;UAC1E;UACA,QAAQ,MAAM;UACd,MAAM,QAAQ;UACd,YAAY,OAAO,IAAI,aAAa;QACtC;QACA,aAAa,MAAM;QACnB;MACF;IACF;AAEA,QAAI,SAAS,cAAc;AACzB,WAAK,iBAAiB,SAAS,aAAa,OAAO;AACnD,aAAO,KAAK,iBAAiB;IAC/B;AAEA,QAAI,SAAS,iBAAiB;AAC5B,aAAO,KAAK,iBAAiB,KAAK,qBAAqB,IAAI,SAAS,WAAW,CAAC;IAClF;AAEA,QAAI,SAAS,YAAY,QAAQ,SAAS,MAAM,MAAM;AACpD,YAAM,QAAQ,mBAAmB,QAAQ,SAAS,GAAG,WAAW;AAChE,UAAI,MAAM,WAAW,EAAG,QAAO;AAC/B,aAAO,KAAK,iBAAiB,EAAE,IAAI,MAAM,QAAQ,aAAa,MAAM,CAAC;IACvE;AAEA,QAAI,SAAS,mBAAmB,SAAS,qBAAqB;AAC5D,YAAM,UAAU,OAAO,QAAQ,SAAS,KAAK,EAAE,EAAE,KAAK;AACtD,UAAI,CAAC,QAAS,QAAO;AACrB,aAAO,KAAK,iBAAiB;QAC3B;QACA,MAAM;QACN,OAAO;QACP;QACA,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,SAAS,cAAc,YAAY,CAAC;MACpE,CAAC;IACH;AAEA,WAAO;EACT;EAEQ,wBAAwB,SAAkB,aAAoC;AACpF,QAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,QAAO,CAAC;AAErC,UAAM,QAAuB,CAAC;AAC9B,eAAW,QAAQ,SAAS;AAC1B,UAAI,CAAC,SAAS,IAAI,EAAG;AACrB,YAAM,OAAO,KAAK,MAAM;AAExB,UAAI,SAAS,QAAQ;AACnB,cAAM,OAAO,kBAAkB,OAAO,KAAK,MAAM,KAAK,EAAE,CAAC;AACzD,YAAI,KAAM,OAAM,KAAK,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC;AACtE;MACF;AAEA,UAAI,SAAS,YAAY;AACvB,cAAM,OAAO,kBAAkB,OAAO,KAAK,UAAU,KAAK,EAAE,CAAC;AAC7D,YAAI,KAAM,OAAM,KAAK,EAAE,MAAM,aAAa,MAAM,cAAc,YAAY,CAAC;AAC3E;MACF;AAEA,UAAI,SAAS,YAAY;AACvB,cAAM,SAAS,OAAO,KAAK,IAAI,KAAK,EAAE,EAAE,KAAK;AAC7C,cAAM,WAAW,OAAO,KAAK,MAAM,KAAK,EAAE,EAAE,KAAK,KAAK;AACtD,cAAMZ,YAAwB;UAC5B,MAAM;UACN,MAAM;UACN,OAAO,SAAS,QAAQ;UACxB,QAAQ,UAAU;UAClB,cAAc;UACd,OAAO;YACL,QAAQ;YACR,OAAO,KAAK,WAAW,KAAK,CAAC;UAC/B;QACF;AACA,cAAM,KAAKA,SAAQ;MACrB;IACF;AAEA,WAAO;EACT;EAEQ,iBACN,SACA,aACA,SACM;AACN,UAAM,SAAS,OAAO,QAAQ,YAAY,KAAK,EAAE,EAAE,KAAK;AACxD,UAAM,SAAS,mBAAmB,QAAQ,SAAS,GAAG,WAAW;AACjE,QAAI,CAAC,OAAQ;AACb,YAAQ,gBAAgB,QAAQ;MAC9B;MACA,QAAQ,QAAQ,SAAS,MAAM,OAAO,UAAU;MAChD,UAAU,QAAQ,SAAS;MAC3B,SAAS;IACX,CAAC;EACH;EAEQ,qBACN,IACA,SACA,aACwB;AACxB,UAAM,UAAU,OAAO,QAAQ,SAAS,KAAK,EAAE;AAC/C,UAAM,SAAS,OAAO,QAAQ,QAAQ,KAAK,EAAE;AAC7C,UAAM,UAAU,OAAO,QAAQ,UAAU,KAAK,CAAC,MAAM,KAAK,QAAQ,WAAW,MAAM;AACnF,WAAO;MACL;MACA,MAAM;MACN;MACA,OAAO;QACL;UACE,MAAM;UACN,MAAM;UACN,OAAO;UACP,cAAc;UACd,OAAO;YACL,QAAQ,UAAU,UAAU;YAC5B,OAAO,EAAE,QAAQ;YACjB,QAAQ,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,cAAc,YAAY,CAAC,IAAI,CAAC;YAChF,UAAU;cACR,UAAU,QAAQ,UAAU;cAC5B,WAAW,QAAQ,WAAW;cAC9B,WAAW,QAAQ,WAAW;cAC9B,gBAAgB,QAAQ,gBAAgB;YAC1C;UACF;QACF;MACF;IACF;EACF;EAEQ,oBACN,OACA,aAC+B;AAC/B,UAAM,OAAO,MAAM,MAAM;AACzB,QAAI,SAAS,gBAAgB,SAAS,oBAAoB,SAAS,kBAAkB;AACnF,aAAO;IACT;AAEA,QAAI,SAAS,oBAAoB,MAAM,SAAS,MAAM,KAAM,QAAO;AAEnE,UAAM,UACJ,SAAS,mBAAmB,cAAc,MAAM,SAAS,CAAC,IAAI,OAAO,MAAM,SAAS,KAAK,EAAE;AAC7F,UAAM,OAAO,kBAAkB,OAAO;AACtC,QAAI,CAAC,KAAM,QAAO;AAElB,WAAO;MACL,IAAI,cAAc,cAAc,MAAM,IAAI,GAAG,QAAQ,KAAK;MAC1D,MAAM,SAAS,mBAAmB,SAAS;MAC3C,OAAO,SAAS,mBAAmB,SAAY;MAC/C;MACA,OAAO,CAAC,EAAE,MAAM,QAAQ,MAAM,cAAc,YAAY,CAAC;IAC3D;EACF;EAEQ,eAAe,KAQrB;AACA,UAAM,QAAQ,cAAc,iBAAiB,KAAK,QAAQ,KAAK,CAAC;AAChE,UAAM,cAAc,cAAc,uBAAuB,MAAM,OAAO,GAAG,QAAQ,KAAK;AACtF,UAAM,eAAe,cAAc,wBAAwB,MAAM,QAAQ,GAAG,QAAQ,KAAK;AACzF,UAAM,kBACJ,cAAc,2BAA2B,MAAM,WAAW,GAAG,QAAQ,KAAK;AAC5E,UAAM,oBACJ,cAAc,4BAA4B,MAAM,YAAY,GAAG,QAAQ,KAAK;AAC9E,UAAM,cACJ,cAAc,6BAA6B,MAAM,aAAa,GAAG,QAAQ,KACzE,cAAc,eAAe,kBAAkB;AACjD,UAAM,OAAO,SAAS,MAAM,MAAM,CAAC,IAAI,OAAO,MAAM,MAAM,EAAE,OAAO,KAAK,CAAC,IAAI;AAE7E,WAAO;MACL,aAAa,cAAc,kBAAkB;MAC7C;MACA;MACA;MACA;MACA,MAAM,QAAQ,OAAO,SAAS,IAAI,IAAI,OAAO;MAC7C,QAAQ;QACN,OAAO,cAAc,kBAAkB;QACvC,QAAQ;QACR,YAAY,mBAAmB;QAC/B,cAAc,qBAAqB;MACrC;IACF;EACF;EAEQ,iBAAiB,SAIvB;AACA,WAAO;MACL;MACA,aAAa;MACb,OAAO;IACT;EACF;AACF;AC3lBO,SAAS,uBAAsC;AACpD,QAAM,kBAAkBP,UAAS;AACjC,MAAI,oBAAoB,YAAY,oBAAoB,QAAS,QAAO;AACxE,SAAOP,OAAKG,SAAQ,GAAG,QAAQ;AACjC;AAEA,SAAS,kBAAiC;AACxC,MAAI,CAAC,kBAAkB,EAAG,QAAO;AACjC,QAAM,WAAW,qBAAqB;AACtC,MAAI,CAAC,SAAU,QAAO;AACtB,SAAO,cAAcH,OAAK,UAAU,OAAO,MAAM,WAAW,CAAC;AAC/D;AAEA,SAAS,2BAA2B;AAClC,QAAM,WAAW,qBAAqB;AACtC,SAAO;IACL,QAAQ;IACR,SAAS,WAAW,CAAC,EAAE,MAAM,UAAU,MAAMA,OAAK,UAAU,OAAO,MAAM,WAAW,EAAE,CAAC,IAAI,CAAC;EAC9F;AACF;AAEO,IAAM,aAAN,cAAyB,oBAAoB;EAClD,cAAc;AACZ,UAAM;MACJ,MAAM;MACN,aAAa;MACb,YAAY;MACZ,qBAAqB;IACvB,CAAC;EACH;AACF;AC1BA,cAAc;EACZ,MAAM;EACN,aAAa;EACb,iBAAiB;EACjB,qBAAqB;EACrB,cAAc;EACd,QAAQ,MAAM,IAAI,gBAAgB;AACpC,CAAC;AAED,cAAc;EACZ,MAAM;EACN,iBAAiB;EACjB,qBAAqB;EACrB,cAAc;EACd,QAAQ,MAAM,IAAI,cAAc;AAClC,CAAC;AAED,cAAc;EACZ,MAAM;EACN,iBAAiB;EACjB,qBAAqB;EACrB,cAAc;EACd,QAAQ,MAAM,IAAI,WAAW;AAC/B,CAAC;AAED,cAAc;EACZ,MAAM;EACN,iBAAiB;EACjB,qBAAqB;EACrB,cAAc;EACd,QAAQ,MAAM,IAAI,UAAU;AAC9B,CAAC;AAED,cAAc;EACZ,MAAM;EACN,iBAAiB;EACjB,qBAAqB;EACrB,cAAc;EACd,QAAQ,MAAM,IAAI,cAAc;AAClC,CAAC;AAED,cAAc;EACZ,MAAM;EACN,iBAAiB;EACjB,qBAAqB;EACrB,cAAc;EACd,QAAQ,MAAM,IAAI,WAAW;AAC/B,CAAC;AAED,cAAc;EACZ,MAAM;EACN,iBAAiB;EACjB,qBAAqB;EACrB,cAAc;EACd,QAAQ,MAAM,IAAI,QAAQ;AAC5B,CAAC;AAED,cAAc;EACZ,MAAM;EACN,iBAAiB;EACjB,qBAAqB;EACrB,cAAc;EACd,QAAQ,MAAM,IAAI,YAAY;AAChC,CAAC;AEzEM,SAAS,oBAAoB,OAAuB;AACzD,MAAI,UAAU,IAAK,QAAO;AAC1B,QAAM,UAAU,MAAM,QAAQ,WAAW,EAAE;AAC3C,QAAM,QAAQ,QAAQ,MAAM,QAAQ,EAAE,OAAO,OAAO;AACpD,SAAO,MAAM,GAAG,EAAE,KAAK;AACzB;ACDO,IAAM,SAAqB;EAChC,OAAOU,OAAM;AACX,WAAOd,aAAWc,KAAI;EACxB;EACA,SAASA,OAAM;AACb,QAAI;AACF,aAAOZ,cAAaY,OAAM,MAAM;IAClC,QAAQ;AACN,aAAO;IACT;EACF;EACA,MAAM,KAAK,MAAM,MAAM;AACrB,UAAM,SAAS,UAAU,KAAK,MAAM,EAAE,KAAK,KAAK,KAAK,UAAU,QAAQ,SAAS,IAAK,CAAC;AACtF,WAAO;MACL,QAAQ,OAAO,OAAO,WAAW,WAAW,OAAO,SAAS;MAC5D,UAAU,OAAO,UAAU;IAC7B;EACF;AACF;ACVA,IAAM,YAAY;EAChB;EACA;EACA;EACA;EACA;EACA;EACA;AACF;AAEA,IAAM,sBAAsB,CAAC,gBAAgB,cAAc,gBAAgB;AAE3E,IAAM,aAAa,oBAAI,IAAI,CAAC,QAAQ,cAAc,CAAC;AACnD,IAAM,kBAAkB,CAAC,WAAW,aAAa,WAAW;AAcrD,SAAS,mBAAmB,KAA4B;AAC7D,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,QAAQ,IAAI,KAAK,EAAE,QAAQ,UAAU,EAAE;AAC3C,QAAM,WAAW,MAAM,MAAM,sBAAsB;AACnD,MAAI,SAAU,SAAQ,GAAG,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC;AACnD,UAAQ,MAAM,QAAQ,6BAA6B,EAAE;AACrD,MAAI,CAAC,MAAM,SAAS,GAAG,EAAG,QAAO;AACjC,SAAO,MAAM,YAAY;AAC3B;AAMA,IAAM,wBAAwB,KAAK,KAAK;AAOxC,IAAM,gBAAgB,oBAAI,IAAgC;AAOnD,SAAS,gBAAgB,KAAgC,IAAiC;AAC/F,MAAI,OAAO,OAAQ,QAAO,gBAAgB,KAAK,EAAE;AAEjD,QAAM,MAAM,OAAO;AACnB,QAAM,SAAS,cAAc,IAAI,GAAG;AACpC,MAAI,UAAU,KAAK,IAAI,IAAI,OAAO,aAAa,uBAAuB;AACpE,WAAO,OAAO;EAChB;AACA,QAAM,WAAW,gBAAgB,KAAK,EAAE;AACxC,gBAAc,IAAI,KAAK,EAAE,UAAU,YAAY,KAAK,IAAI,EAAE,CAAC;AAC3D,SAAO;AACT;AAEA,SAAS,gBAAgB,KAAgC,IAAiC;AACxF,MAAI,CAAC,IAAK,QAAO,MAAM;AAEvB,QAAM,UAAU,WAAW,GAAG;AAC9B,QAAM,cAAc,QAAQ,QAAQ,GAAG;AACvC,QAAM,UAAa,WAAQ;AAC3B,QAAM,cAAc,WAAW,OAAO;AACtC,QAAM,OAAO,gBAAgB,UAAU,QAAQ,QAAQ,OAAO,IAAI;AAClE,MAAI,gBAAgB,QAAQ,WAAW,IAAI,WAAW,EAAG,QAAO,MAAM;AACtE,MACE,gBAAgB,WAChB,gBAAgB,KAAK,CAAC,QAAQ,gBAAgB,QAAQ,KAAK,MAAM,GAAG,CAAC,GACrE;AACA,WAAO,MAAM;EACf;AAEA,QAAM,UAAU,YAAY,aAAa,IAAI,OAAO;AACpD,MAAI,SAAS;AACX,UAAM,SAAS,GAAG,MAAM,OAAO,CAAC,UAAU,SAAS,mBAAmB,GAAG,EAAE,KAAK,QAAQ,CAAC;AACzF,QAAI,OAAO,aAAa,GAAG;AACzB,YAAM,aAAa,mBAAmB,OAAO,OAAO,KAAK,CAAC;AAC1D,UAAI,YAAY;AACd,eAAO;UACL,MAAM;UACN,KAAK;UACL,aAAa,kBAAkB,EAAE,MAAM,cAAc,KAAK,YAAY,SAAS,GAAG,CAAC;QACrF;MACF;IACF;AAEA,UAAM,SAAS,GAAG,MAAM,OAAO,CAAC,aAAa,kBAAkB,GAAG,EAAE,KAAK,QAAQ,CAAC;AAClF,QAAI,OAAO,aAAa,GAAG;AACzB,YAAM,MAAM,OAAO,OAAO,KAAK;AAC/B,UAAI,KAAK;AACP,cAAM,MAAM,QAAQ,WAAW,GAAG,IAAI,MAAM,QAAQ,QAAQ,SAAS,GAAG;AACxE,eAAO;UACL,MAAM;UACN;UACA,aAAa,kBAAkB,EAAE,MAAM,kBAAkB,KAAK,SAAS,GAAG,CAAC;QAC7E;MACF;IACF;EACF;AAEA,QAAM,cAAc,gBAAgB,aAAa,IAAI,OAAO;AAC5D,MAAI,aAAa;AACf,WAAO;MACL,MAAM;MACN,KAAK;MACL,aAAa,kBAAkB,EAAE,MAAM,iBAAiB,KAAK,aAAa,GAAG,CAAC;IAChF;EACF;AAEA,MAAI,gBAAgB,SAAS;AAC3B,UAAM,YAAY,+BAA+B,aAAa,MAAM,OAAO;AAC3E,QAAI,UAAW,QAAO;EACxB;AAEA,SAAO;IACL,MAAM;IACN,KAAK;IACL,aAAa,oBAAoB,WAAW;EAC9C;AACF;AAEA,SAAS,QAAyB;AAChC,SAAO,EAAE,MAAM,SAAS,KAAK,SAAS,aAAa,QAAQ;AAC7D;AAEA,SAAS,+BACP,aACA,MACA,SACwB;AACxB,QAAM,OAAO,QAAQ,QAAQ,QAAQ,KAAK,MAAM,aAAa,OAAO,CAAC;AACrE,QAAM,QAAQ,QAAQ,SAAS,MAAM,WAAW;AAChD,MACE,CAAC,SACD,UAAU,QACV,MAAM,WAAW,KAAK,QAAQ,GAAG,EAAE,KACnC,QAAQ,WAAW,KAAK,GACxB;AACA,WAAO;EACT;AACA,SAAO,EAAE,MAAM,aAAa,KAAK,iBAAiB,aAAa,QAAQ;AACzE;AAEA,SAAS,WAAW,OAAwB;AAC1C,MAAI,kBAAkB,KAAK,KAAK,KAAK,MAAM,WAAW,MAAM,KAAK,MAAM,SAAS,IAAI,GAAG;AACrF,WAAY;EACd;AACA,MAAI,MAAM,WAAW,GAAG,EAAG,QAAY;AACvC,SAAO;AACT;AAEA,SAAS,YAAY,OAAe,IAAgB,SAAiC;AACnF,MAAI,UAAU;AACd,SAAO,SAAS;AACd,QAAI,GAAG,OAAO,QAAQ,KAAK,SAAS,MAAM,CAAC,EAAG,QAAO;AACrD,UAAM,SAAS,QAAQ,QAAQ,OAAO;AACtC,QAAI,WAAW,QAAS;AACxB,cAAU;EACZ;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,OAAe,IAAgB,SAAiC;AACvF,MAAI,UAAU;AACd,SAAO,SAAS;AACd,eAAW,YAAY,WAAW;AAChC,UAAI,GAAG,OAAO,QAAQ,KAAK,SAAS,QAAQ,CAAC,EAAG,QAAO;IACzD;AACA,UAAM,SAAS,QAAQ,QAAQ,OAAO;AACtC,QAAI,WAAW,QAAS;AACxB,cAAU;EACZ;AACA,SAAO;AACT;AASA,SAAS,kBAAkB,OAAiC;AAC1D,QAAM,UAAU,WAAW,MAAM,WAAW,MAAM,GAAG;AACrD,QAAM,MAAM,MAAM,YAAY,MAAM,SAAS,kBAAkB,MAAM,MAAM;AAC3E,MAAI,KAAK;AACP,eAAW,YAAY,qBAAqB;AAC1C,YAAM,eAAe,QAAQ,KAAK,KAAK,QAAQ;AAC/C,UAAI,MAAM,GAAG,OAAO,YAAY,GAAG;AACjC,cAAM,OAAO,kBAAkB,UAAU,MAAM,GAAG,SAAS,YAAY,KAAK,EAAE;AAC9E,YAAI,KAAM,QAAO;MACnB;IACF;EACF;AAEA,MAAI,MAAM,SAAS,cAAc;AAC/B,WAAO,MAAM,IAAI,MAAM,GAAG,EAAE,GAAG,EAAE,KAAK,MAAM;EAC9C;AACA,MAAI,MAAM,QAAS,QAAO,oBAAoB,MAAM,OAAO;AAC3D,SAAO,oBAAoB,MAAM,GAAG;AACtC;AAEA,SAAS,kBAAkB,MAAc,MAA6B;AACpE,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,SAAS,kBAAkB,SAAS,gBAAgB,SAAS,kBAAkB;AACjF,UAAM,QAAQ,KAAK,MAAM,wBAAwB,KAAK,KAAK,MAAM,2BAA2B;AAC5F,QAAI,QAAQ,CAAC,EAAG,QAAO,MAAM,CAAC;EAChC;AACA,SAAO;AACT;ACrOO,SAAS,mBAAmB,UAAyC;AAC1E,QAAM,SAAS,oBAAI,IAGjB;AAEF,aAAW,WAAW,UAAU;AAC9B,QAAI,eAAe,OAAO,EAAG;AAC7B,UAAM,WAAW,QAAQ;AACzB,QAAI,CAAC,SAAU;AACf,UAAM,WAAW,QAAQ,gBAAgB,QAAQ;AACjD,UAAM,WAAW,sBAAsB,QAAQ;AAC/C,UAAM,UAAU,OAAO,IAAI,QAAQ;AACnC,QAAI,SAAS;AACX,cAAQ,QAAQ,IAAI,mBAAmB,OAAO,CAAC;AAC/C,cAAQ,gBAAgB;AACxB,cAAQ,eAAe,KAAK,IAAI,QAAQ,cAAc,QAAQ;IAChE,OAAO;AACL,aAAO,IAAI,UAAU;QACnB;QACA,SAAS,oBAAI,IAAI,CAAC,mBAAmB,OAAO,CAAC,CAAC;QAC9C,cAAc;QACd,cAAc;MAChB,CAAC;IACH;EACF;AAEA,SAAO,CAAC,GAAG,OAAO,OAAO,CAAC,EACvB,IAAI,CAAC,WAAW;IACf,cAAc,MAAM,SAAS;IAC7B,aAAa,MAAM,SAAS;IAC5B,aAAa,MAAM,SAAS;IAC5B,SAAS,CAAC,GAAG,MAAM,OAAO,EAAE,KAAK;IACjC,cAAc,MAAM;IACpB,cAAc,MAAM,gBAAgB;EACtC,EAAE,EACD,KAAK,CAAC,GAAG,MAAM;AACd,QAAI,EAAE,iBAAiB,WAAW,EAAE,iBAAiB,QAAS,QAAO;AACrE,QAAI,EAAE,iBAAiB,WAAW,EAAE,iBAAiB,QAAS,QAAO;AACrE,YAAQ,EAAE,gBAAgB,MAAM,EAAE,gBAAgB;EACpD,CAAC;AACL;ACnCO,SAAS,0BACd,WACA,KAAiB,QACI;AACrB,QAAM,WAAW,gBAAgB,WAAW,EAAE;AAC9C,SAAO;IACL,UAAU,EAAE,MAAM,SAAS,MAAM,KAAK,SAAS,IAAI;IACnD,MAAM,mBAAmB,SAAS;EACpC;AACF;AAEO,SAAS,oBAAoB,SAAsB,OAAqC;AAC7F,MAAI,CAAC,QAAQ,UAAW,QAAO;AAC/B,MAAI,uBAAuB,QAAQ,kBAAkB,MAAM,QAAQ,EAAG,QAAO;AAC7E,SAAO,iBAAiB,MAAM,MAAM,QAAQ,SAAS;AACvD;AAEO,SAAS,6BACd,UACA,WACA,IACe;AACf,QAAM,QAAQ,0BAA0B,WAAW,EAAE;AACrD,SAAO,SAAS,OAAO,CAAC,YAAY,oBAAoB,SAAS,KAAK,CAAC;AACzE;AAEA,SAAS,iBAAiB,WAAmB,aAA8B;AACzE,QAAM,UAAU,mBAAmB,WAAW;AAC9C,SACE,YAAY,aACZ,QAAQ,WAAW,YAAY,GAAG,KAClC,UAAU,WAAW,UAAU,GAAG;AAEtC;AAEA,SAAS,mBAAmBA,OAAsB;AAChD,SAAOF,SAAQE,KAAI,EAAE,WAAW,KAAK,GAAG;AAC1C;AC7CA,IAAM,YAAwB;EAC5B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AACF;AAEA,IAAM,aAAwC;EAC5C,CAAC,UAAU,qEAAqE;EAChF,CAAC,eAAe,+DAA+D;EAC/E,CAAC,eAAe,iEAAiE;EACjF,CAAC,QAAQ,kDAAkD;AAC7D;AAEA,IAAM,qBAAqB;AAC3B,IAAM,iBAAiB;AACvB,IAAM,0BACJ;AACF,IAAM,cAAc;AACpB,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,eAAe;AAEd,SAAS,2BACd,SACQ;AACR,SAAO,QAAQ,gBAAgB,QAAQ;AACzC;AAEO,SAAS,oBAAoB,SAAsD;AACxF,QAAM,OAAO,oBAAI,IAAc;AAC/B,MAAI,gBAAgB;AACpB,MAAI,gBAAgB;AAEpB,aAAW,WAAW,QAAQ,UAAU;AACtC,QAAI,QAAQ,SAAS,QAAQ;AAC3B,YAAM,OAAO,QAAQ,MAAM,IAAI,QAAQ,EAAE,KAAK,IAAI;AAClD,iBAAW,CAAC,KAAK,OAAO,KAAK,YAAY;AACvC,YAAI,QAAQ,KAAK,IAAI,EAAG,MAAK,IAAI,GAAG;MACtC;IACF;AAEA,eAAW,QAAQ,QAAQ,OAAO;AAChC,UAAI,KAAK,SAAS,OAAQ,MAAK,IAAI,UAAU;AAC7C,UAAI,KAAK,SAAS,OAAQ;AAE1B,YAAM,WAAW,GAAG,KAAK,IAAI,IAAI,KAAK,SAAS,EAAE;AACjD,YAAM,cAAc,qBAAqB,IAAI;AAE7C,UAAI,aAAa,KAAK,QAAQ,EAAG,MAAK,IAAI,UAAU;AACpD,UAAI,aAAa,KAAK,QAAQ,EAAG,kBAAiB;AAClD,UAAI,aAAa,KAAK,QAAQ,EAAG,kBAAiB;AAElD,UAAI,mBAAmB,KAAK,WAAW,EAAG,MAAK,IAAI,SAAS;AAC5D,UAAI,eAAe,KAAK,WAAW,EAAG,MAAK,IAAI,SAAS;AACxD,UAAI,wBAAwB,KAAK,WAAW,EAAG,MAAK,IAAI,cAAc;AACtE,UAAI,iBAAiB,KAAK,MAAM,KAAK,GAAG;AACtC,aAAK,IAAI,MAAM;MACjB;IACF;EACF;AAEA,MAAI,iBAAiB,KAAK,iBAAiB,GAAG;AAC5C,SAAK,IAAI,aAAa;EACxB;AAEA,SAAO,UAAU,OAAO,CAAC,QAAQ,KAAK,IAAI,GAAG,CAAC;AAChD;AAEA,SAAS,SAAS,MAA2B;AAC3C,SAAO,KAAK,SAAS,UAAU,KAAK,SAAS,eAAe,KAAK,SAAS,SAAS,KAAK,OAAO;AACjG;AAEA,SAAS,qBAAqB,MAAwB;AACpD,SAAO,CAAC,KAAK,MAAM,KAAK,OAAO,YAAY,KAAK,KAAK,CAAC,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;AACnF;AAEA,SAAS,YAAY,OAAwB;AAC3C,MAAI,SAAS,KAAM,QAAO;AAC1B,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAW,QAAO,OAAO,KAAK;AAChF,MAAI;AACF,WAAO,KAAK,UAAU,KAAK;EAC7B,QAAQ;AACN,WAAO;EACT;AACF;AAEA,SAAS,iBAAiB,OAAyB;AACjD,MAAI,SAAS,KAAM,QAAO;AAC1B,MAAI,OAAO,UAAU,SAAU,QAAO,YAAY,KAAK,KAAK;AAC5D,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,KAAK,gBAAgB;AAC5D,MAAI,OAAO,UAAU,SAAU,QAAO;AAEtC,QAAM,SAAS;AACf,aAAW,OAAO,CAAC,QAAQ,QAAQ,YAAY,aAAa,cAAc,aAAa,GAAG;AACxF,UAAM,MAAM,OAAO,GAAG;AACtB,QAAI,OAAO,QAAQ,YAAY,YAAY,KAAK,GAAG,EAAG,QAAO;EAC/D;AAEA,SAAO,OAAO,OAAO,MAAM,EAAE,KAAK,gBAAgB;AACpD;AC9FA,SAASiB,UAAS,OAAgB;AAChC,MAAI,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,GAAG;AAC/D,WAAO;EACT;AACA,SAAO,CAAC;AACV;AAEA,SAAS,cAAc,OAAgB;AACrC,SAAO,OAAO,UAAU,WAAW,QAAQ;AAC7C;AAEA,SAAS,mBAAmB,MAAgB;AAC1C,MAAI,KAAK,OAAO,KAAK,GAAG;AACtB,WAAO,KAAK,MAAM,KAAK,EAAE,QAAQ,cAAc,EAAE;EACnD;AACA,MAAI,KAAK,KAAK,KAAK,EAAG,QAAO,KAAK,KAAK,KAAK;AAC5C,SAAO;AACT;AAEA,SAAS,kBAAkB,MAAgB;AACzC,SAAO,mBAAmB,IAAI,EAAE,KAAK,EAAE,YAAY;AACrD;AAEA,SAAS,kBAAkB,OAAe;AACxC,QAAM,OAAO,MAAM,KAAK;AACxB,MAAI,CAAC,QAAQ,KAAK,SAAS,IAAK,QAAO;AACvC,MAAI,KAAK,SAAS,IAAI,EAAG,QAAO;AAChC,MAAI,gBAAgB,KAAK,IAAI,EAAG,QAAO;AACvC,MAAI,SAAS,KAAK,IAAI,EAAG,QAAO;AAChC,MAAI,KAAK,WAAW,GAAG,EAAG,QAAO;AACjC,MAAI,KAAK,WAAW,IAAI,KAAK,KAAK,WAAW,KAAK,KAAK,KAAK,WAAW,IAAI,EAAG,QAAO;AACrF,MAAI,KAAK,SAAS,GAAG,KAAK,KAAK,SAAS,IAAI,EAAG,QAAO;AACtD,SAAO,qCAAqC,KAAK,IAAI;AACvD;AAEA,SAAS,qBAAqB,KAAa;AACzC,QAAM,aAAa,IAAI,KAAK,EAAE,YAAY;AAC1C,MAAI,CAAC,WAAY,QAAO;AACxB,MACE,WAAW,SAAS,SAAS,KAC7B,WAAW,SAAS,SAAS,KAC7B,WAAW,SAAS,MAAM,KAC1B,WAAW,SAAS,QAAQ,KAC5B,WAAW,SAAS,KAAK,KACzB,WAAW,SAAS,MAAM,KAC1B,WAAW,SAAS,OAAO,KAC3B,WAAW,SAAS,aAAa,KACjC,eAAe,SACf,eAAe,aACf,eAAe,aACf;AACA,WAAO;EACT;AACA,SACE,eAAe,UACf,eAAe,WACf,WAAW,SAAS,MAAM,KAC1B,WAAW,SAAS,MAAM;AAE9B;AAEA,SAAS,sBACP,OACA,SACA,OACA,QAAQ,GACF;AACN,MAAI,SAAS,QAAQ,QAAQ,EAAG;AAEhC,MAAI,OAAO,UAAU,UAAU;AAC7B,QAAI,qBAAqB,OAAO,KAAK,kBAAkB,KAAK,GAAG;AAC7D,YAAM,IAAI,MAAM,KAAK,CAAC;IACxB;AACA;EACF;AAEA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,eAAW,QAAQ,OAAO;AACxB,4BAAsB,MAAM,SAAS,OAAO,QAAQ,CAAC;IACvD;AACA;EACF;AAEA,MAAI,OAAO,UAAU,UAAU;AAC7B,eAAW,CAAC,KAAK,MAAM,KAAK,OAAO,QAAQ,KAAgC,GAAG;AAC5E,4BAAsB,QAAQ,KAAK,OAAO,QAAQ,CAAC;IACrD;EACF;AACF;AAEA,SAAS,0BAA0B,YAAqB;AACtD,QAAM,QAAQ,oBAAI,IAAY;AAC9B,wBAAsB,YAAY,IAAI,KAAK;AAC3C,SAAO,CAAC,GAAG,KAAK;AAClB;AAEA,SAAS,kBAAkB,MAAgB;AACzC,SAAO,KAAK,MAAM,SAAS;AAC7B;AAEA,SAAS,iBAAiB,MAAyC;AACjE,QAAM,WAAW,kBAAkB,IAAI;AACvC,MAAI,aAAa,UAAU,aAAa,cAAc,aAAa,YAAa,QAAO;AACvF,MACE,aAAa,UACb,aAAa,eACb,aAAa,iBACb,aAAa,gBACb;AACA,WAAO;EACT;AACA,MACE,aAAa,WACb,aAAa,eACb,aAAa,gBACb,aAAa,eACb;AACA,WAAO;EACT;AACA,MAAI,aAAa,YAAY,aAAa,eAAe;AACvD,WAAO;EACT;AACA,SAAO;AACT;AAEA,SAAS,yBAAyB,OAAwC;AACxE,QAAM,SAASA,UAAS,KAAK;AAC7B,QAAM,OAAO,cAAc,OAAO,IAAI;AACtC,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO;IACL;IACA,MAAM,cAAc,OAAO,IAAI;IAC/B,SAAS,cAAc,OAAO,QAAQ;EACxC;AACF;AAEA,SAAS,qBAAqB,YAAwC;AACpE,QAAM,QAAQA,UAAS,UAAU;AACjC,QAAM,aAAwB,MAAM,QAAQ,UAAU,IAClD,aACA,MAAM,QAAQ,MAAM,OAAO,IACxB,MAAM,UACP,CAAC;AAEP,SAAO,WACJ,IAAI,CAAC,UAAU,yBAAyB,KAAK,CAAC,EAC9C,OAAO,CAAC,UAAoC,SAAS,IAAI;AAC9D;AAEA,SAAS,eAAe,MAAgC;AACtD,MAAI,SAAS,aAAc,QAAO;AAClC,MAAI,SAAS,cAAe,QAAO;AACnC,SAAO;AACT;AAEO,SAAS,+BACd,UACiC;AACjC,QAAM,cAA+C,CAAC;AAEtD,WAAS,QAAQ,CAAC,SAAS,iBAAiB;AAC1C,QAAI,YAAY;AAEhB,eAAW,QAAQ,QAAQ,OAAO;AAChC,UAAI,KAAK,SAAS,OAAQ;AAE1B,YAAM,aAAa,kBAAkB,IAAI;AACzC,YAAM,YAAY,mBAAmB,IAAI;AACzC,YAAM,OAAO,KAAK,gBAAgB,QAAQ;AAC1C,YAAM,mBAAmB;AACzB,mBAAa;AAEb,YAAM,eAAe,qBAAqB,UAAU;AACpD,UAAI,aAAa,SAAS,GAAG;AAC3B,mBAAW,SAAS,cAAc;AAChC,gBAAMjB,SAAQ,MAAM,QAAQ,MAAM,SAAS,KAAK;AAChD,cAAI,CAACA,MAAM;AACX,sBAAY,KAAK;YACf,MAAAA;YACA,MAAM,eAAe,MAAM,IAAI;YAC/B;YACA,YAAY;YACZ,eAAe;YACf,YAAY;UACd,CAAC;QACH;AACA;MACF;AAEA,YAAM,OAAO,iBAAiB,IAAI;AAClC,UAAI,CAAC,KAAM;AAEX,iBAAWA,SAAQ,0BAA0B,UAAU,GAAG;AACxD,oBAAY,KAAK;UACf,MAAAA;UACA;UACA;UACA,YAAY;UACZ,eAAe;UACf,YAAY;QACd,CAAC;MACH;IACF;EACF,CAAC;AAED,SAAO;AACT;AAEO,SAAS,sBACd,WACA,WACA,oBACA,aACuB;AACvB,QAAM,UAAU,oBAAI,IAAiC;AAErD,aAAW,cAAc,aAAa;AACpC,UAAM,MAAM,GAAG,WAAW,IAAI,KAAK,WAAW,IAAI;AAClD,UAAM,UAAU,QAAQ,IAAI,GAAG;AAC/B,QAAI,SAAS;AACX,cAAQ,SAAS;AACjB,cAAQ,aAAa,KAAK,IAAI,QAAQ,YAAY,WAAW,IAAI;AACjE;IACF;AAEA,YAAQ,IAAI,KAAK;MACf,WAAW,EAAE,WAAW,UAAU;MAClC;MACA,MAAM,WAAW;MACjB,MAAM,WAAW;MACjB,OAAO;MACP,YAAY,WAAW;IACzB,CAAC;EACH;AAEA,SAAO,CAAC,GAAG,QAAQ,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM;AAC1C,QAAI,EAAE,eAAe,EAAE,WAAY,QAAO,EAAE,aAAa,EAAE;AAC3D,WAAO,EAAE,KAAK,cAAc,EAAE,IAAI;EACpC,CAAC;AACH;AAEO,SAAS,2BACd,WACA,WACA,oBACA,UACuB;AACvB,SAAO;IACL;IACA;IACA;IACA,+BAA+B,QAAQ;EACzC;AACF;AEjQA,IAAM,iBAAiB;AACvB,IAAM,wBAAwB;AACvB,IAAM,mCAAmC;AAyBhD,IAAI,oBAAmC;AAEhC,SAAS,uBAAsC;AACpD,SAAO;AACT;AAEO,SAAS,qBAAqBA,OAA2B;AAC9D,sBAAoBA;AACtB;AAEO,SAASkB,eAAsB;AACpC,SAAO5B,OAAKG,SAAQ,GAAG,UAAU,UAAU;AAC7C;AAEO,SAAS0B,gBAAuB;AACrC,SAAO7B,OAAK4B,aAAY,GAAG,cAAc;AAC3C;AAEO,SAAS,qBAA6B;AAC3C,SAAO5B,OAAK4B,aAAY,GAAG,qBAAqB;AAClD;AAEO,SAAS,kBAA2B;AACzC,SAAOhC,aAAWiC,cAAa,CAAC;AAClC;AAEO,SAAS,YAAY,OAAuB;AACjD,SAAO,IAAI,MACR,KAAK,EACL,YAAY,EACZ,QAAQ,WAAW,MAAM,CAAC;AAC/B;AAEO,SAAS,iBAAiB,OAA8B;AAC7D,QAAMnB,QAAO,wBAAwB,KAAK;AAC1C,MAAIA,MAAK,SAAS,EAAG,QAAO;AAC5B,SAAO,IAAIA,MAAK,WAAW,KAAK,IAAI,CAAC;AACvC;AAEO,SAAS,aAAa,OAAuB;AAClD,SAAO,MAAM,QAAQ,uBAAuB,MAAM;AACpD;AAEO,SAAS,wBAAwB,OAAuB;AAC7D,SAAO,MAAM,KAAK,EAAE,QAAQ,UAAU,EAAE;AAC1C;AC/DO,IAAM,+BAA+B;AA0ErC,SAAS,sBAAsB,OAA+B;AACnE,SAAO,SAAS,OAAO,OAAO,KAAK,UAAU,KAAK;AACpD;AAEO,SAAS,kBAAqB,OAA+B;AAClE,SAAO,SAAS,OAAO,SAAa,KAAK,MAAM,OAAO,KAAK,CAAC;AAC9D;AAEO,SAAS,mBAAmB,MAAmD;AACpF,SAAO,OAAO,MAAM,eAAe,WAAW,KAAK,aAAa;AAClE;AAEO,SAAS,uBAAuB,UAAoD;AACzF,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,OAAO,KAAK,MAAM,QAAQ;AAChC,SAAO,mBAAmB,IAAI;AAChC;AAEO,SAAS,qBAAqB,IAAqC;AACxE,SAAO,GAAG,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDjB;AACH;AAEO,SAAS,4BAA4B,IAAqC;AAC/E,SAAO,GAAG,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDjB;AACH;AAEO,SAAS,iBACd,WACA,WACA,SACA,UACA,WACA,YACM;AACN,QAAM,WAAW,QAAQ,oBAAoB,gBAAgB,QAAQ,WAAW,MAAM;AACtF,QAAM,eAAe,QAAQ,gBAAgB,QAAQ;AACrD,YAAU;IACR;IACA,QAAQ;IACR;IACA,QAAQ;IACR,QAAQ;IACR;IACA,QAAQ;IACR,QAAQ,kBAAkB,aAAa;IACvC,QAAQ,kBAAkB,aAAa;IACvC,SAAS;IACT,SAAS;IACT,SAAS;IACT,QAAQ;IACR,QAAQ,gBAAgB;IACxB;IACA,QAAQ,MAAM;IACd,QAAQ,MAAM;IACd,QAAQ,MAAM;IACd,QAAQ,MAAM,2BAA2B;IACzC,QAAQ,MAAM,6BAA6B;IAC3C,QAAQ,MAAM;IACd,QAAQ,MAAM,eAAe;IAC7B,QAAQ,MAAM,gBAAgB;IAC9B,sBAAsB,QAAQ,WAAW;IACzC,sBAAsB,QAAQ,UAAU;IACxC,QAAQ,gCAAgC;IACxC;EACF;AACF;AAEO,SAAS,0BAA0B,IAAqC;AAC7E,SAAO,GAAG,QAAQ;;;;;;;;;;GAUjB;AACH;AAEO,SAAS,yBAAyB,IAAqC;AAC5E,SAAO,GAAG,QAAQ;;;;;;;GAOjB;AACH;AAEO,SAAS,sBACd,WACA,YACM;AACN,aAAW,YAAY,YAAY;AACjC,cAAU;MACR,SAAS,UAAU;MACnB,SAAS,UAAU;MACnB,SAAS;MACT,SAAS;MACT,SAAS;MACT,SAAS;MACT,SAAS;IACX;EACF;AACF;AAEO,SAAS,eAAe,KAA8B;AAC3D,QAAM,UAAuB;IAC3B,IAAI,OAAO,IAAI,UAAU;IACzB,MAAM,OAAO,IAAI,IAAI;IACrB,OAAO,OAAO,IAAI,KAAK;IACvB,WAAW,OAAO,IAAI,SAAS;IAC/B,cAAc,OAAO,IAAI,YAAY;IACrC,OAAO;MACL,eAAe,OAAO,IAAI,iBAAiB,CAAC;MAC5C,oBAAoB,OAAO,IAAI,sBAAsB,CAAC;MACtD,qBAAqB,OAAO,IAAI,uBAAuB,CAAC;MACxD,YAAY,OAAO,IAAI,cAAc,CAAC;IACxC;EACF;AAEA,MAAI,IAAI,sBAAsB;AAC5B,YAAQ,mBAAmB;MACzB,MAAM,IAAI,yBAAyB;MACnC,KAAK,OAAO,IAAI,oBAAoB;MACpC,aAAa,OAAO,IAAI,wBAAwB,EAAE;IACpD;EACF;AACA,MAAI,IAAI,qBAAqB,IAAI,mBAAmB;AAClD,YAAQ,mBAAmB;MACzB,WAAW,OAAO,IAAI,iBAAiB;MACvC,WAAW,OAAO,IAAI,iBAAiB;IACzC;EACF;AACA,MAAI,IAAI,gBAAgB,MAAM;AAC5B,YAAQ,eAAe,OAAO,IAAI,YAAY;EAChD;AACA,MAAI,IAAI,2BAA2B,MAAM;AACvC,YAAQ,MAAM,0BAA0B,OAAO,IAAI,uBAAuB;EAC5E;AACA,MAAI,IAAI,6BAA6B,MAAM;AACzC,YAAQ,MAAM,4BAA4B,OAAO,IAAI,yBAAyB;EAChF;AACA,MAAI,IAAI,aAAa;AACnB,YAAQ,MAAM,cAAc,IAAI;EAClC;AACA,MAAI,IAAI,gBAAgB,MAAM;AAC5B,YAAQ,MAAM,eAAe,OAAO,IAAI,YAAY;EACtD;AAEA,QAAM,aAAa,kBAA0C,IAAI,gBAAgB;AACjF,MAAI,YAAY;AACd,YAAQ,cAAc;EACxB;AAEA,QAAM,YAAY,kBAA6C,IAAI,eAAe;AAClF,MAAI,WAAW;AACb,YAAQ,aAAa;EACvB;AACA,MAAI,IAAI,gCAAgC,MAAM;AAC5C,YAAQ,+BAA+B,OAAO,IAAI,4BAA4B;EAChF;AAEA,SAAO;AACT;AAEA,SAAS,+BAA+B,KAAiD;AACvF,QAAM,OAAO,IAAI,SAAS,eAAe,IAAI,SAAS,SAAS,IAAI,OAAO;AAC1E,SAAO;IACL,IAAI,OAAO,IAAI,cAAc,EAAE;IAC/B;IACA,OAAO,IAAI,SAAS;IACpB,cAAc,OAAO,IAAI,gBAAgB,CAAC;IAC1C,gBAAgB,IAAI,kBAAkB,OAAO,OAAO,OAAO,IAAI,cAAc;IAC7E,MAAM,IAAI,QAAQ;IAClB,OAAO,IAAI,SAAS;IACpB,UAAU,IAAI,YAAY;IAC1B,aAAa,IAAI,eAAe;IAChC,UAAU,IAAI,YAAY;EAC5B;AACF;AAEA,SAAS,6BAA6B,KAA+C;AACnF,QAAM,UAAU,+BAA+B,GAAG;AAClD,QAAM,SAAS,kBAAqC,IAAI,WAAW;AACnE,MAAI,QAAQ;AACV,YAAQ,SAAS;EACnB;AACA,MAAI,IAAI,QAAQ,MAAM;AACpB,YAAQ,OAAO,OAAO,IAAI,IAAI;EAChC;AACA,MAAI,IAAI,aAAa;AACnB,YAAQ,cAAc,IAAI;EAC5B;AACA,SAAO;AACT;AAEO,SAAS,uBAAuB,KAAkC;AACvE,SAAO;IACL,GAAG,+BAA+B,GAAG;IACrC,OAAO,qBAAqB,IAAI,UAAU;EAC5C;AACF;AAEO,SAAS,qBAAqB,KAAgC;AACnE,SAAO;IACL,GAAG,6BAA6B,GAAG;IACnC,OAAO,qBAAqB,IAAI,UAAU;EAC5C;AACF;AAEA,SAAS,qBAAqB,OAA+B;AAC3D,MAAI;AACF,WAAO,sBAAsB,KAAK,MAAM,OAAO,SAAS,IAAI,CAAC,CAAC;EAChE,QAAQ;AACN,WAAO,CAAC;EACV;AACF;AAEO,SAAS,0BAA0B,OAAwB;AAChE,SAAO,KAAK,UAAU,qBAAqB,KAAK,CAAC;AACnD;AAEO,SAAS,yBAAyB,KAA+B;AACtE,QAAM,eAAe,KAAK,UAAU,+BAA+B,GAAG,CAAC;AACvE,QAAM,SAAmB,CAAC;AAC1B,MAAI,IAAI,eAAe,MAAM;AAC3B,WAAO,KAAK,YAAY,OAAO,IAAI,WAAW,CAAC,EAAE;EACnD;AACA,MAAI,IAAI,QAAQ,MAAM;AACpB,WAAO,KAAK,UAAU,KAAK,UAAU,OAAO,IAAI,IAAI,CAAC,CAAC,EAAE;EAC1D;AACA,MAAI,IAAI,aAAa;AACnB,WAAO,KAAK,iBAAiB,KAAK,UAAU,IAAI,WAAW,CAAC,EAAE;EAChE;AACA,QAAM,YACJ,OAAO,IAAI,oBAAoB,KAAK,+BAChC,OAAO,IAAI,cAAc,IAAI,IAC7B,0BAA0B,IAAI,UAAU;AAC9C,SAAO,KAAK,WAAW,SAAS,EAAE;AAClC,SAAO,GAAG,aAAa,MAAM,GAAG,EAAE,CAAC,IAAI,OAAO,KAAK,GAAG,CAAC;AACzD;AAEO,SAAS,gBAAgB,OAAgB,QAAwB;AACtE,MAAI,SAAS,KAAM;AAEnB,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,aAAa,MAAM,KAAK;AAC9B,QAAI,YAAY;AACd,aAAO,KAAK,UAAU;IACxB;AACA;EACF;AAEA,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,WAAW;AAC3D,WAAO,KAAK,OAAO,KAAK,CAAC;AACzB;EACF;AAEA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,eAAW,QAAQ,OAAO;AACxB,sBAAgB,MAAM,MAAM;IAC9B;AACA;EACF;AAEA,MAAI,OAAO,UAAU,UAAU;AAC7B,eAAW,UAAU,OAAO,OAAO,KAAgC,GAAG;AACpE,sBAAgB,QAAQ,MAAM;IAChC;EACF;AACF;AAEO,SAAS,cAAc,QAA0D;AACtF,SAAO,OAAO,YAAY,OAAO,QAAQ,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,SAAS,IAAI,CAAC;AACvF;AAEO,SAASoB,mBAAkB,OAA+B;AAC/D,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,OAAO,MAAM,KAAK,EAAE,YAAY;AACtC,SAAO,QAAQ;AACjB;AAEO,SAAS,0BAA0B,OAA0B;AAClE,MAAI,CAAC,MAAO,QAAO,CAAC;AAEpB,MAAI;AACF,UAAM,WAAW,KAAK,MAAM,OAAO,KAAK,CAAC;AACzC,QAAI,CAAC,MAAM,QAAQ,QAAQ,EAAG,QAAO,CAAC;AACtC,UAAM,QAAQ,oBAAI,IAAY;AAC9B,eAAW,QAAQ,UAAU;AAC3B,UAAI,QAAQ,QAAQ,OAAO,SAAS,SAAU;AAC9C,YAAM,WAAWA,mBAAmB,KAAiC,IAAI;AACzE,UAAI,SAAU,OAAM,IAAI,QAAQ;IAClC;AACA,WAAO,CAAC,GAAG,KAAK;EAClB,QAAQ;AACN,WAAO,CAAC;EACV;AACF;AAEO,SAAS,qBAAqB,SAA4B;AAC/D,QAAM,QAAQ,oBAAI,IAAY;AAC9B,aAAW,QAAQ,QAAQ,OAAO;AAChC,QAAI,KAAK,SAAS,OAAQ;AAC1B,UAAM,WAAWA,mBAAkB,KAAK,IAAI;AAC5C,QAAI,SAAU,OAAM,IAAI,QAAQ;EAClC;AACA,SAAO,CAAC,GAAG,KAAK;AAClB;AAEO,SAAS,kBAAkB,MAAyC;AACzE,QAAM,QAAQ,cAAc;IAC1B,QAAQ,KAAK,MAAM;IACnB,OAAO,KAAK,MAAM;IAClB,UAAU,KAAK,MAAM;EACvB,CAAC;AACD,SAAO,cAAc;IACnB,MAAM,KAAK;IACX,MAAM,KAAK;IACX,OAAO,KAAK;IACZ,QAAQ,KAAK;IACb;EACF,CAAC;AACH;AAEO,SAAS,iBAAiB,SAA0B;AACzD,QAAM,SAAmB,CAAC;AAE1B,SAAO,KAAK,QAAQ,IAAI;AACxB,kBAAgB,QAAQ,OAAO,MAAM;AACrC,kBAAgB,QAAQ,OAAO,MAAM;AAErC,aAAW,QAAQ,QAAQ,OAAO;AAChC,oBAAgB,KAAK,MAAM,MAAM;AACjC,QAAI,KAAK,SAAS,UAAU,KAAK,SAAS,eAAe,KAAK,SAAS,QAAQ;AAC7E,sBAAgB,KAAK,MAAM,MAAM;IACnC,WAAW,KAAK,SAAS,QAAQ;AAC/B,sBAAgB,KAAK,OAAO,MAAM;AAClC,sBAAgB,KAAK,MAAM,MAAM;AACjC,sBAAgB,KAAK,OAAO,MAAM;IACpC;EACF;AAEA,SAAO,OAAO,KAAK,IAAI;AACzB;AAEO,SAAS,kBAAkB,SAAmD;AACnF,SAAO,QAAQ,SAAS,IAAI,CAAC,SAAS,UAAU;AAC9C,UAAM,eAAe,QAAQ,MAC1B,OAAO,CAAC,SAA2B,KAAK,SAAS,MAAM,EACvD,IAAI,CAAC,SAAS,kBAAkB,IAAI,CAAC;AAExC,WAAO;MACL;MACA,IAAI,QAAQ,MAAM,GAAG,QAAQ,EAAE,IAAI,KAAK;MACxC,MAAM,QAAQ;MACd,aAAa,QAAQ;MACrB,eAAe,QAAQ,kBAAkB;MACzC,OAAO,QAAQ,SAAS;MACxB,MAAM,QAAQ,QAAQ;MACtB,OAAO,QAAQ,SAAS;MACxB,UAAU,QAAQ,YAAY;MAC9B,YAAY,sBAAsB,QAAQ,MAAM;MAChD,MAAM,QAAQ,QAAQ;MACtB,YAAY,QAAQ,eAAe;MACnC,WAAW,KAAK,UAAU,QAAQ,KAAK;MACvC,YAAY,QAAQ,eAAe;MACnC,UAAU,QAAQ,YAAY;MAC9B,aAAa,iBAAiB,OAAO;MACrC,kBAAkB,aAAa,SAAS,IAAI,KAAK,UAAU,YAAY,IAAI;MAC3E,WAAW,qBAAqB,OAAO;IACzC;EACF,CAAC;AACH;AAEO,SAAS,gCACd,OACA,UACQ;AACR,QAAM,SAAmB,CAAC;AAC1B,kBAAgB,OAAO,MAAM;AAC7B,aAAW,WAAW,UAAU;AAC9B,oBAAgB,QAAQ,aAAa,MAAM;EAC7C;AACA,SAAO,OAAO,KAAK,IAAI;AACzB;AC9iBA,IAAM,uBAAuB;AAsCtB,SAAS,YAAe,IAAyC;AACtE,QAAM,YAAYD,cAAa;AAC/B,QAAM,KAAK,OAAO,SAAS;AAC3B,MAAI,CAAC,GAAI,QAAO;AAEhB,MAAI;AACF,QAAI,qBAAqB,MAAM,WAAW;AACxC,mBAAa,IAAI,SAAS;AAC1B,2BAAqB,SAAS;IAChC;AACA,WAAO,GAAG,EAAE;EACd,SAAS,OAAO;AACd,uBAAmB,GAAG,KAAK,sBAAsB;MAC/C,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAChE,CAAC;AACD,WAAO;EACT,UAAA;AACE,OAAG,MAAM;EACX;AACF;AAEO,SAAS,oBAAuB,IAAyC;AAC9E,QAAM,KAAK,eAAeA,cAAa,CAAC;AACxC,MAAI,CAAC,GAAI,QAAO;AAEhB,MAAI;AACF,WAAO,GAAG,EAAE;EACd,QAAQ;AACN,WAAO;EACT,UAAA;AACE,OAAG,MAAM;EACX;AACF;AAEO,SAAS,aAAgB,IAAyC;AACvE,SAAO,YAAY,CAAC,OAAO,mBAAmB,IAAI,EAAE,CAAC;AACvD;AAEO,SAAS,kBAAqB,IAAyC;AAC5E,SAAO,YAAY,CAAC,OAAO,mBAAmB,IAAI,EAAE,CAAC;AACvD;AAOO,SAAS,oBACd,IACA,SACA,OAC2B;AAC3B,SAAO,GAAG,YAAY,MAAM;AAC1B,QAAI,SAAS;AACX,yBAAmB,EAAE;AACrB,gCAA0B,EAAE;IAC9B;AAEA,UAAM,QAAQ,MAAM;AACpB,QAAI;AAEJ,QAAI,SAAS;AACX,YAAM,mBAAmB,YAAY,IAAI;AACzC,yBAAmB,EAAE;AACrB,gCAA0B,EAAE;AAC5B,0BAAoB,YAAY,IAAI,IAAI;AACxC,2BAAqB,EAAE;AACvB,kCAA4B,EAAE;IAChC;AAEA,WAAO,EAAE,OAAO,kBAAkB;EACpC,CAAC,EAAE;AACL;AAEA,SAAS,kBAAkB,IAA0B;AACnD,KAAG,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BP;AACH;AAEA,SAAS,oBAAoB,IAA0B;AACrD,KAAG,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEP;AAED,0BAAwB,EAAE;AAC5B;AAEA,SAAS,wBAAwB,IAA0B;AACzD,KAAG,KAAK;;;;;;;;;;;;;;GAcP;AACH;AAEA,SAAS,0BAA0B,IAA0B;AAC3D,MAAI,CAAC,YAAY,IAAI,UAAU,GAAG;AAChC,wBAAoB,EAAE;EACxB;AAEA,KAAG,KAAK;;;;;;GAMP;AAED,8BAA4B,EAAE;AAChC;AAEA,SAAS,4BAA4B,IAA0B;AAC7D,KAAG,KAAK;;;;;;;;;;;;;;;;;GAiBP;AACH;AAEA,SAAS,0BAA0B,IAA0B;AAC3D,KAAG,KAAK;;;;GAIP;AACH;AAEA,SAAS,yBAAyB,IAA0B;AAC1D,KAAG,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCP;AAED,qCAAmC,EAAE;AACvC;AAEA,SAAS,mCAAmC,IAA0B;AACpE,KAAG,KAAK;;;;;;;GAOP;AAED,uCAAqC,EAAE;AACzC;AAEA,SAAS,qCAAqC,IAA0B;AACtE,KAAG,KAAK;;;;;;;;;;;;;;;;;;;;GAoBP;AACH;AAEA,SAAS,6BAA6B,IAA0B;AAC9D,MAAI,CAAC,YAAY,IAAI,gCAAgC,GAAG;AACtD;EACF;AACA,KAAG;IACD;EACF;AACF;AAEA,SAAS,mBAAmB,IAA0B;AACpD,KAAG,KAAK;;;;;;;;;;;;;;;;;;;GAmBP;AAED,uBAAqB,EAAE;AACzB;AAEA,SAAS,qBAAqB,IAA0B;AACtD,KAAG,KAAK;;;;;;;;;;;;;;;;;GAiBP;AACH;AAEA,SAAS,uBAAuB,IAA0B;AACxD,MAAI,CAAC,YAAY,IAAI,mBAAmB,EAAG;AAE3C,MAAI,CAAC,aAAa,IAAI,qBAAqB,uBAAuB,GAAG;AACnE,OAAG;MACD;IACF;EACF;AACA,MAAI,CAAC,YAAY,IAAI,UAAU,EAAG;AAElC,KAAG,KAAK;;;;;;;;GAQP;AACH;AAEA,SAAS,mBAAmB,IAA0B;AACpD,KAAG,KAAK;;;;GAIP;AACH;AAEA,IAAM,kCAAkC;EACtC,CAAC,QAAQ,0BAA0B;EACnC,CAAC,aAAa,0BAA0B;EACxC,CAAC,gBAAgB,4BAA4B;EAC7C,CAAC,gBAAgB,SAAS;EAC1B,CAAC,iBAAiB,4BAA4B;EAC9C,CAAC,yBAAyB,8BAA8B;EACxD,CAAC,wBAAwB,0BAA0B;EACnD,CAAC,wBAAwB,0BAA0B;AACrD;AAEA,SAAS,mCAAmC,IAA0B;AACpE,MAAI,CAAC,YAAY,IAAI,mBAAmB,GAAG;AACzC;EACF;AAEA,aAAW,CAAC,MAAM,UAAU,KAAK,iCAAiC;AAChE,QAAI,CAAC,aAAa,IAAI,qBAAqB,IAAI,GAAG;AAChD,SAAG,KAAK,4CAA4C,IAAI,IAAI,UAAU,EAAE;IAC1E;EACF;AACF;AAEA,SAAS,oBAAoB,IAA0B;AACrD,KAAG,KAAK;;;;;;;;;;;;;;GAcP;AACD,0BAAwB,EAAE;AAC5B;AAEA,SAAS,wBAAwB,IAA0B;AACzD,MAAI,CAAC,YAAY,IAAI,UAAU,GAAG;AAChC,OAAG,KAAK;;;;;;;;;;;KAWP;AACD;EACF;AAEA,QAAM,qBACJ,aAAa,IAAI,YAAY,mBAAmB,KAChD,aAAa,IAAI,YAAY,mBAAmB;AAClD,KAAG,KAAK;;;;;;;;;;QAUF,qBAAqB,iEAAiE,EAAE;;GAE7F;AACH;AAEA,SAAS,0BAA0B,IAA0B;AAC3D,KAAG,KAAK,sCAAsC;AAC9C,0BAAwB,EAAE;AAC5B;AAEA,SAAS,wBAAwB,IAA0B;AACzD,oBAAkB,EAAE;AACpB,sBAAoB,EAAE;AACtB,2BAAyB,EAAE;AAC3B,sBAAoB,EAAE;AACtB,iBAAe,EAAE;AACnB;AAEA,SAAS,0BAA0B,IAA0B;AAC3D,KAAG,KAAK;;;;;GAKP;AACD,qBAAmB,EAAE;AACrB,qBAAmB,EAAE;AACvB;AAEA,SAAS,uBAAuB,IAA4B;AAC1D,MACE,CAAC,YAAY,IAAI,YAAY,KAC7B,CAAC,aAAa,IAAI,cAAc,KAAK,KACrC,CAAC,aAAa,IAAI,cAAc,OAAO,GACvC;AACA,WAAO;EACT;AAEA,QAAM,aAAa,GAAG,QAAQ,oDAAoD,EAAE,IAAI;AAGxF,SAAO,OAAO,YAAY,SAAS,CAAC;AACtC;AAEA,SAAS,wBAAwB,IAA4B;AAC3D,MAAI,aAAa,IAAI,qBAAqB,uBAAuB,GAAG;AAClE,WAAO,aAAa,IAAI,qBAAqB,MAAM,IAAI,KAAK;EAC9D;AACA,MAAI,YAAY,IAAI,eAAe,GAAG;AACpC,WAAO;EACT;AACA,MAAI,YAAY,IAAI,gCAAgC,GAAG;AACrD,WAAO;EACT;AACA,MAAI,YAAY,IAAI,cAAc,GAAG;AACnC,WAAO;EACT;AACA,MAAI,YAAY,IAAI,uBAAuB,GAAG;AAC5C,WAAO;EACT;AACA,MAAI,YAAY,IAAI,UAAU,KAAK,YAAY,IAAI,UAAU,GAAG;AAC9D,WAAO;EACT;AACA,MACE,YAAY,IAAI,kBAAkB,KAClC,aAAa,IAAI,qBAAqB,sBAAsB,GAC5D;AACA,WAAO;EACT;AACA,MAAI,YAAY,IAAI,mBAAmB,GAAG;AACxC,WAAO;EACT;AACA,MAAI,YAAY,IAAI,iBAAiB,KAAK,YAAY,IAAI,aAAa,GAAG;AACxE,WAAO;EACT;AACA,SAAO;AACT;AAEA,SAAS,6BAA6B,IAA4B;AAChE,QAAM,cAAc,eAAe,EAAE;AACrC,MAAI,cAAc,GAAG;AACnB,WAAO;EACT;AAEA,QAAM,gBAAgB,uBAAuB,EAAE;AAC/C,SAAO,KAAK,IAAI,eAAe,wBAAwB,EAAE,CAAC;AAC5D;AAEA,SAAS,kBAAkB,IAA6B;AACtD,SAAO;IACL;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;EACF,EAAE,KAAK,CAAC,UAAU,YAAY,IAAI,KAAK,CAAC;AAC1C;AAEA,SAAS,wBAAwB,IAA0B;AACzD,MAAI,CAAC,YAAY,IAAI,iBAAiB,KAAK,CAAC,YAAY,IAAI,kBAAkB,GAAG;AAC/E;EACF;AAEA,QAAM,OAAO,GACV,QAAQ,kEAAkE,EAC1E,IAAI;AACP,QAAM,SAAS,GAAG,QAAQ;;;;;;;;;;;;;;;;GAgBzB;AAED,aAAW,OAAO,MAAM;AACtB,QAAI,CAAC,IAAI,gBAAgB,CAAC,IAAI,cAAc,CAAC,IAAI,YAAY;AAC3D;IACF;AAEA,QAAI;AACF,YAAM,UAAU,KAAK,MAAM,IAAI,YAAY;AAC3C,YAAM,WAAW,QAAQ,oBAAoB,gBAAgB,QAAQ,WAAW,MAAM;AACtF,aAAO;QACL,IAAI;QACJ,IAAI;QACJ,SAAS;QACT,SAAS;QACT,SAAS;QACT,QAAQ;QACR,QAAQ,gBAAgB,QAAQ;MAClC;IACF,QAAQ;AACN;IACF;EACF;AACF;AAEA,SAAS,gCAAgC,IAA0B;AACjE,MACE,CAAC,YAAY,IAAI,mBAAmB,KACpC,CAAC,aAAa,IAAI,qBAAqB,sBAAsB,GAC7D;AACA;EACF;AAEA,QAAM,OAAO,GACV,QAAQ,6CAA6C,EACrD,IAAI;AACP,QAAM,SAAS,GAAG,QAAQ;;;;;;;GAOzB;AAED,aAAW,OAAO,MAAM;AACtB,UAAM,WAAW,gBAAgB,OAAO,IAAI,aAAa,EAAE,GAAG,MAAM;AACpE,WAAO,IAAI,SAAS,MAAM,SAAS,KAAK,SAAS,aAAa,OAAO,IAAI,EAAE,CAAC;EAC9E;AACF;AAEA,SAAS,uBAAuB,IAA0B;AACxD,qCAAmC,EAAE;AACrC,sBAAoB,EAAE;AACtB,0BAAwB,EAAE;AAC1B,kCAAgC,EAAE;AACpC;AAEA,SAAS,yBAAyB,IAA0B;AAC1D,MACE,YAAY,IAAI,UAAU,KAC1B,aAAa,IAAI,YAAY,sBAAsB,KACnD,aAAa,IAAI,YAAY,WAAW,GACxC;AACA,UAAM,OAAO,GACV,QAAQ,wDAAwD,EAChE,IAAI;AACP,UAAM,SAAS,GAAG,QAAQ;;;;;;;KAOzB;AACD,UAAM,qBACJ,YAAY,IAAI,uBAAuB,KACvC,aAAa,IAAI,yBAAyB,sBAAsB,IAC5D,GAAG,QAAQ;;;;WAIV,IACD;AAEN,eAAW,OAAO,MAAM;AACtB,YAAM,WAAW,gBAAgB,OAAO,IAAI,aAAa,EAAE,GAAG,MAAM;AACpE,aAAO,IAAI,SAAS,MAAM,SAAS,KAAK,SAAS,aAAa,IAAI,YAAY,IAAI,UAAU;AAC5F,0BAAoB,IAAI,SAAS,KAAK,IAAI,YAAY,IAAI,UAAU;IACtE;EACF;AAEA,MACE,YAAY,IAAI,kBAAkB,KAClC,aAAa,IAAI,oBAAoB,cAAc,KACnD,aAAa,IAAI,oBAAoB,WAAW,GAChD;AACA,UAAM,OAAO,GACV,QAAQ,gEAAgE,EACxE,IAAI;AACP,UAAM,SAAS,GAAG,QAAQ;;;;;;;KAOzB;AAED,eAAW,OAAO,MAAM;AACtB,YAAM,WAAW,gBAAgB,OAAO,IAAI,aAAa,EAAE,GAAG,MAAM;AACpE,aAAO,IAAI,SAAS,MAAM,SAAS,KAAK,SAAS,aAAa,IAAI,YAAY,IAAI,UAAU;IAC9F;EACF;AAEA,kCAAgC,EAAE;AAClC,4BAA0B,EAAE;AAC9B;AAEA,SAAS,2BAA2B,IAA0B;AAC5D,sBAAoB,EAAE;AACtB,4BAA0B,EAAE;AAC5B,QAAM,gBAAgB,qBAAqB,EAAE;AAE7C,MAAI,YAAY,IAAI,iBAAiB,GAAG;AACtC,UAAM,OAAO,GACV;MACC;IACF,EACC,IAAI;AAEP,eAAW,OAAO,MAAM;AACtB,UAAI,CAAC,IAAI,cAAc,CAAC,IAAI,cAAc;AACxC;MACF;AAEA,UAAI;AACF,cAAM,UAAU,KAAK,MAAM,IAAI,YAAY;AAC3C;UACE;UACA,OAAO,IAAI,UAAU;UACrB;UACA,IAAI,aAAa;UACjB,OAAO,IAAI,cAAc,CAAC;UAC1B,uBAAuB,IAAI,SAAS;QACtC;MACF,QAAQ;AACN;MACF;IACF;EACF;AAEA,MAAI,CAAC,YAAY,IAAI,mBAAmB,GAAG;AACzC;EACF;AAEA,QAAM,eAAe,GAClB;IACC;;;;;;;;;;;;;;;;;;;EAmBF,EACC,IAAI;AAEP,aAAW,OAAO,cAAc;AAC9B,UAAM,YAAY,OAAO,IAAI,aAAa,EAAE;AAC5C,UAAM,WACJ,IAAI,wBAAwB,IAAI,yBAAyB,IAAI,uBACzD;MACE,MAAM,IAAI;MACV,KAAK,OAAO,IAAI,oBAAoB;MACpC,aAAa,OAAO,IAAI,oBAAoB;IAC9C,IACA,gBAAgB,WAAW,MAAM;AAEvC;MACE;MACA,OAAO,IAAI,UAAU;MACrB;QACE,IAAI,OAAO,IAAI,UAAU;QACzB,MAAM,OAAO,IAAI,IAAI;QACrB,OAAO,OAAO,IAAI,KAAK;QACvB;QACA,kBAAkB;QAClB,cAAc,OAAO,IAAI,gBAAgB,IAAI,iBAAiB,CAAC;QAC/D,cAAc,IAAI,gBAAgB,OAAO,SAAY,OAAO,IAAI,YAAY;QAC5E,OAAO;UACL,eAAe;UACf,oBAAoB;UACpB,qBAAqB;UACrB,YAAY;QACd;MACF;MACA;MACA,OAAO,IAAI,MAAM,CAAC;MAClB;IACF;EACF;AACF;AAEA,SAAS,qBAAqB,IAA0B;AACtD,0BAAwB,EAAE;AAC1B,MAAI,CAAC,YAAY,IAAI,UAAU,GAAG;AAChC;EACF;AAEA,KAAG,KAAK,2BAA2B;AACnC,QAAM,OAAO,GACV;IACC;;;;;EAKF,EACC,IAAI;AACP,QAAM,aAAa,yBAAyB,EAAE;AAE9C,aAAW,OAAO,MAAM;AACtB,QAAI,CAAC,IAAI,cAAc,CAAC,IAAI,cAAc,IAAI,iBAAiB,MAAM;AACnE;IACF;AAEA,eAAW,YAAY,0BAA0B,IAAI,kBAAkB,GAAG;AACxE,iBAAW,IAAI,IAAI,YAAY,IAAI,YAAY,IAAI,eAAe,QAAQ;IAC5E;EACF;AACF;AAEA,SAAS,qBAAqB,IAA0B;AACtD,2BAAyB,EAAE;AAC3B,MAAI,CAAC,YAAY,IAAI,UAAU,KAAK,CAAC,YAAY,IAAI,UAAU,GAAG;AAChE;EACF;AAEA,QAAM,WAAW,GACd;IACC;;;;;EAKF,EACC,IAAI;AACP,QAAM,eAAe,GAAG,QAAQ;;;;;;;;;;;;;;;;GAgB/B;AACD,QAAM,iBAAiB,GAAG;IACxB;EACF;AACA,QAAM,iBAAiB,0BAA0B,EAAE;AAEnD,aAAW,WAAW,UAAU;AAC9B,QAAI,CAAC,QAAQ,cAAc,CAAC,QAAQ,cAAc,CAAC,QAAQ,sBAAsB;AAC/E;IACF;AAEA,QAAI;AACF,YAAM,OAAO,aAAa,IAAI,QAAQ,YAAY,QAAQ,UAAU;AACpE,YAAM,WAAW,KAAK,IAAI,CAAC,QAAQ,uBAAuB,GAAG,CAAC;AAC9D,YAAM,aAAa;QACjB,OAAO,QAAQ,UAAU;QACzB,OAAO,QAAQ,UAAU;QACzB,OAAO,QAAQ,oBAAoB;QACnC;MACF;AACA,qBAAe,IAAI,QAAQ,YAAY,QAAQ,UAAU;AACzD,4BAAsB,gBAAgB,UAAU;IAClD,QAAQ;AACN;IACF;EACF;AACF;AAEA,SAAS,8BAA8B,IAA0B;AAC/D,MACE,YAAY,IAAI,mBAAmB,KACnC,aAAa,IAAI,qBAAqB,cAAc,GACpD;AACA,OAAG,KAAK,gDAAgD;EAC1D;AACF;AAEA,SAAS,wBAAwB,IAA0B;AACzD,MAAI,CAAC,YAAY,IAAI,mBAAmB,GAAG;AACzC,uBAAmB,EAAE;AACrB;EACF;AAEA,qBAAmB,EAAE;AACrB,KAAG,KAAK;;;;GAIP;AACD,qBAAmB,EAAE;AACrB,KAAG,KAAK;;;;;;;;;;;;;;;;;;;;;;;GAuBP;AACH;AAEA,SAAS,6BAA6B,IAA0B;AAC9D,MAAI,CAAC,YAAY,IAAI,UAAU,KAAK,aAAa,IAAI,YAAY,sBAAsB,GAAG;AACxF;EACF;AACA,KAAG,KAAK,iFAAiF;AAC3F;AAEA,SAAS,0BAA0B,IAA0B;AAC3D,MAAI,CAAC,YAAY,IAAI,UAAU,EAAG;AAElC,MAAI,CAAC,aAAa,IAAI,YAAY,mBAAmB,GAAG;AACtD,OAAG,KAAK,wDAAwD;EAClE;AACA,MAAI,CAAC,aAAa,IAAI,YAAY,mBAAmB,GAAG;AACtD,OAAG,KAAK,wDAAwD;EAClE;AACA,KAAG;IACD;EACF;AACA,4BAA0B,EAAE;AAC9B;AAEA,IAAM,kCAAkC;AAaxC,SAAS,uBAAuB,IAA0B;AACxD,MAAI,CAAC,YAAY,IAAI,YAAY,EAAG;AACpC,QAAM,OAAO,GACV,QAAQ,4CAA4C,EACpD,IAAI,+BAA+B;AACtC,MAAI,KAAM;AAEV,MAAI,YAAY,IAAI,UAAU,KAAK,YAAY,IAAI,iBAAiB,GAAG;AACrE,OAAG;MACD;IAEF;EACF;AACA,KAAG;IACD;EACF,EAAE,IAAI,+BAA+B;AACvC;AAEA,IAAM,6BAA6B;AACnC,IAAM,oBAAoB;AAO1B,SAAS,4BAA4B,IAA0B;AAC7D,MAAI,CAAC,YAAY,IAAI,YAAY,EAAG;AACpC,QAAM,OAAO,GACV,QAAQ,4CAA4C,EACpD,IAAI,0BAA0B;AACjC,MAAI,KAAM;AAEV,MAAI,YAAY,IAAI,aAAa,GAAG;AAClC,OAAG,QAAQ,mEAAmE,EAAE,IAAI;EACtF;AACA,KAAG;IACD;EACF,EAAE,IAAI,0BAA0B;AAClC;AAEA,SAAS,oBAAoB,IAA0B;AACrD,MAAI,CAAC,YAAY,IAAI,YAAY,EAAG;AACpC,QAAM,OAAO,GAAG,QAAQ,4CAA4C,EAAE,IAAI,iBAAiB;AAC3F,MAAI,KAAM;AAEV,MAAI,YAAY,IAAI,aAAa,GAAG;AAClC,OAAG,QAAQ,4EAA4E,EAAE,IAAI;EAC/F;AACA,KAAG;IACD;EACF,EAAE,IAAI,iBAAiB;AACzB;AAEA,SAAS,mBAAmB,IAA0B;AACpD,MAAI,CAAC,YAAY,IAAI,uBAAuB,GAAG;AAC7C;EACF;AACA,KAAG,KAAK,6EAA6E;AACvF;AAEA,SAAS,0BAA0B,IAA0B;AAC3D,MAAI,CAAC,YAAY,IAAI,cAAc,GAAG;AACpC;EACF;AACA,KAAG,KAAK,2DAA2D;AACrE;AAEA,IAAM,qBAAqB,CAAC,yBAAyB,cAAc;AAInE,SAAS,cAAc,IAAoB,aAA8B;AACvE,SACE,GACG,QAAQ,kFAAkF,EAC1F,IAAI,WAAW,MAAM;AAE5B;AAEA,SAAS,eAAe,IAAoB,cAAiC;AAC3E,SAAO,aAAa,MAAM,CAAC,gBAAgB,cAAc,IAAI,WAAW,CAAC;AAC3E;AAEA,SAAS,wBACP,IACA,SACA,QACM;AACN,MAAI,QAAQ,WAAW,EAAG;AAE1B,QAAM,YAAY,YAAY,IAAI;AAClC,qBAAmB,GAAG,OAAO,8BAA8B,EAAE,SAAS,OAAO,CAAC;AAC9E,MAAI;AACF,eAAW,SAAS,SAAS;AAC3B,UAAI,UAAU,wBAAyB,oBAAmB,EAAE;UACvD,2BAA0B,EAAE;IACnC;AACA,uBAAmB,GAAG,OAAO,gCAAgC;MAC3D;MACA;MACA,aAAa,KAAK,MAAM,YAAY,IAAI,IAAI,SAAS;IACvD,CAAC;EACH,SAAS,OAAO;AACd,uBAAmB,GAAG,KAAK,6BAA6B;MACtD;MACA;MACA,aAAa,KAAK,MAAM,YAAY,IAAI,IAAI,SAAS;MACrD,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAChE,CAAC;AACD,UAAM;EACR;AACF;AAEA,SAAS,eAAe,IAA0B;AAChD,QAAM,qBACJ,CAAC,YAAY,IAAI,uBAAuB,KACxC,CAAC,eAAe,IAAI,CAAC,wBAAwB,wBAAwB,sBAAsB,CAAC;AAC9F,QAAM,4BACJ,CAAC,YAAY,IAAI,cAAc,KAC/B,CAAC,eAAe,IAAI,CAAC,eAAe,eAAe,aAAa,CAAC;AAEnE,qBAAmB,EAAE;AACrB,4BAA0B,EAAE;AAE5B,QAAM,UAA4B,CAAC;AACnC,MAAI,mBAAoB,SAAQ,KAAK,uBAAuB;AAC5D,MAAI,0BAA2B,SAAQ,KAAK,cAAc;AAC1D,0BAAwB,IAAI,SAAS,gBAAgB;AACvD;AAEA,SAAS,qBAAqB,IAA0B;AACtD,QAAM,YAAY,YAAY,IAAI;AAClC,qBAAmB,GAAG,OAAO,gCAAgC;IAC3D,SAAS;EACX,CAAC;AACD,MAAI;AACF,OAAG;MACD;IACF;AACA,OAAG,KAAK,4EAA4E;AACpF,uBAAmB,GAAG,OAAO,kCAAkC;MAC7D,SAAS;MACT,aAAa,KAAK,MAAM,YAAY,IAAI,IAAI,SAAS;IACvD,CAAC;EACH,SAAS,OAAO;AACd,uBAAmB,GAAG,KAAK,+BAA+B;MACxD,SAAS;MACT,aAAa,KAAK,MAAM,YAAY,IAAI,IAAI,SAAS;MACrD,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAChE,CAAC;AACD,4BAAwB,IAAI,CAAC,GAAG,kBAAkB,GAAG,YAAY;EACnE;AACF;AAEA,SAAS,qBAAqB,OAAyB;AACrD,SACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,MAAM,SAAS;AAEnB;AAEA,SAAS,mBAAsB,IAAoB,IAAkC;AACnF,iBAAe,EAAE;AACjB,MAAI;AACF,WAAO,GAAG,EAAE;EACd,SAAS,OAAO;AACd,QAAI,CAAC,qBAAqB,KAAK,EAAG,OAAM;AACxC,uBAAmB,GAAG,KAAK,kCAAkC;MAC3D,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAChE,CAAC;AACD,yBAAqB,EAAE;AACvB,WAAO,GAAG,EAAE;EACd;AACF;AAEA,SAAS,sBAAsB,IAA0B;AACvD,oBAAkB,EAAE;AACpB,iBAAe,IAAI,oBAAoB;AACvC,KAAG;IACD;;;;;EAKF,EAAE,IAAI,OAAO,oBAAoB,CAAC;AACpC;AAEA,SAAS,aAAa,IAAoB,QAAsB;AAC9D,QAAM,iBAAiB,6BAA6B,EAAE;AACtD,MAAI,mBAAmB,KAAK,CAAC,kBAAkB,EAAE,GAAG;AAClD,4BAAwB,EAAE;AAC1B,0BAAsB,EAAE;AACxB,2BAAuB,EAAE;AACzB,gCAA4B,EAAE;AAC9B,wBAAoB,EAAE;AACtB;EACF;AAEA,sBAAoB,IAAI;IACtB;IACA;IACA,eAAe;IACf,aAAa;IACb,cAAc;MACZ;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;IACF;IACA,YAAY;MACV,EAAE,SAAS,GAAG,SAAS,kBAAkB;MACzC,EAAE,SAAS,GAAG,SAAS,mBAAmB;MAC1C,EAAE,SAAS,GAAG,SAAS,uBAAuB;MAC9C;QACE,SAAS;QACT,aAAa;QACb,QAAQE,KAAI;AACV,kCAAwBA,GAAE;AAC1B,oCAA0BA,GAAE;AAC5B,wCAA8BA,GAAE;QAClC;MACF;MACA;QACE,SAAS;QACT,QAAQA,KAAI;AACV,oCAA0BA,GAAE;AAC5B,qCAA2BA,GAAE;QAC/B;MACF;MACA,EAAE,SAAS,GAAG,SAAS,qBAAqB;MAC5C;QACE,SAAS;QACT,QAAQA,KAAI;AACV,oCAA0BA,GAAE;AAC5B,oCAA0BA,GAAE;QAC9B;MACF;MACA;QACE,SAAS;QACT,QAAQA,KAAI;AACV,6CAAmCA,GAAE;AACrC,uCAA6BA,GAAE;QACjC;MACF;MACA;QACE,SAAS;QACT,QAAQA,KAAI;AACV,+BAAqBA,GAAE;QACzB;MACF;MACA;QACE,SAAS;QACT,QAAQA,KAAI;AACV,mCAAyBA,GAAE;QAC7B;MACF;MACA,EAAE,SAAS,IAAI,SAAS,kBAAkB;MAC1C,EAAE,SAAS,IAAI,SAAS,uBAAuB;MAC/C,EAAE,SAAS,IAAI,aAAa,MAAM,SAAS,wBAAwB;MACnE,EAAE,SAAS,IAAI,SAAS,6BAA6B;MACrD,EAAE,SAAS,IAAI,SAAS,0BAA0B;IACpD;EACF,CAAC;AAED,0BAAwB,EAAE;AAE1B,MAAI,eAAe,EAAE,KAAK,sBAAsB;AAC9C,0BAAsB,EAAE;EAC1B;AAEA,yBAAuB,EAAE;AACzB,8BAA4B,EAAE;AAC9B,sBAAoB,EAAE;AACxB;ACzyCA,SAAS,cAAc,OAAuB;AAC5C,SAAO,MAAM,WAAW,KAAK,IAAI;AACnC;AAEO,SAAS,kBAAkB,OAAyB;AACzD,QAAM,SAAmB,CAAC;AAC1B,MAAI,QAAQ;AACZ,MAAI,UAAU;AAEd,aAAW,QAAQ,OAAO;AACxB,QAAI,SAAS,KAAK;AAChB,gBAAU,CAAC;AACX,eAAS;AACT;IACF;AACA,QAAI,KAAK,KAAK,IAAI,KAAK,CAAC,SAAS;AAC/B,UAAI,OAAO;AACT,eAAO,KAAK,KAAK;AACjB,gBAAQ;MACV;AACA;IACF;AACA,aAAS;EACX;AAEA,MAAI,MAAO,QAAO,KAAK,KAAK;AAC5B,SAAO;AACT;AAEO,SAAS,kBAAkB,OAAuB;AACvD,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,QAAQ,WAAW,GAAG,KAAK,QAAQ,SAAS,GAAG,GAAG;AACpD,WAAO,QAAQ,MAAM,GAAG,EAAE,EAAE,KAAK;EACnC;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,OAAe,SAAmC;AAC5E,QAAM,MAAM,kBAAkB,KAAK;AACnC,QAAM,QAAQ,IAAI,MAAM,sCAAsC;AAC9D,MAAI,OAAO;AACT,YAAQ,UAAU,OAAO,MAAM,CAAC,CAAC;AACjC,YAAQ,UAAU,OAAO,MAAM,CAAC,CAAC;AACjC;EACF;AAEA,QAAM,aAAa,IAAI,MAAM,8BAA8B;AAC3D,MAAI,YAAY;AACd,UAAMC,UAAS,OAAO,WAAW,CAAC,CAAC;AACnC,QAAI,WAAW,CAAC,GAAG,SAAS,GAAG,GAAG;AAChC,cAAQ,UAAUA;AAClB,cAAQ,mBAAmB,WAAW,CAAC,MAAM;IAC/C,OAAO;AACL,cAAQ,UAAUA;AAClB,cAAQ,mBAAmB,WAAW,CAAC,MAAM;IAC/C;AACA;EACF;AAEA,QAAM,SAAS,OAAO,GAAG;AACzB,MAAI,CAAC,OAAO,MAAM,MAAM,GAAG;AACzB,YAAQ,UAAU;AAClB,YAAQ,UAAU;EACpB;AACF;AAEA,SAAS,aAAgB,QAAyB,OAAe;AAC/D,MAAI,QAAQ,SAAS,KAAK,EAAG,QAAO;AACpC,SAAO,CAAC,GAAI,UAAU,CAAC,GAAI,KAAK;AAClC;AAEA,SAAS,WAAW,OAAkC;AACpD,SACE,UAAU,YACV,UAAU,iBACV,UAAU,iBACV,UAAU,aACV,UAAU,UACV,UAAU,aACV,UAAU,kBACV,UAAU,iBACV,UAAU;AAEd;AAEO,SAAS,iBAAiB,OAAkC;AACjE,QAAM,UAA8B,CAAC;AACrC,QAAM,aAAuB,CAAC;AAC9B,MAAI,gBAAgB;AAEpB,aAAW,SAAS,kBAAkB,KAAK,GAAG;AAC5C,UAAM,QAAQ,MAAM,MAAM,8BAA8B;AACxD,QAAI,CAAC,OAAO;AACV,iBAAW,KAAK,KAAK;AACrB;IACF;AAEA,UAAM,MAAM,MAAM,CAAC,EAAG,YAAY;AAClC,UAAM,QAAQ,kBAAkB,MAAM,CAAC,CAAE;AACzC,QAAI,CAAC,MAAO;AAEZ,QAAI,WAAW;AACf,QAAI,QAAQ,QAAS,SAAQ,QAAQ,MAAM,YAAY;aAC9C,QAAQ,UAAW,SAAQ,UAAU;aACrC,QAAQ,gBAAgB,QAAQ,cAAe,SAAQ,aAAa;aACpE,QAAQ,iBAAiB,QAAQ,gBAAgB;AACxD,UAAI,sBAAsB,KAAK,EAAG,SAAQ,cAAc;UACnD,YAAW;IAClB,WAAW,QAAQ,MAAO,SAAQ,MAAM;aAC/B,QAAQ,OAAQ,SAAQ,QAAQ,aAAa,QAAQ,OAAO,MAAM,YAAY,CAAC;aAC/E,QAAQ,UAAU,QAAQ,OAAQ,SAAQ,OAAO;aACjD,QAAQ,UAAU,QAAQ,cAAc,QAAQ,aAAa;AACpE,UAAI,UAAU,UAAU,UAAU,UAAU,UAAU,WAAW,UAAU,UAAU;AACnF,gBAAQ,WAAW;MACrB,OAAO;AACL,mBAAW;MACb;IACF,WAAW,QAAQ,SAAS,QAAQ,UAAU;AAC5C,YAAM,MAAM,MAAM,YAAY;AAC9B,UAAI,WAAW,GAAG,EAAG,SAAQ,OAAO,aAAa,QAAQ,MAAM,GAAG;UAC7D,YAAW;IAClB,WAAW,QAAQ,QAAQ;AACzB,yBAAmB,OAAO,OAAO;IACnC,OAAO;AACL,iBAAW;IACb;AAEA,QAAI,SAAU,iBAAgB;QACzB,YAAW,KAAK,KAAK;EAC5B;AAEA,SAAO;IACL,MAAM,WAAW,KAAK,GAAG,EAAE,KAAK;IAChC;IACA;EACF;AACF;AAEO,SAAS,WAAW,OAAuB;AAChD,QAAM,SAAS,kBAAkB,KAAK;AACtC,SAAO,OACJ,IAAI,CAAC,UAAU;AACd,QAAI,QAAQ,KAAK,KAAK,EAAG,QAAO;AAChC,QAAI,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,GAAG;AAChD,aAAO,IAAI,cAAc,MAAM,MAAM,GAAG,EAAE,CAAC,CAAC;IAC9C;AACA,WAAO,IAAI,cAAc,KAAK,CAAC;EACjC,CAAC,EACA;IACC,CAAC,OAAO,OAAO,WACb,UAAU,QACT,QAAQ,KACP,QAAQ,OAAO,SAAS,KACxB,OAAO,QAAQ,CAAC,MAAM,QACtB,OAAO,QAAQ,CAAC,MAAM;EAC5B,EACC,KAAK,GAAG;AACb;ACjIA,SAAS,sBAAsB,IAAoB,WAAgC;AACjF,QAAM,OAAO,GACV,QAAQ,6DAA6D,EACrE,IAAI,SAAS;AAChB,SAAO,IAAI,IAAI,KAAK,IAAI,CAAC,QAAQ,OAAO,IAAI,UAAU,CAAC,CAAC;AAC1D;AAIA,IAAM,gCAAgC;AACtC,IAAM,iCAAiC;AAWvC,SAAS,0BAA0B,SAAiC,cAA+B;AACjG,MAAI,QAAQ,UAAU,MAAM;AAC1B,WAAO,QAAQ;EACjB;AAEA,QAAM,YAAY,QAAQ,iBAAiB;AAC3C,SAAO,YAAY,KAAK,gBAAgB;AAC1C;AAEA,SAAS,mBAAmB,SAA8B;AACxD,SAAO,KAAK,UAAU;IACpB,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAQ,gBAAgB,QAAQ;IAChC,QAAQ,MAAM;IACd,QAAQ,MAAM;IACd,QAAQ,MAAM;IACd,QAAQ,MAAM,2BAA2B;IACzC,QAAQ,MAAM,6BAA6B;IAC3C,QAAQ,MAAM;IACd,QAAQ,MAAM,eAAe;IAC7B,QAAQ,MAAM,gBAAgB;EAChC,CAAC;AACH;AAEA,SAAS,yBACP,aACA,kBACA,2BAAwC,oBAAI,IAAI,GAC9B;AAClB,SAAO;IACL,wBAAwB,IAAI;MAC1B,YAAY,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,UAAU,GAAG,OAAO,IAAI,gBAAgB,EAAE,CAAC,CAAC;IACnF;IACA,gCAAgC,IAAI;MAClC,YAAY,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,UAAU,GAAG,OAAO,IAAI,yBAAyB,CAAC,CAAC,CAAC;IAC3F;IACA,yBAAyB,IAAI;MAC3B,iBAAiB,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,UAAU,GAAG,OAAO,IAAI,SAAS,CAAC,CAAC,CAAC;IAChF;IACA;EACF;AACF;AAEA,SAAS,qBACP,IACA,WACA,YACkB;AAClB,QAAM,OAA8B,CAAC;AACrC,QAAM,mBAAmB,CAAC,GAAG,IAAI,IAAI,UAAU,CAAC;AAEhD,WAAS,SAAS,GAAG,SAAS,iBAAiB,QAAQ,UAAU,+BAA+B;AAC9F,UAAM,QAAQ,iBAAiB,MAAM,QAAQ,SAAS,6BAA6B;AACnF,UAAM,gBAAgB,MAAM,IAAI,MAAM,KAAK,EAAE,KAAK,IAAI;AACtD,UAAM,YAAY,GACf;MACC;8DACsD,aAAa;;;;;;;;;;;;;;;;IAgBrE,EACC,IAAI,GAAG,OAAO,WAAW,SAAS;AACrC,SAAK,KAAK,GAAG,SAAS;EACxB;AAEA,SAAO,yBAAyB,MAAM,MAAM,sBAAsB,IAAI,SAAS,CAAC;AAClF;AAEA,SAAS,4BAA4B,OAAyB,SAA+B;AAC3F,QAAM,YAAY,QAAQ;AAC1B,SACE,MAAM,yBAAyB,IAAI,SAAS,KAC5C,MAAM,uBAAuB,IAAI,SAAS,MAAM,mBAAmB,OAAO,KAC1E,MAAM,+BAA+B,IAAI,SAAS,OAC/C,MAAM,wBAAwB,IAAI,SAAS,KAAK;AAEvD;AAEA,SAAS,qBACP,WACA,QACA,iBAC+B;AAC/B,MAAI;AACF,UAAM,OAAO,gBAAgB,OAAO,QAAQ,EAAE;AAC9C,UAAM,WAAW,kBAAkB,IAAI;AACvC,UAAM,WACJ,OAAO,QAAQ,oBACf,KAAK,oBACL,gBAAgB,OAAO,QAAQ,WAAW,MAAM;AAClD,WAAO;MACL,SAAS,OAAO;MAChB;MACA,aAAa,gCAAgC,KAAK,SAAS,OAAO,QAAQ,OAAO,QAAQ;MACzF,aAAa,mBAAmB,OAAO,OAAO;MAC9C,cAAc;QACZ;QACA,OAAO,QAAQ;QACf,SAAS;QACT,KAAK;MACP;MACA,WAAW,OAAO;IACpB;EACF,QAAQ;AACN,WAAO;EACT;AACF;AAEA,UAAU,uBACR,WACA,SACA,iBACmC;AACnC,aAAW,UAAU,SAAS;AAC5B,UAAM,QAAQ,qBAAqB,WAAW,QAAQ,eAAe;AACrE,QAAI,MAAO,OAAM;EACnB;AACF;AAEA,SAAS,qBACP,IACA,WACA,mBACA,SACQ;AACR,QAAM,YAAY,GAAG;IACnB;EACF;AACA,QAAM,iBAAiB,GAAG;IACxB;EACF;AACA,QAAM,qBAAqB,GAAG;IAC5B;EACF;AACA,QAAM,qBAAqB,GAAG;IAC5B;EACF;AACA,QAAM,uBAAuB,4BAA4B,EAAE;AAC3D,QAAM,qBAAqB,0BAA0B,EAAE;AACvD,QAAM,oBAAoB,yBAAyB,EAAE;AACrD,QAAM,gBAAgB,GAAG,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyChC;AACD,QAAM,YAAY,GAAG,QAAQ;;;;;;;;;;;;;;;;GAgB5B;AAED,QAAM,sBAAsB,GAAG;IAC7B;EACF;AAEA,aAAW,aAAa,IAAI,IAAI,iBAAiB,GAAG;AAClD,cAAU,IAAI,WAAW,SAAS;AAClC,uBAAmB,IAAI,WAAW,SAAS;AAC3C,uBAAmB,IAAI,WAAW,WAAW,CAAC;AAC9C,mBAAe,IAAI,WAAW,WAAW,CAAC;AAC1C,wBAAoB,IAAI,WAAW,SAAS;EAC9C;AAEA,MAAI,UAAU;AACd,aAAW,SAAS,SAAS;AAC3B,qBAAiB,sBAAsB,WAAW,MAAM,SAAS,MAAM,MAAM,WAAW,IAAI;AAC5F,uBAAmB,IAAI,WAAW,MAAM,QAAQ,EAAE;AAClD,uBAAmB,IAAI,WAAW,MAAM,QAAQ,IAAI,CAAC;AACrD,wBAAoB,IAAI,WAAW,MAAM,QAAQ,EAAE;AACnD,0BAAsB,oBAAoB,MAAM,YAAY;AAC5D,eAAW,WAAW,MAAM,UAAU;AACpC,oBAAc;QACZ;QACA,MAAM,QAAQ;QACd,QAAQ;QACR,QAAQ;QACR,QAAQ;QACR,QAAQ;QACR,QAAQ,iBAAiB;QACzB,QAAQ,SAAS;QACjB,QAAQ,QAAQ;QAChB,QAAQ,SAAS;QACjB,QAAQ,YAAY;QACpB,QAAQ,cAAc;QACtB,QAAQ,QAAQ;QAChB,QAAQ,cAAc;QACtB,QAAQ;QACR;QACA,QAAQ,cAAc;QACtB,QAAQ,YAAY;QACpB,QAAQ;QACR,QAAQ,oBAAoB;MAC9B;AACA,iBAAW,YAAY,QAAQ,WAAW;AACxC,0BAAkB,IAAI,WAAW,MAAM,QAAQ,IAAI,QAAQ,OAAO,QAAQ;MAC5E;IACF;AACA,mBAAe,IAAI,WAAW,MAAM,QAAQ,IAAI,MAAM,SAAS,MAAM;AACrE,cAAU;MACR;MACA,MAAM,QAAQ;MACd,MAAM,QAAQ;MACd,MAAM;MACN,MAAM;MACN,MAAM,SAAS;MACf,KAAK,IAAI;IACX;AACA,eAAW;EACb;AACA,SAAO;AACT;AAEO,SAAS,uBACd,WACA,UACA,iBACA,UAAkC,CAAC,GACL;AAC9B,SAAO,kBAAkB,CAAC,OAAO;AAC/B,UAAM,YAAY,YAAY,IAAI;AAClC,UAAM,eAAe,GAClB;MACC;IACF,EACC,IAAI,SAAS;AAChB,UAAM,sBAAsB,IAAI,IAAI,SAAS,IAAI,CAAC,SAAS,UAAU,CAAC,QAAQ,IAAI,KAAK,CAAC,CAAC;AACzF,UAAM,mBAAmB,GACtB;MACC;IACF,EACC,IAAI,SAAS;AAChB,UAAM,mBAAmB;MACvB;MACA;MACA,sBAAsB,IAAI,SAAS;IACrC;AACA,UAAM,aAAa,IAAI,IAAI,SAAS,IAAI,CAAC,YAAY,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAC;AAE3E,UAAM,WAAW,aACd,IAAI,CAAC,QAAQ,OAAO,IAAI,UAAU,CAAC,EACnC,OAAO,CAAC,cAAc,CAAC,WAAW,IAAI,SAAS,CAAC;AACnD,UAAM,WAAW,SAAS;MAAO,CAAC,YAChC,4BAA4B,kBAAkB,OAAO;IACvD;AACA,UAAM,eAAe,SAAS,SAAS,SAAS;AAChD,UAAM,SAAS,0BAA0B,SAAS,YAAY;AAC9D,UAAM,UAAU,SAAS,IAAI,CAAC,aAAa;MACzC;MACA,WAAW,oBAAoB,IAAI,QAAQ,EAAE,KAAK;IACpD,EAAE;AACF,QAAI,UAAU;AAMd,QAAI,QAAQ,SAAS,gCAAgC;AACnD,0BAAoB,IAAI,OAAO,MAAM;AACnC,mBAAW,qBAAqB,IAAI,WAAW,UAAU,CAAC,CAAC;MAC7D,CAAC;AACD,eAAS,SAAS,GAAG,SAAS,QAAQ,QAAQ,UAAU,gCAAgC;AACtF,cAAM,QAAQ,QAAQ,MAAM,QAAQ,SAAS,8BAA8B;AAC3E,4BAAoB,IAAI,OAAO,MAAM;AACnC,qBAAW;YACT;YACA;YACA,CAAC;YACD,uBAAuB,WAAW,OAAO,eAAe;UAC1D;QACF,CAAC;MACH;AACA,aAAO;QACL;QACA,MAAM;QACN,UAAU,SAAS;QACnB,SAAS,SAAS;QAClB,SAAS,SAAS;QAClB;QACA,SAAS,SAAS,SAAS;QAC3B,YAAY,YAAY,IAAI,IAAI;MAClC;IACF;AAEA,UAAM,YAAY,MAAM;AACtB,gBAAU;QACR;QACA;QACA;QACA,uBAAuB,WAAW,SAAS,eAAe;MAC5D;IACF;AAEA,UAAM,eAAe,UAAU,eAAe;AAC9C,UAAM,EAAE,kBAAkB,IAAI,oBAAoB,IAAI,cAAc,SAAS;AAE7E,WAAO;MACL;MACA,MAAM,SAAS,SAAS;MACxB,UAAU,SAAS;MACnB,SAAS,SAAS;MAClB,SAAS,SAAS;MAClB;MACA,SAAS,SAAS,SAAS;MAC3B,YAAY,YAAY,IAAI,IAAI;MAChC;IACF;EACF,CAAC;AACH;AAEO,SAAS,8BACd,WACA,SACA,mBACA,iBACA,UAAkC,CAAC,GACL;AAC9B,MAAI,QAAQ,WAAW,KAAK,kBAAkB,WAAW,GAAG;AAC1D,WAAO;MACL;MACA,MAAM;MACN,UAAU;MACV,SAAS;MACT,SAAS;MACT,SAAS;MACT,SAAS;MACT,YAAY;IACd;EACF;AAEA,SAAO,kBAAkB,CAAC,OAAO;AAC/B,UAAM,YAAY,YAAY,IAAI;AAClC,UAAM,mBAAmB;MACvB;MACA;MACA,QAAQ,IAAI,CAAC,EAAE,QAAQ,MAAM,QAAQ,EAAE;IACzC;AACA,UAAM,WAAW,QAAQ;MAAO,CAAC,EAAE,QAAQ,MACzC,4BAA4B,kBAAkB,OAAO;IACvD;AACA,UAAM,0BAA0B,MAAM,KAAK,IAAI,IAAI,iBAAiB,CAAC;AACrE,UAAM,eAAe,wBAAwB,SAAS,SAAS;AAC/D,UAAM,SAAS,0BAA0B,SAAS,YAAY;AAC9D,QAAI,UAAU;AACd,UAAM,YAAY,MAAM;AACtB,gBAAU;QACR;QACA;QACA;QACA,uBAAuB,WAAW,UAAU,eAAe;MAC7D;IACF;AAEA,UAAM,eAAe,UAAU,eAAe;AAC9C,UAAM,EAAE,kBAAkB,IAAI,oBAAoB,IAAI,cAAc,SAAS;AAE7E,WAAO;MACL;MACA,MAAM,SAAS,SAAS;MACxB,UAAU,QAAQ;MAClB,SAAS,SAAS;MAClB,SAAS,wBAAwB;MACjC;MACA,SAAS,SAAS,SAAS;MAC3B,YAAY,YAAY,IAAI,IAAI;MAChC;IACF;EACF,CAAC;AACH;AChaO,SAAS,yBAAyB,KAAmC;AAC1E,SAAO,eAAe,GAAiB;AACzC;AAEO,SAAS,iBACd,MACA,OACiB;AACjB,QAAM,SAAS,CAAC,GAAI,QAAQ,CAAC,GAAI,GAAI,SAAS,CAAC,CAAE;AACjD,SAAO,OAAO,SAAS,IAAI,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,IAAI;AACpD;AAEO,SAAS,wBAAwB,OAAe,SAAwB;AAC7E,QAAM,SAAS,iBAAiB,KAAK;AACrC,SAAO;IACL,MAAM,OAAO,SAAS,OAAO,gBAAgB,KAAK,MAAM,KAAK;IAC7D,SAAS;MACP,GAAG;MACH,OAAO,QAAQ,SAAS,OAAO,QAAQ;MACvC,SAAS,QAAQ,WAAW,OAAO,QAAQ;MAC3C,aAAa,QAAQ,eAAe,OAAO,QAAQ;MACnD,YAAY,QAAQ,cAAc,OAAO,QAAQ;MACjD,KAAK,QAAQ,OAAO,OAAO,QAAQ;MACnC,MAAM,iBAAiB,QAAQ,MAAM,OAAO,QAAQ,IAAI;MACxD,OAAO,iBAAiB,QAAQ,OAAO,OAAO,QAAQ,KAAK;MAC3D,MAAM,QAAQ,QAAQ,OAAO,QAAQ;MACrC,UAAU,QAAQ,YAAY,OAAO,QAAQ;MAC7C,SAAS,QAAQ,WAAW,OAAO,QAAQ;MAC3C,SAAS,QAAQ,WAAW,OAAO,QAAQ;MAC3C,kBAAkB,QAAQ,oBAAoB,OAAO,QAAQ;MAC7D,kBAAkB,QAAQ,oBAAoB,OAAO,QAAQ;IAC/D;IACA;EACF;AACF;AAEO,SAAS,yBAAyB,SAAsB,SAAiC;AAC9F,QAAM,OAAO,QAAQ,MAAM;AAC3B,MAAI,QAAQ,WAAW,MAAM;AAC3B,QAAI,QAAQ,mBAAmB,QAAQ,QAAQ,UAAU,OAAO,QAAQ,SAAS;AAC/E,aAAO;IACT;EACF;AACA,MAAI,QAAQ,WAAW,MAAM;AAC3B,QAAI,QAAQ,mBAAmB,QAAQ,QAAQ,UAAU,OAAO,QAAQ,SAAS;AAC/E,aAAO;IACT;EACF;AACA,SAAO;AACT;AAEO,SAAS,0BAA0B,SAGxC;AACA,QAAM,UAAoB,CAAC;AAC3B,QAAM,SAAoB,CAAC;AAE3B,MAAI,QAAQ,OAAO;AACjB,YAAQ,KAAK,kBAAkB;AAC/B,WAAO,KAAK,QAAQ,KAAK;EAC3B;AACA,MAAI,QAAQ,eAAe,QAAQ,YAAY;AAC7C,QAAI,QAAQ,eAAe,QAAQ,YAAY;AAC7C,cAAQ,KAAK,4DAA4D;AACzE,aAAO,KAAK,QAAQ,aAAa,QAAQ,UAAU;IACrD,OAAO;AACL,cAAQ,KAAK,GAAG;IAClB;EACF;AACA,MAAI,QAAQ,KAAK;AACf,UAAM,WAAW,gBAAgB,QAAQ,KAAK,MAAM;AACpD,YAAQ;MACN;IACF;AACA,WAAO,KAAK,SAAS,MAAM,SAAS,KAAK,YAAY,QAAQ,GAAG,CAAC;EACnE;AACA,MAAI,QAAQ,SAAS;AACnB,YAAQ;MACN;IACF;AACA,UAAM,UAAU,YAAY,QAAQ,OAAO;AAC3C,WAAO,KAAK,SAAS,SAAS,OAAO;EACvC;AACA,aAAW,OAAO,QAAQ,QAAQ,CAAC,GAAG;AACpC,YAAQ,KAAK,0BAA0B;AACvC,WAAO,KAAK,KAAK,GAAG,IAAI;EAC1B;AACA,aAAW,QAAQ,QAAQ,SAAS,CAAC,GAAG;AACtC,UAAM,WAAWF,mBAAkB,IAAI;AACvC,QAAI,CAAC,SAAU;AACf,YAAQ;MACN;IACF;AACA,WAAO,KAAK,QAAQ;EACtB;AACA,MAAI,QAAQ,QAAQ,QAAQ,UAAU;AACpC,UAAM,cAAc,CAAC,gCAAgC,8BAA8B;AACnF,QAAI,QAAQ,MAAM;AAChB,YAAM,YAAY,iBAAiB,QAAQ,IAAI;AAC/C,UAAI,WAAW;AACb,oBAAY;UACV;QACF;AACA,eAAO,KAAK,SAAS;MACvB,OAAO;AACL,oBAAY,KAAK,mCAAmC;AACpD,eAAO,KAAK,YAAY,QAAQ,IAAI,CAAC;MACvC;IACF;AACA,QAAI,QAAQ,UAAU;AACpB,kBAAY,KAAK,aAAa;AAC9B,aAAO,KAAK,QAAQ,QAAQ;IAC9B;AACA,YAAQ;MACN,wDAAwD,YAAY,KAAK,OAAO,CAAC;IACnF;EACF;AACA,MAAI,QAAQ,QAAQ,MAAM;AACxB,YAAQ,KAAK,sBAAsB;AACnC,WAAO,KAAK,QAAQ,IAAI;EAC1B;AACA,MAAI,QAAQ,MAAM,MAAM;AACtB,YAAQ,KAAK,sBAAsB;AACnC,WAAO,KAAK,QAAQ,EAAE;EACxB;AACA,MAAI,QAAQ,WAAW,MAAM;AAC3B,YAAQ,KAAK,QAAQ,mBAAmB,qBAAqB,mBAAmB;AAChF,WAAO,KAAK,QAAQ,OAAO;EAC7B;AACA,MAAI,QAAQ,WAAW,MAAM;AAC3B,YAAQ,KAAK,QAAQ,mBAAmB,qBAAqB,mBAAmB;AAChF,WAAO,KAAK,QAAQ,OAAO;EAC7B;AAEA,SAAO;IACL,OAAO,QAAQ,SAAS,IAAI,QAAQ,QAAQ,KAAK,OAAO,CAAC,KAAK;IAC9D;EACF;AACF;AAOA,IAAM,8BAA8B;AAE7B,SAAS,+BACd,YACA,SACa;AACb,MAAI,WAAW,WAAW,KAAK,CAAC,gBAAgB,EAAG,QAAO,oBAAI,IAAI;AAElE,QAAM,UAAU,aAAa,CAAC,OAAO;AACnC,UAAM,UAAU,0BAA0B,OAAO;AACjD,UAAM,SAAS,oBAAI,IAAY;AAE/B,aAAS,SAAS,GAAG,SAAS,WAAW,QAAQ,UAAU,6BAA6B;AACtF,YAAM,QAAQ,WAAW,MAAM,QAAQ,SAAS,2BAA2B;AAC3E,YAAM,mBAAmB,MAAM,IAAI,MAAM,yCAAyC;AAClF,YAAM,kBAAkB,MAAM,QAAQ,CAAC,EAAE,WAAW,UAAU,MAAM,CAAC,WAAW,SAAS,CAAC;AAC1F,YAAM,OAAO,GACV;QACC;;;qBAGW,iBAAiB,KAAK,MAAM,CAAC;gBAClC,QAAQ,KAAK;;MAErB,EACC,IAAI,GAAG,iBAAiB,GAAG,QAAQ,MAAM;AAE5C,iBAAW,OAAO,MAAM;AACtB,eAAO,IAAI,mBAAmB,GAAG,CAAC;MACpC;IACF;AAEA,WAAO;EACT,CAAC;AAED,SAAO,WAAW,oBAAI,IAAI;AAC5B;AAEA,SAAS,uBAA+B;AACtC,SAAO;;;;;;;;;;;;;;;;;;;;;;;AAuBT;AAEA,SAAS,eAAe,OAAyD;AAC/E,QAAM,SAAS,kBAAkB,KAAK;AACtC,SAAO;IACL,OAAO,OACJ,OAAO,CAAC,UAAU,CAAC,QAAQ,KAAK,KAAK,CAAC,EACtC,IAAI,CAAC,UAAU,kBAAkB,KAAK,EAAE,YAAY,CAAC,EACrD,OAAO,OAAO;IACjB,MAAM,OAAO,KAAK,CAAC,UAAU,QAAQ,KAAK,KAAK,CAAC,IAAI,QAAQ;EAC9D;AACF;AAEA,SAAS,iBAAiB,MAAc,OAAiD;AACvF,QAAM,QAAQ,KAAK,YAAY;AAC/B,MAAI,MAAM,MAAM,WAAW,EAAG,QAAO;AACrC,MAAI,MAAM,SAAS,MAAO,QAAO,MAAM,MAAM,KAAK,CAAC,SAAS,MAAM,SAAS,IAAI,CAAC;AAChF,SAAO,MAAM,MAAM,MAAM,CAAC,SAAS,MAAM,SAAS,IAAI,CAAC;AACzD;AAEA,SAAS,cAAc,MAAc,MAAsB;AACzD,SAAO,KAAK,QAAQ,IAAI,OAAO,aAAa,IAAI,GAAG,IAAI,GAAG,CAAC,UAAU,SAAS,KAAK,SAAS;AAC9F;AAEA,SAAS,iBAAiB,MAAc,OAAyD;AAC/F,QAAM,QAAQ,KAAK,YAAY;AAC/B,QAAM,OAAO,MAAM,MAAM,KAAK,CAAC,SAAS,MAAM,SAAS,IAAI,CAAC,KAAK,MAAM,MAAM,CAAC,KAAK;AACnF,MAAI,CAAC,KAAM,QAAO,KAAK,MAAM,GAAG,GAAG;AAEnC,QAAM,QAAQ,MAAM,QAAQ,IAAI;AAChC,QAAM,QAAQ,KAAK,IAAI,GAAG,QAAQ,EAAE;AACpC,QAAM,MAAM,KAAK,IAAI,KAAK,QAAQ,QAAQ,KAAK,SAAS,EAAE;AAC1D,SAAO,GAAG,QAAQ,IAAI,YAAO,EAAE,GAAG,cAAc,KAAK,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,GAC3E,MAAM,KAAK,SAAS,YAAO,EAC7B;AACF;AAEA,SAAS,iBAAiB,KAAwC;AAChE,MAAI,IAAI,SAAS,OAAQ,QAAO;AAChC,MAAI,IAAI,SAAS,UAAU,IAAI,SAAS,UAAU,IAAI,mBAAoB,QAAO;AACjF,SAAO;AACT;AAEA,SAAS,mBAAmB,KAAiE;AAC3F,SAAO,GAAG,OAAO,IAAI,UAAU,CAAC,KAAS,OAAO,IAAI,UAAU,CAAC;AACjE;AAEA,SAAS,0BACP,IACA,MACA,UACA,OAC8D;AAC9D,QAAM,aAAa,KAAK,OAAO,CAAC,QAAQ,CAAC,iBAAiB,OAAO,IAAI,SAAS,EAAE,GAAG,KAAK,CAAC;AACzF,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO,oBAAI,IAAI;EACjB;AAEA,QAAM,UAAoB,CAAC;AAC3B,QAAM,SAAoB,CAAC,QAAQ;AACnC,aAAW,OAAO,YAAY;AAC5B,YAAQ,KAAK,yCAAyC;AACtD,WAAO,KAAK,OAAO,IAAI,UAAU,GAAG,OAAO,IAAI,UAAU,CAAC;EAC5D;AAEA,QAAM,cAAc,GACjB;IACC;;;;;;;;;;;;iBAYW,QAAQ,KAAK,MAAM,CAAC;;;EAGjC,EACC,IAAI,GAAG,MAAM;AAChB,QAAM,UAAU,oBAAI,IAA6D;AAEjF,aAAW,WAAW,aAAa;AACjC,UAAM,MAAM,mBAAmB,OAAO;AACtC,QAAI,QAAQ,IAAI,GAAG,EAAG;AAEtB,UAAM,OAAO,OAAO,QAAQ,gBAAgB,EAAE;AAC9C,QAAI,CAAC,iBAAiB,MAAM,KAAK,EAAG;AAEpC,YAAQ,IAAI,KAAK;MACf,SAAS,iBAAiB,MAAM,KAAK;MACrC,WAAW,iBAAiB,OAAO;IACrC,CAAC;EACH;AAEA,SAAO;AACT;AAEA,SAAS,mBACP,KACA,OACA,gBACiD;AACjD,QAAM,QAAQ,OAAO,IAAI,SAAS,EAAE;AAEpC,MAAI,MAAM,MAAM,WAAW,GAAG;AAC5B,WAAO;MACL,SAAS,uBAAoB,OAAO,IAAI,aAAa,EAAE,CAAC;MACxD,WAAW;IACb;EACF;AAEA,MAAI,iBAAiB,OAAO,KAAK,GAAG;AAClC,WAAO,EAAE,SAAS,iBAAiB,OAAO,KAAK,GAAG,WAAW,QAAQ;EACvE;AAEA,QAAM,eAAe,eAAe,IAAI,mBAAmB,GAAG,CAAC;AAC/D,MAAI,cAAc;AAChB,WAAO;EACT;AAEA,SAAO;IACL,SAAS,OAAO,IAAI,WAAW,EAAE;IACjC,WAAW;EACb;AACF;AAEA,SAAS,oBACP,IACA,MACA,WACA,WAAW,WAAW,SAAS,GACf;AAChB,QAAM,QAAQ,eAAe,SAAS;AACtC,QAAM,iBACJ,MAAM,MAAM,SAAS,KAAK,WACtB,0BAA0B,IAAI,MAAM,UAAU,KAAK,IACnD,oBAAI,IAA6D;AAEvE,SAAO,KAAK,IAAI,CAAC,QAAQ;AACvB,UAAM,QAAQ,mBAAmB,KAAK,OAAO,cAAc;AAC3D,WAAO;MACL,WAAW;QACT,WAAW,OAAO,IAAI,UAAU;QAChC,WAAW,OAAO,IAAI,UAAU;MAClC;MACA,SAAS,yBAAyB,GAAG;MACrC,SAAS,MAAM;MACf,WAAW,MAAM;IACnB;EACF,CAAC;AACH;AAEO,SAAS,eAAe,OAAe,UAAyB,CAAC,GAAmB;AACzF,QAAM,SAAS,wBAAwB,OAAO,OAAO;AACrD,QAAM,kBAAkB,OAAO,KAAK,KAAK;AACzC,MAAI,CAAC,gBAAgB,GAAG;AACtB,WAAO,CAAC;EACV;AAEA,QAAM,UAAU,aAAa,CAAC,OAAO;AACnC,UAAM,UAAU,0BAA0B,OAAO,OAAO;AAExD,QAAI,CAAC,iBAAiB;AACpB,YAAMG,QAAO,GACV;QACC;;gBAEM,qBAAqB,CAAC;;;;gBAItB,QAAQ,KAAK;;;;MAIrB,EACC,IAAI,GAAG,QAAQ,QAAQ,OAAO,QAAQ,SAAS,EAAE;AAEpD,aAAO,oBAAoB,IAAIA,OAAM,EAAE;IACzC;AAEA,UAAM,WAAW,WAAW,eAAe;AAC3C,QAAI,CAAC,SAAU,QAAO,CAAC;AACvB,UAAM,OAAO,GACV;MACC;;cAEM,qBAAqB,CAAC;;;;;;;;;cAStB,QAAQ,KAAK;;;;IAIrB,EACC,IAAI,UAAU,GAAG,QAAQ,QAAQ,OAAO,QAAQ,SAAS,EAAE;AAE9D,WAAO,oBAAoB,IAAI,MAAM,iBAAiB,QAAQ;EAChE,CAAC;AAED,SAAO,WAAW,CAAC;AACrB;AC/cO,SAAS,oBAAoB,SASlC;AACA,QAAMvB,QAAO,QAAQ,OAAO,wBAAwB,QAAQ,IAAI,IAAI;AACpE,QAAM,cAAc,QAAQ,MAAM,gBAAgB,QAAQ,KAAK,MAAM,IAAI;AACzE,SAAO;IACL,aAAa,QAAQ,eAAe;IACpC,YAAY,QAAQ,cAAc;IAClC,aAAa,QAAQ,UAAU,YAAY,QAAQ,OAAO,IAAI;IAC9D,SAAS,aAAa,QAAQ;IAC9B,QAAQ,aAAa,OAAO;IAC5B,SAAS,QAAQ,MAAM,YAAY,QAAQ,GAAG,IAAI;IAClD,MAAAA;IACA,UAAUA,QAAO,YAAYA,KAAI,IAAI;EACvC;AACF;AAEO,SAAS,oBAAoB,KAA2C;AAC7E,SAAO;IACL,WAAW;MACT,WAAW,OAAO,IAAI,UAAU;MAChC,WAAW,OAAO,IAAI,UAAU;IAClC;IACA,oBAAoB,OAAO,IAAI,wBAAwB,EAAE;IACzD,MAAM,OAAO,IAAI,QAAQ,EAAE;IAC3B,MAAO,IAAI,QAAQ;IACnB,OAAO,OAAO,IAAI,SAAS,CAAC;IAC5B,YAAY,OAAO,IAAI,eAAe,CAAC;EACzC;AACF;AAEO,SAAS,uBAAuB,SAGrC;AACA,QAAM,UAAU,oBAAoB,OAAO;AAC3C,QAAM,UAAoB,CAAC;AAC3B,QAAM,SAAoB,CAAC;AAE3B,MAAI,QAAQ,SAAS,MAAM;AACzB,YAAQ,KAAK,mBAAmB;AAChC,WAAO,KAAK,QAAQ,KAAK;EAC3B;AACA,MAAI,QAAQ,aAAa,MAAM;AAC7B,YAAQ,KAAK,mBAAmB;AAChC,WAAO,KAAK,QAAQ,SAAS;EAC/B;AACA,MAAI,QAAQ,eAAe,QAAQ,QAAQ,cAAc,MAAM;AAC7D,QAAI,QAAQ,eAAe,QAAQ,QAAQ,cAAc,MAAM;AAC7D,cAAQ,KAAK,6DAA6D;AAC1E,aAAO,KAAK,QAAQ,aAAa,QAAQ,UAAU;IACrD,OAAO;AACL,cAAQ,KAAK,GAAG;IAClB;EACF;AACA,MAAI,QAAQ,eAAe,MAAM;AAC/B,YAAQ;MACN;IACF;AACA,WAAO,KAAK,QAAQ,aAAa,QAAQ,aAAa,QAAQ,WAAW;EAC3E;AACA,MAAI,QAAQ,UAAU,MAAM;AAC1B,YAAQ;MACN;IACF;AACA,WAAO,KAAK,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,OAAO;EAC9D;AACA,MAAI,QAAQ,YAAY,MAAM;AAC5B,UAAM,YAAY,iBAAiB,QAAQ,IAAI;AAC/C,QAAI,WAAW;AACb,cAAQ;QACN;MACF;AACA,aAAO,KAAK,SAAS;IACvB,OAAO;AACL,cAAQ,KAAK,mCAAmC;AAChD,aAAO,KAAK,QAAQ,QAAQ;IAC9B;EACF;AACA,MAAI,QAAQ,QAAQ,MAAM;AACxB,YAAQ,KAAK,aAAa;AAC1B,WAAO,KAAK,QAAQ,IAAI;EAC1B;AACA,MAAI,QAAQ,QAAQ,MAAM;AACxB,YAAQ,KAAK,qBAAqB;AAClC,WAAO,KAAK,QAAQ,IAAI;EAC1B;AACA,MAAI,QAAQ,MAAM,MAAM;AACtB,YAAQ,KAAK,qBAAqB;AAClC,WAAO,KAAK,QAAQ,EAAE;EACxB;AAEA,SAAO;IACL,OAAO,QAAQ,SAAS,IAAI,SAAS,QAAQ,KAAK,OAAO,CAAC,KAAK;IAC/D;EACF;AACF;AAEA,IAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4B9B,IAAM,qBAAqB;;;;AAM3B,IAAM,sBAAsB;AAErB,SAAS,iBAAiB,UAA+B,CAAC,GAAyB;AACxF,SAAO,kBAAkB,OAAO;AAClC;AASA,SAAS,kBAAkB,OAAgE;AACzF,QAAM,UAAU,uBAAuB,MAAM,OAAO;AACpD,QAAM,iBAAiB,MAAM,uBACzB,0BAA0B,MAAM,oBAAoB,IACpD,EAAE,OAAO,IAAI,QAAQ,CAAC,EAAE;AAC5B,QAAM,UAAU;IACd,QAAQ,MAAM,QAAQ,WAAW,EAAE;IACnC,eAAe,MAAM,QAAQ,UAAU,EAAE;EAC3C,EAAE,OAAO,OAAO;AAChB,SAAO;IACL,OAAO,QAAQ,SAAS,IAAI,SAAS,QAAQ,KAAK,OAAO,CAAC,KAAK;IAC/D,QAAQ,CAAC,GAAG,QAAQ,QAAQ,GAAG,eAAe,MAAM;EACtD;AACF;AAEA,SAAS,gBAAgB,OAA0B,OAAuB;AACxE,MAAI,CAAC,MAAM,eAAe;AACxB,WAAO;eACI,qBAAqB;QAC5B,kBAAkB;QAClB,KAAK;iBACI,mBAAmB;;;EAGlC;AAEA,SAAO;aACI,qBAAqB;;;;;;qBAMb,mBAAmB;;QAEhC,kBAAkB;QAClB,KAAK;;;;;eAKE,mBAAmB;;;AAGlC;AAEA,SAAS,kBACP,SACA,sBACA,gBAAgB,OACM;AACtB,MAAI,CAAC,gBAAgB,GAAG;AACtB,WAAO,CAAC;EACV;AAEA,QAAM,QAA2B,EAAE,SAAS,sBAAsB,cAAc;AAChF,QAAM,EAAE,OAAO,OAAO,IAAI,kBAAkB,KAAK;AACjD,QAAM,MAAM,gBAAgB,OAAO,KAAK;AACxC,QAAM,YAAY,CAAC,OACjB,GAAG,QAAQ,GAAG,EAAE,IAAI,GAAG,QAAQ,QAAQ,SAAS,EAAE;AAEpD,MAAI,OAAO,oBAAoB,SAAS;AACxC,MAAI,QAAQ,QAAQ,QAAQ,MAAM;AAChC,WAAO,YAAY,SAAS;EAC9B;AAEA,UAAQ,QAAQ,CAAC,GAAG,IAAI,CAAC,SAAS;IAChC,GAAG,oBAAoB,GAAG;IAC1B,SAAS,yBAAyB,GAAG;EACvC,EAAE;AACJ;AAEO,SAAS,wBACd,WACA,WACuB;AACvB,SAAO,iBAAiB,EAAE,OAAO,WAAW,WAAW,OAAO,IAAI,CAAC,EAAE;IACnE,CAAC,EAAE,SAAS,UAAU,GAAG,SAAS,MAAM;EAC1C;AACF;AAEO,SAAS,kBAAkBA,OAAc,OAAuB;AACrE,QAAM,SAAS,wBAAwB,KAAK;AAC5C,MAAI,CAAC,OAAQ,QAAOA;AACpB,QAAM,QAAQA,MAAK,YAAY;AAC/B,QAAM,QAAQ,MAAM,QAAQ,OAAO,YAAY,CAAC;AAChD,MAAI,QAAQ,EAAG,QAAOA;AACtB,SAAO,GAAGA,MAAK,MAAM,GAAG,KAAK,CAAC,SAASA,MAAK,MAAM,OAAO,QAAQ,OAAO,MAAM,CAAC,UAAUA,MAAK;IAC5F,QAAQ,OAAO;EACjB,CAAC;AACH;AAEO,SAAS,2BACd,OACA,UAAyB,CAAC,GACV;AAChB,QAAM,SAAS,wBAAwB,OAAO,OAAO;AACrD,QAAMA,QAAO,wBAAwB,OAAO,QAAQ,QAAQ,OAAO,IAAI;AACvE,MAAI,CAACA,MAAM,QAAO,CAAC;AAEnB,QAAM,OAAO;IACX;MACE,MAAAA;MACA,MAAM,OAAO,QAAQ;MACrB,OAAO,OAAO,QAAQ,SAAS;IACjC;IACA,OAAO;IACP;EACF;AAEA,SAAO,KAAK,IAAI,CAAC,SAAS;IACxB,WAAW,IAAI;IACf,SAAS,IAAI;IACb,SAAS,GAAG,IAAI,IAAI,IAAI,kBAAkB,IAAI,MAAMA,KAAI,CAAC,SAAM,IAAI,KAAK;IACxE,WAAW;EACb,EAAE;AACJ;APhSO,IAAM,+BAA+B;AAC5C,IAAM,0BAA0B;AAkBhC,SAAS,uBAAuB,OAA2D;AACzF,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI;AACF,WAAO,KAAK,MAAM,KAAK;EACzB,QAAQ;AACN,WAAO;EACT;AACF;AAEO,SAAS,wBAA8B;AAC5C,QAAM,aAAa,mBAAmB;AACtC,MAAI,CAACd,aAAW,UAAU,GAAG;AAC3B;EACF;AAEA,MAAI;AACF,eAAW,UAAU;EACvB,QAAQ;EAER;AACF;AAEO,SAAS,mBAAmB,WAAwC;AACzE,MAAI,CAAC,gBAAgB,GAAG;AACtB,WAAO;EACT;AAEA,SAAO,YAAY,CAAC,OAAO;AACzB,UAAM,eAAe,GAClB,QAAQ,iEAAiE,EACzE,IAAI,SAAS;AAChB,UAAM,YAAY,OAAO,cAAc,SAAS,CAAC;AAEjD,QAAI,CAAC,WAAW;AACd,aAAO;IACT;AAEA,UAAM,OAAO,GACV;MACC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA+BF,EACC,IAAI,SAAS;AAEhB,UAAM,WAA0B,CAAC;AACjC,UAAM,OAAyC,CAAC;AAEhD,eAAW,OAAO,MAAM;AACtB,YAAM,UAAU,eAAe,GAAG;AAClC,eAAS,KAAK,OAAO;AAErB,UAAI,IAAI,WAAW;AACjB,aAAK,QAAQ,EAAE,IAAI,KAAK,MAAM,IAAI,SAAS;MAC7C;IACF;AAEA,WAAO,EAAE,UAAU,MAAM,UAAU;EACrC,CAAC;AACH;AAEO,SAAS,wBACd,WACA,eAAe,8BACN;AACT,MAAI,CAAC,gBAAgB,GAAG;AACtB,WAAO;EACT;AAEA,SACE,oBAAoB,CAAC,OAAO;AAC1B,QAAI,CAAC,YAAY,IAAI,sBAAsB,EAAG,QAAO;AACrD,UAAM,MAAM,GACT;MACC;;;;;IAKF,EACC,IAAI,SAAS;AAChB,WAAO,KAAK,kBAAkB;EAChC,CAAC,KAAK;AAEV;AASO,SAAS,0BACd,WACA,eAAe,8BACT;AACN,cAAY,CAAC,OAAO;AAClB,OAAG;MACD;;;;;;IAMF,EAAE,IAAI,WAAW,KAAK,IAAI,GAAG,YAAY;EAC3C,CAAC;AACH;AAGO,SAAS,yBAAyB,WAAyB;AAChE,cAAY,CAAC,OAAO;AAClB,OAAG;MACD;;;;;IAKF,EAAE,IAAI,SAAS;EACjB,CAAC;AACH;AAGO,SAAS,uBAAuB,WAAkC;AACvE,MAAI,CAAC,gBAAgB,EAAG,QAAO;AAE/B,SACE,oBAAoB,CAAC,OAAO;AAC1B,UAAM,MAAM,GACT,QAAQ,4CAA4C,EACpD,IAAI,GAAG,uBAAuB,GAAG,SAAS,EAAE;AAC/C,WAAO,KAAK,SAAS;EACvB,CAAC,KAAK;AAEV;AAGO,SAAS,0BAA0B,WAAmB,QAAsB;AACjF,MAAI,CAAC,OAAQ;AAEb,cAAY,CAAC,OAAO;AAClB,OAAG;MACD;;;;;IAKF,EAAE,IAAI,GAAG,uBAAuB,GAAG,SAAS,IAAI,MAAM;EACxD,CAAC;AACH;AAGA,SAAS,yBAAyB,WAAyB;AACzD,cAAY,CAAC,OAAO;AAClB,OAAG,QAAQ,sCAAsC,EAAE;MACjD,GAAG,uBAAuB,GAAG,SAAS;IACxC;EACF,CAAC;AACH;AAGO,SAAS,uBAAuB,WAAkC;AACvE,MAAI,CAAC,gBAAgB,GAAG;AACtB,WAAO;EACT;AAEA,SACE,oBAAoB,CAAC,OAAO;AAC1B,QAAI,CAAC,YAAY,IAAI,sBAAsB,EAAG,QAAO;AACrD,UAAM,MAAM,GACT;MACC;;;;;IAKF,EACC,IAAI,SAAS;AAChB,WAAO,KAAK,gBAAgB;EAC9B,CAAC,KAAK;AAEV;AAGO,SAAS,2BAA2B,WAAyB;AAClE,cAAY,CAAC,OAAO;AAClB,OAAG;MACD;;;;;IAKF,EAAE,IAAI,KAAK,IAAI,GAAG,SAAS;EAC7B,CAAC;AACD,2BAAyB,SAAS;AACpC;AAEO,SAAS,0BACd,WACA,WAC8B;AAC9B,MAAI,CAAC,gBAAgB,GAAG;AACtB,WAAO;EACT;AAEA,SAAO,oBAAoB,CAAC,OAAO;AACjC,UAAM,MAAM,GACT;MACC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA8BF,EACC,IAAI,WAAW,SAAS;AAE3B,QAAI,CAAC,KAAK;AACR,aAAO;IACT;AAMA,UAAM,iBACJ,GACG,QAAQ,uEAAuE,EAC/E,IAAI,WAAW,SAAS,KAAK;AAElC,UAAM,cAAc,iBAChB,CAAC,IACA,GACE;MACC;;;;;;;;;;;;;;;;;;;;;IAqBF,EACC,IAAI,WAAW,SAAS;AAE/B,UAAM,OAAO,eAAe,GAAG;AAC/B,UAAM,mBAAmB,GACtB;MACC;;;;;;;IAOF,EACC,IAAI,WAAW,SAAS;AAE3B,WAAO;MACL,MAAM;QACJ,GAAG;QACH,WAAW,EAAE,WAAW,UAAU;QAClC,eAAe,iBAAiB,IAAI,CAAC,gBAAgB,oBAAoB,WAAW,CAAC;MACvF;MACA;MACA,MAAM,uBAAuB,IAAI,SAAS;IAC5C;EACF,CAAC;AACH;AAsBO,SAAS,mBACd,WACA,UACA,OAAyC,CAAC,GACjC;AACT,QAAM,YAAY,YAAY,CAAC,OAAO;AACpC,UAAM,gBAAgB,GAAG;MACvB;IACF;AACA,UAAM,uBAAuB,GAAG;MAC9B;IACF;AACA,UAAM,iBAAiB,GAAG;MACxB;IACF;AACA,UAAM,qBAAqB,GAAG;MAC5B;IACF;AACA,UAAM,qBAAqB,GAAG;MAC5B;IACF;AACA,UAAM,cAAc,GAAG,QAAQ;;;;KAI9B;AACD,UAAM,gBAAgB,qBAAqB,EAAE;AAE7C,UAAM,QAAQ,GAAG,YAAY,MAAM;AACjC,YAAM,YAAY,KAAK,IAAI;AAC3B,YAAM,aAAa,IAAI,IAAI,SAAS,IAAI,CAAC,YAAY,QAAQ,EAAE,CAAC;AAChE,YAAM,qBAAqB,GACxB,QAAQ,sDAAsD,EAC9D,IAAI,SAAS;AAChB,kBAAY,IAAI,WAAW,SAAS;AAEpC,iBAAW,OAAO,oBAAoB;AACpC,cAAM,YAAY,OAAO,IAAI,UAAU;AACvC,YAAI,CAAC,WAAW,IAAI,SAAS,GAAG;AAC9B,+BAAqB,IAAI,WAAW,SAAS;AAC7C,6BAAmB,IAAI,WAAW,SAAS;AAC3C,yBAAe,IAAI,WAAW,SAAS;AACvC,6BAAmB,IAAI,WAAW,SAAS;AAC3C,wBAAc,IAAI,WAAW,SAAS;QACxC;MACF;AAEA,eAAS,QAAQ,CAAC,SAAS,UAAU;AACnC,cAAM,cAAc,KAAK,QAAQ,EAAE;AACnC,cAAM,WAAW,cAAc,KAAK,UAAU,WAAW,IAAI;AAC7D;UACE;UACA;UACA;UACA;UACA;UACA,mBAAmB,WAAW;QAChC;MACF,CAAC;IACH,CAAC;AAED,UAAM;AACN,0BAAsB;AACtB,WAAO;EACT,CAAC;AAED,SAAO,aAAa;AACtB;AAGO,SAAS,yBACd,WACA,SACA,mBACA,OAAyC,CAAC,GACjC;AACT,QAAM,YAAY,YAAY,CAAC,OAAO;AACpC,UAAM,gBAAgB,GAAG;MACvB;IACF;AACA,UAAM,uBAAuB,GAAG;MAC9B;IACF;AACA,UAAM,iBAAiB,GAAG;MACxB;IACF;AACA,UAAM,qBAAqB,GAAG;MAC5B;IACF;AACA,UAAM,qBAAqB,GAAG;MAC5B;IACF;AACA,UAAM,cAAc,GAAG,QAAQ;;;;KAI9B;AACD,UAAM,gBAAgB,qBAAqB,EAAE;AAE7C,UAAM,QAAQ,GAAG,YAAY,MAAM;AACjC,kBAAY,IAAI,WAAW,KAAK,IAAI,CAAC;AAErC,iBAAW,aAAa,IAAI,IAAI,iBAAiB,GAAG;AAClD,6BAAqB,IAAI,WAAW,SAAS;AAC7C,2BAAmB,IAAI,WAAW,SAAS;AAC3C,uBAAe,IAAI,WAAW,SAAS;AACvC,2BAAmB,IAAI,WAAW,SAAS;AAC3C,sBAAc,IAAI,WAAW,SAAS;MACxC;AAEA,iBAAW,EAAE,SAAS,UAAU,KAAK,SAAS;AAC5C,cAAM,cAAc,KAAK,QAAQ,EAAE;AACnC,cAAM,WAAW,cAAc,KAAK,UAAU,WAAW,IAAI;AAC7D;UACE;UACA;UACA;UACA;UACA;UACA,mBAAmB,WAAW;QAChC;MACF;IACF,CAAC;AAED,UAAM;AACN,0BAAsB;AACtB,WAAO;EACT,CAAC;AAED,SAAO,aAAa;AACtB;AAEO,SAAS,aAAmB;AACjC,uBAAqB,IAAI;AACzB,MAAI,CAAC,gBAAgB,GAAG;AACtB,0BAAsB;AACtB;EACF;AAEA,cAAY,CAAC,OAAO;AAClB,OAAG,KAAK;;;;;;;;;;KAUP;EACH,CAAC;AAED,wBAAsB;AAEtB,QAAM,YAAYiC,cAAa;AAC/B,QAAM,UAAU,GAAG,SAAS;AAC5B,QAAM,UAAU,GAAG,SAAS;AAE5B,aAAW,YAAY,CAAC,SAAS,OAAO,GAAG;AACzC,QAAI,CAACjC,aAAW,QAAQ,GAAG;AACzB;IACF;AACA,QAAI;AACFa,cAAO,UAAU,EAAE,OAAO,KAAK,CAAC;IAClC,QAAQ;IAER;EACF;AACF;AQ1iBO,SAAS,+BAA+B,UAAwC;AACrF,SAAO,SAAS,IAAI,CAAC,YAAY;AAC/B,QAAI,QAAQ,iBAAkB,QAAO;AACrC,WAAO,EAAE,GAAG,SAAS,kBAAkB,gBAAgB,QAAQ,WAAW,MAAM,EAAE;EACpF,CAAC;AACH;AAGO,SAAS,oBACd,OACA,YACkC;AAClC,QAAM,UAAU,MAAM,oBAAoB;AAC1C,QAAM,OAAyC,CAAC;AAChD,MAAI,CAAC,QAAS,QAAO;AAErB,aAAW,CAAC,IAAI,IAAI,KAAK,QAAQ,QAAQ,GAAG;AAC1C,QAAI,cAAc,CAAC,WAAW,IAAI,EAAE,EAAG;AACvC,SAAK,EAAE,IAAI,EAAE,IAAI,GAAI,KAAiC;EACxD;AAEA,SAAO;AACT;AAQO,SAAS,iBAAiB,SAA8B;AAC7D,SAAO,KAAK,UAAU;IACpB,QAAQ;IACR,QAAQ;IACR,QAAQ,kBAAkB,aAAa;IACvC,QAAQ,kBAAkB,aAAa;IACvC,QAAQ;IACR,QAAQ,gBAAgB,QAAQ;IAChC,QAAQ,MAAM;IACd,QAAQ,MAAM;IACd,QAAQ,MAAM;IACd,QAAQ,MAAM;IACd,QAAQ,MAAM,gBAAgB;IAC9B,QAAQ,gCAAgC;EAC1C,CAAC;AACH;AAGO,SAAS,aAAa,UAAwC;AACnE,SAAO,uBAAuB,QAAQ;AACxC;AA2BO,SAAS,mBACd,gBACA,iBACA,aAAuB,CAAC,GACxB,YAA8C,kBAC9C,gBACmB;AACnB,QAAM,YAAY,IAAI,IAAI,eAAe,IAAI,CAAC,YAAY,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAC;AAChF,QAAM,aAAa,IAAI,IAAI,gBAAgB,IAAI,CAAC,YAAY,QAAQ,EAAE,CAAC;AACvE,QAAM,eAAe,IAAI,IAAI,UAAU;AACvC,QAAM,UAA+B,CAAC;AACtC,QAAM,oBAA8B,CAAC;AACrC,MAAI,WAAW;AACf,MAAI,eAAe;AAEnB,kBAAgB,QAAQ,CAAC,SAAS,cAAc;AAC9C,UAAM,SAAS,UAAU,IAAI,QAAQ,EAAE;AACvC,QAAI,CAAC,QAAQ;AACX,kBAAY;AACZ,cAAQ,KAAK,EAAE,SAAS,UAAU,CAAC;AACnC,sBAAgB,IAAI,QAAQ,IAAI,UAAU,OAAO,CAAC;AAClD;IACF;AACA,UAAM,kBAAkB,gBAAgB,IAAI,OAAO,EAAE,KAAK,UAAU,MAAM;AAC1E,UAAM,mBAAmB,UAAU,OAAO;AAC1C,oBAAgB,IAAI,QAAQ,IAAI,gBAAgB;AAChD,QAAI,aAAa,IAAI,QAAQ,EAAE,KAAK,oBAAoB,kBAAkB;AACxE,sBAAgB;AAChB,cAAQ,KAAK,EAAE,SAAS,UAAU,CAAC;IACrC;EACF,CAAC;AAED,aAAW,WAAW,gBAAgB;AACpC,QAAI,CAAC,WAAW,IAAI,QAAQ,EAAE,GAAG;AAC/B,wBAAkB,KAAK,QAAQ,EAAE;IACnC;EACF;AAEA,SAAO;IACL;IACA;IACA,QAAQ,EAAE,KAAK,UAAU,SAAS,cAAc,SAAS,kBAAkB,OAAO;EACpF;AACF;AhBtEO,SAAS,eAAe,UAAyB,SAAqC;AAC3F,MAAI,SAAS;AAEb,MAAI,QAAQ,KAAK;AACf,aAAS,6BAA6B,QAAQ,QAAQ,GAAG;EAC3D;AAEA,SAAO,kCAAkC,QAAQ,QAAQ,MAAM,QAAQ,EAAE;AAC3E;AAwDA,SAAS,sBACP,OACA,gBACA,iBACA,aAAuB,CAAC,GAClB;AACN,QAAM,OAAO,mBAAmB,gBAAgB,iBAAiB,YAAY,gBAAgB;AAC7F;IACE,MAAM;IACN,KAAK;IACL,KAAK;IACL,oBAAoB,KAAK;EAC3B;AACF;AAEA,SAAS,uBAAuB,cAA8B;AAC5D,MAAI,eAAe,GAAI,QAAO;AAC9B,SAAO,KAAK,IAAI,cAAc,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,qBAAqB,IAAI,CAAC,CAAC,CAAC;AACpF;AAEA,SAAS,cAAiB,OAAY,YAA2B;AAC/D,QAAM,SAAS,MAAM,KAAK,EAAE,QAAQ,WAAW,GAAG,MAAM,CAAC,CAAQ;AACjE,QAAM,QAAQ,CAAC,MAAM,UAAU;AAC7B,WAAO,QAAQ,UAAU,EAAG,KAAK,IAAI;EACvC,CAAC;AACD,SAAO,OAAO,OAAO,CAAC,UAAU,MAAM,SAAS,CAAC;AAClD;AAEO,SAAS,sBACd,OACA,UACA,YACyE;AACzE,MAAI,UAAU;AACd,MAAI,YAAY;AAChB,QAAM,QAAQ,SAAS;AACvB,QAAM,SAA2B;IAC/B,UAAU;IACV,WAAW;IACX,eAAe;IACf,gBAAgB;IAChB,qBAAqB;IACrB,kBAAkB;IAClB,0BAA0B;IAC1B,uBAAuB;EACzB;AAEA,QAAM,SAAS,SAAS,IAAI,CAAC,YAAY;AACvC,UAAM,kBAAkB,QAAQ,gBAAgB,QAAQ;AACxD,UAAM,cAAc,MAAM,QAAQ,QAAQ,UAAU,IAAI,QAAQ,aAAa;AAC7E,QAAI,eAAe,QAAQ,iCAAiC,iBAAiB;AAC3E,aAAO,aAAa;AACpB,mBAAa;AACb,mBAAa,WAAW,KAAK;AAC7B,aAAO;IACT;AAEA,WAAO,iBAAiB;AACxB,QAAI;AACF,aAAO,uBAAuB;AAC9B,YAAM,0BAA0B,YAAY,IAAI;AAChD,UAAI;AACJ,UAAI;AACF,eAAO,MAAM,eAAe,QAAQ,EAAE;MACxC,UAAA;AACE,eAAO,oBAAoB,YAAY,IAAI,IAAI;MACjD;AAEA,aAAO,4BAA4B;AACnC,YAAM,+BAA+B,YAAY,IAAI;AACrD,UAAI;AACJ,UAAI;AACF,eAAO,oBAAoB,IAAI;MACjC,UAAA;AACE,eAAO,yBAAyB,YAAY,IAAI,IAAI;MACtD;AAEA,gBAAU;AACV,aAAO;QACL,GAAG;QACH,YAAY;QACZ,8BAA8B,2BAA2B,IAAI;MAC/D;IACF,QAAQ;AACN,aAAO,kBAAkB;AACzB,aAAO;IACT,UAAA;AACE,mBAAa;AACb,mBAAa,WAAW,KAAK;IAC/B;EACF,CAAC;AAED,SAAO,EAAE,UAAU,QAAQ,SAAS,OAAO;AAC7C;AAEA,eAAe,4BACb,WACA,WACA,YACA,MACiC;AACjC,SAAO,IAAI,QAAQ,CAAC,eAAe,iBAAiB;AAClD,UAAM,SAAS,IAAI,OAAO,WAAW;MACnC,YAAY,EAAE,WAAW,YAAY,KAAK;IAC5C,CAAC;AACD,WAAO,KAAK,WAAW,CAAC,YAAoC,cAAc,OAAO,CAAC;AAClF,WAAO,KAAK,SAAS,YAAY;AACjC,WAAO,KAAK,QAAQ,CAAC,SAAS;AAC5B,UAAI,SAAS,GAAG;AACd,qBAAa,IAAI,MAAM,qCAAqC,IAAI,EAAE,CAAC;MACrE;IACF,CAAC;EACH,CAAC;AACH;AAEA,eAAe,kBACb,OACA,UACA,WACwD;AACxD,QAAM,gBAAgB,SAAS,OAAO,CAAC,YAAY;AACjD,UAAM,kBAAkB,QAAQ,gBAAgB,QAAQ;AACxD,UAAM,cAAc,MAAM,QAAQ,QAAQ,UAAU,IAAI,QAAQ,aAAa;AAC7E,WAAO,CAAC,eAAe,QAAQ,iCAAiC;EAClE,CAAC;AAED,MAAI,cAAc,WAAW,GAAG;AAC9B,WAAO,EAAE,UAAU,SAAS,MAAM;EACpC;AAEA,QAAM,cAAc,YAAY,uBAAuB,cAAc,MAAM,IAAI;AAC/E,MAAI,eAAe,GAAG;AACpB,WAAO,sBAAsB,OAAO,QAAQ;EAC9C;AAEA,QAAM,OAAO,oBAAoB,KAAK;AACtC,MAAI;AACF,UAAM,WACJ,MAAM,QAAQ;MACZ;QACE,cAAc,IAAI,CAAC,YAAY,QAAQ,EAAE;QACzC;MACF,EAAE;QAAI,CAAC,eACL,4BAA4B,WAAY,MAAM,MAAM,YAAY,IAAI;MACtE;IACF,GACA,KAAK;AACP,UAAM,YAAY,IAAI,IAAI,QAAQ,OAAO,CAAC,SAAS,KAAK,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;AAE5F,WAAO;MACL,SAAS,UAAU,OAAO;MAC1B,UAAU,SAAS,IAAI,CAAC,YAAY;AAClC,cAAM,SAAS,UAAU,IAAI,QAAQ,EAAE;AACvC,YAAI,CAAC,QAAQ,QAAQ,OAAO,mBAAmB,KAAM,QAAO;AAC5D,eAAO;UACL,GAAG;UACH,YAAY,OAAO;UACnB,8BAA8B,OAAO;QACvC;MACF,CAAC;IACH;EACF,QAAQ;AACN,WAAO,sBAAsB,OAAO,QAAQ;EAC9C;AACF;AAEA,eAAsB,kBACpB,OACA,UACA,SAC0B;AAC1B,QAAM,EAAE,cAAc,SAAS,QAAQ,YAAY,WAAW,IAAI;AAClE,QAAM,gBAAgB,aAAa,SAAS;AAE5C,MAAI,CAAC,eAAe;AAClB,iBAAa,EAAE,OAAO,MAAM,MAAM,OAAO,YAAY,UAAU,SAAS,OAAO,CAAC;EAClF;AAEA,QAAM,gBAAgB,YAAY,IAAI;AACtC,QAAM,uBAAuB,+BAA+B,QAAQ;AACpE,SAAO,WAAW,YAAY,IAAI,IAAI;AAEtC,MAAI,SAAS,EAAE,UAAU,sBAAsB,SAAS,MAAM;AAC9D,MAAI,aAAa,SAAS,cAAc;AACtC,UAAM,YAAY,YAAY,IAAI;AAClC,aACE,QAAQ,qBAAqB,QACzB,SACA,MAAM,kBAAkB,OAAO,sBAAsB,QAAQ,iBAAiB;AACpF,WAAO,OAAO,YAAY,IAAI,IAAI;EACpC;AAEA,MAAI,QAAQ,eAAe,OAAO;AAChC,QAAI,aAAa,SAAS,eAAe;AACvC;QACE;QACA,aAAa,OAAO;QACpB,OAAO;QACP,aAAa;MACf;IACF,WAAW,aAAa,SAAS,eAAe,OAAO,SAAS;AAC9D,4BAAsB,OAAO,aAAa,OAAO,UAAU,OAAO,QAAQ;IAC5E;EACF;AAEA,MAAI,eAAe;AACjB,iBAAa,EAAE,OAAO,MAAM,MAAM,OAAO,YAAY,UAAU,OAAO,SAAS,OAAO,CAAC;EACzF;AAEA,QAAM,QAAQ,eAAe,OAAO,UAAU,OAAO;AACrD,SAAO,QAAQ,YAAY,IAAI,IAAI;AACnC,SAAO;IACL;IACA;IACA,WAAW;IACX,GAAI,gBAAgB,EAAE,WAAW,KAAK,IAAI,CAAC;IAC3C;IACA,gBAAgB,gBAAgB,aAAa,iBAAiB,aAAa,OAAO;EACpF;AACF;AAQA,eAAe,eACb,OACA,SACA,YACiC;AACjC,QAAM,aAAa,YAAY,IAAI;AACnC,QAAM,SAA0B,EAAE,OAAO,EAAE;AAC3C,QAAM,WAAW,QAAQ,YAAY;AAGrC,MAAI,UAAU;AACZ,UAAM,KAAK,YAAY,IAAI;AAC3B,UAAM,SAAS,mBAAmB,MAAM,IAAI;AAC5C,WAAO,YAAY,YAAY,IAAI,IAAI;AAEvC,QAAI,WAAW,MAAM;AAEnB,YAAM,UAAU,oBAAI,IAA8B;AAClD,iBAAW,CAAC,IAAI,IAAI,KAAK,OAAO,QAAQ,OAAO,IAAI,GAAG;AACpD,gBAAQ,IAAI,IAAI,IAAI;MACtB;AACA,YAAM,kBAAkB,OAAO;AAE/B,UAAI,QAAQ,WAAW;AACrB,cAAM,kBAAkB,MAAM,qBAAqB,OAAO,QAAQ;AAClE,qBAAa;UACX,OAAO,MAAM;UACb,OAAO;UACP,aAAa,gBAAgB;QAC/B,CAAC;AACD,eAAO,kBAAkB,OAAO,iBAAiB;UAC/C,cAAc,EAAE,MAAM,cAAc,OAAO;UAC3C;UACA;UACA;UACA;QACF,CAAC;MACH;AAEA,YAAM,UAAU,MAAM,YAAY;AAClC,UAAI,CAAC,SAAS;AACZ,eAAO;MACT;AAGA,mBAAa;QACX,OAAO,MAAM;QACb,OAAO;QACP,aAAa,OAAO,SAAS;MAC/B,CAAC;AAED,mBAAa,EAAE,OAAO,MAAM,MAAM,OAAO,WAAW,CAAC;AAErD,YAAM,KAAK,YAAY,IAAI;AAC3B,YAAM,cAAc,MAAM,QAAQ;QAChC,MAAM,gBAAgB,OAAO,WAAW,OAAO,QAAQ;MACzD;AACA,aAAO,eAAe,YAAY,IAAI,IAAI;AAE1C,UAAI,YAAY,YAAY;AAC1B,qBAAa;UACX,OAAO,MAAM;UACb,OAAO;UACP,cAAc,YAAY,YAAY;QACxC,CAAC;AAED,cAAM,KAAK,YAAY,IAAI;AAC3B,cAAM,kBAAkB,MAAM,QAAQ;UACpC,MAAM,gBAAgB,OAAO,UAAU,YAAY,cAAc,CAAC,GAAG,YAAY,IAAI;QACvF;AACA,eAAO,OAAO,YAAY,IAAI,IAAI;AAElC,eAAO,kBAAkB,OAAO,iBAAiB;UAC/C,cAAc;YACZ,MAAM;YACN;YACA,YAAY,YAAY,cAAc,CAAC;YACvC,gBAAgB,YAAY;UAC9B;UACA;UACA;UACA;UACA;QACF,CAAC;MACH;AAEA,aAAO,kBAAkB,OAAO,OAAO,UAAU;QAC/C,cAAc,EAAE,MAAM,aAAa,OAAO;QAC1C;QACA;QACA;QACA;MACF,CAAC;IACH;EACF;AAEA,MAAI,QAAQ,WAAW;AACrB,WAAO,QAAQ,YAAY,IAAI,IAAI;AACnC,WAAO;EACT;AAGA,SAAO,cAAc,OAAO,SAAS,YAAY,QAAQ,UAAU;AACrE;AAKA,eAAe,cACb,OACA,SACA,YACA,SAA0B,EAAE,OAAO,EAAE,GACrC,aAAa,YAAY,IAAI,GACI;AACjC,QAAM,cAAc,KAAK,MAAM,SAAS,MAAM,IAAI,cAAc;AAChE,QAAM,UAAU,MAAM,YAAY;AAClC,OAAK,IAAI,WAAW;AAEpB,MAAI,CAAC,SAAS;AACZ,WAAO;EACT;AAEA,MAAI;AACF,UAAM,aAAa,KAAK,MAAM,SAAS,MAAM,IAAI,OAAO;AACxD,UAAM,KAAK,YAAY,IAAI;AAC3B,UAAM,QAAQ,MAAM,KAAK;MACvB,MAAM,QAAQ;MACd,IAAI,QAAQ;MACZ,MAAM,QAAQ;MACd,wBAAwB;MACxB,YAAY,CAAC,aAAa;AACxB,qBAAa;UACX,OAAO,MAAM;UACb,OAAO;UACP,aAAa,SAAS;UACtB,UAAU,SAAS;UACnB,cAAc,SAAS;QACzB,CAAC;MACH;IACF,CAAC;AACD,SAAK,IAAI,UAAU;AACnB,WAAO,OAAO,YAAY,IAAI,IAAI;AAElC,UAAM,KAAK,YAAY,IAAI;AAC3B,UAAM,oBAAoB,+BAA+B,KAAK;AAC9D,WAAO,WAAW,YAAY,IAAI,IAAI;AAEtC,UAAM,KAAK,YAAY,IAAI;AAC3B,UAAM,SACJ,QAAQ,qBAAqB,QACzB,EAAE,UAAU,mBAAmB,SAAS,MAAM,IAC9C,MAAM,kBAAkB,OAAO,mBAAmB,QAAQ,iBAAiB;AACjF,WAAO,OAAO,YAAY,IAAI,IAAI;AAGlC,UAAM,OAAO,oBAAoB,KAAK;AAEtC,QAAI,QAAQ,eAAe,OAAO;AAEhC,YAAM,eAAe,QAAQ,QAAQ,QAAQ,QAAQ,MAAM;AAE3D,YAAM,YAAY,eAAe,mBAAmB,MAAM,MAAM,OAAO,UAAU,IAAI,IAAI;AACzF,UAAI,WAAW;AACb,YAAI,aAAc,4BAA2B,MAAM,IAAI;AAEvD,kCAA0B,MAAM,IAAI;MACtC,OAAO;AACL,2BAAmB,GAAG,KAAK,qBAAqB;UAC9C,OAAO,MAAM;UACb,UAAU,OAAO,SAAS;QAC5B,CAAC;MACH;IACF;AAEA,iBAAa,EAAE,OAAO,MAAM,MAAM,OAAO,YAAY,UAAU,OAAO,SAAS,OAAO,CAAC;AAEvF,UAAM,WAAW,eAAe,OAAO,UAAU,OAAO;AACxD,WAAO,QAAQ,YAAY,IAAI,IAAI;AACnC,WAAO,EAAE,OAAO,OAAO,UAAU,WAAW,OAAO,OAAO;EAC5D,SAAS,KAAK;AACZ,YAAQ,MAAM,kBAAkB,MAAM,IAAI,KAAK,GAAG;AAClD,WAAO,EAAE,OAAO,OAAO,CAAC,GAAG,WAAW,MAAM;EAC9C;AACF;AAKA,eAAsB,aACpB,UAAuB,CAAC,GACxB,YACuB;AACvB,QAAM,aAAa,KAAK,MAAM,cAAc;AAC5C,QAAM,SAAS,uBAAuB;AACtC,QAAM,UAAyC,CAAC;AAChD,QAAM,cAA6B,CAAC;AACpC,QAAM,kBAA+B,CAAC;AACtC,QAAM,kBAA0C,CAAC;AAEjD,QAAM,cAAc,QAAQ,QAAQ,SAChC,IAAI,IAAI,QAAQ,OAAO,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,IAClD;AAGJ,QAAM,eAAe,OAAO,OAAO,CAAC,UAAU;AAC5C,QAAI,eAAe,CAAC,YAAY,IAAI,MAAM,KAAK,YAAY,CAAC,GAAG;AAC7D,aAAO;IACT;AACA,WAAO;EACT,CAAC;AAGD,QAAM,eAAe,aAAa,IAAI,CAAC,UAAU,eAAe,OAAO,SAAS,UAAU,CAAC;AAE3F,QAAM,UAAU,MAAM,QAAQ,IAAI,YAAY;AAG9C,QAAM,UAA2C,CAAC;AAClD,aAAW,UAAU,SAAS;AAC5B,QAAI,QAAQ;AACV,sBAAgB,KAAK,OAAO,KAAK;AACjC,cAAQ,OAAO,MAAM,IAAI,IAAI,OAAO;AACpC,kBAAY,KAAK,GAAG,OAAO,KAAK;AAChC,UAAI,OAAO,QAAQ;AACjB,gBAAQ,OAAO,MAAM,IAAI,IAAI,OAAO;MACtC;AACA,UAAI,OAAO,kBAAkB,MAAM;AACjC,wBAAgB,OAAO,MAAM,IAAI,IAAI,OAAO;MAC9C;IACF;EACF;AAEA,OAAK,IAAI,UAAU;AACnB,SAAO;IACL,UAAU;IACV;IACA,QAAQ;IACR;IACA,iBAAiB,OAAO,KAAK,eAAe,EAAE,SAAS,IAAI,kBAAkB;EAC/E;AACF;AiBhjBA,IAAM,uBAAuB,oBAAI,QAA4C;AAE7E,SAAS,oBAAoB,WAAmB,WAA2B;AACzE,SAAO,GAAG,SAAS,KAAK,SAAS;AACnC;AAMA,SAAS,uBAAuB,YAA+C;AAC7E,QAAM,SAAS,qBAAqB,IAAI,WAAW,QAAQ;AAC3D,MAAI,OAAQ,QAAO;AAEnB,QAAM,eAAe,oBAAI,IAAuB;AAChD,aAAW,SAAS,WAAW,QAAQ;AACrC,QAAI,CAAC,aAAa,IAAI,MAAM,IAAI,EAAG,cAAa,IAAI,MAAM,MAAM,KAAK;EACvE;AACA,QAAM,mBAAmB,oBAAI,IAAyB;AACtD,aAAW,CAAC,WAAW,QAAQ,KAAK,OAAO,QAAQ,WAAW,OAAO,GAAG;AACtE,eAAW,WAAW,UAAU;AAC9B,YAAM,MAAM,oBAAoB,WAAW,QAAQ,EAAE;AACrD,UAAI,CAAC,iBAAiB,IAAI,GAAG,EAAG,kBAAiB,IAAI,KAAK,OAAO;IACnE;EACF;AAEA,QAAM,SAAS,EAAE,cAAc,iBAAiB;AAChD,uBAAqB,IAAI,WAAW,UAAU,MAAM;AACpD,SAAO;AACT;AAEA,SAAS,wBACP,YACA,WAC6B;AAC7B,QAAM,SAAS,uBAAuB,UAAU;AAChD,QAAM,QAAQ,OAAO,aAAa,IAAI,UAAU,SAAS;AACzD,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO;IACL;IACA,MAAM,OAAO,iBAAiB;MAC5B,oBAAoB,UAAU,WAAW,UAAU,SAAS;IAC9D;EACF;AACF;AAEA,SAAS,0BACP,YACA,aACS;AACT,QAAM,qBAAqB,aAAa;AACxC,MAAI,OAAO,uBAAuB,SAAU,QAAO;AACnD,SAAO,YAAY,sBAAsB;AAC3C;AAEA,SAAS,uBACP,aACA,aACsC;AACtC,MAAI,CAAC,eAAe,CAAC,0BAA0B,YAAY,MAAM,WAAW,GAAG;AAC7E,WAAO;EACT;AAEA,SAAO,YAAY,YAAY,SAAS,KAAK,YAAY,KAAK,MAAM,kBAAkB;AACxF;AAEA,SAAS,mBACP,MACA,MACA;AACA,SAAO,KAAK,oBAAoB,MAAM,oBAAoB,gBAAgB,KAAK,WAAW,MAAM;AAClG;AAEA,SAAS,mCACP,SACA,WACA,cAAc,0BAA0B,UAAU,WAAW,UAAU,SAAS,GAC3D;AACrB,QAAM,EAAE,OAAO,KAAK,IAAI;AACxB,QAAM,cAAc,OAAO,MAAM,kBAAkB,EAAE,IAAI,UAAU,SAAS,IAAI;AAChF,QAAM,WAAW,uBAAuB,aAAa,WAAW;AAChE,QAAM,OAAO,WACT;IACE,GAAG,YAAY;IACf,UAAU,YAAY,YAAY,IAAI,CAAC,eAAe,qBAAqB,UAAU,CAAC;EACxF,IACA,OACE,MAAM,eAAe,UAAU,SAAS,IACxC;AAEN,MAAI,CAAC,MAAM;AACT,WAAO,EAAE,QAAQ,YAAY;EAC/B;AAEA,QAAM,kBAAkB,mBAAmB,MAAM,IAAI;AACrD,QAAM,eACJ,KAAK,kBACJ,WACG,wBAAwB,UAAU,WAAW,UAAU,SAAS,IAChE;IACE,UAAU;IACV,UAAU;IACV,gBAAgB;IAChB,KAAK;EACP;AAEN,SAAO;IACL,QAAQ;IACR,MAAM;MACJ,GAAG;MACH;MACA,kBAAkB;MAClB,YAAY,KAAK,cAAc,oBAAoB,IAAI;MACvD,8BAA8B,2BAA2B,IAAI;MAC7D,eAAe;IACjB;EACF;AACF;AAEA,UAAU,wBAAwB,OAAwD;AACxF,aAAW,cAAc,MAAM,aAAa;AAC1C,UAAM,yBAAyB,UAAU;EAC3C;AACF;AAWO,SAAS,iCACd,YACA,WAC6B;AAC7B,QAAM,UAAU,wBAAwB,YAAY,SAAS;AAC7D,MAAI,CAAC,QAAS,QAAO,EAAE,QAAQ,gBAAgB;AAE/C,QAAM,cAAc,0BAA0B,UAAU,WAAW,UAAU,SAAS;AACtF,QAAM,cAAc,QAAQ,OACxB,QAAQ,MAAM,kBAAkB,EAAE,IAAI,UAAU,SAAS,IACzD;AACJ,QAAM,WAAW,uBAAuB,aAAa,WAAW;AAChE,MAAI,CAAC,YAAY,YAAY,KAAK,cAAc,MAAM;AACpD,WAAO,mCAAmC,SAAS,WAAW,WAAW;EAC3E;AAEA,QAAM,OAAO,YAAY;AACzB,SAAO;IACL,QAAQ;IACR,MAAM;MACJ,GAAG;MACH;MACA,kBAAkB,mBAAmB,MAAM,QAAQ,IAAI;MACvD,8BAA8B,2BAA2B,IAAI;MAC7D,eACE,KAAK,iBAAiB,wBAAwB,UAAU,WAAW,UAAU,SAAS;IAC1F;IACA,UAAU,wBAAwB,WAAW;IAC7C,cAAc,YAAY,YAAY;EACxC;AACF;ACvLO,SAAS,wBAAwB,UAA0C;AAChF,MAAI,UAAU;AACZ,WAAO,mBAAmB,QAAQ;EACpC;AAEA,MAAI,CAAC,gBAAgB,GAAG;AACtB,WAAO,CAAC;EACV;AAEA,QAAM,YAAY,CAAC,OACjB,GACG;IACC;;;;;;;;EAQF,EACC,IAAI;AAET,MAAI,OAAO,oBAAoB,SAAS;AACxC,MAAI,QAAQ,MAAM;AAChB,WAAO,YAAY,SAAS;EAC9B;AAEA,UAAQ,QAAQ,CAAC,GAAG,IAAI,CAAC,SAAS;IAChC,cAAc,IAAI,iBAAiB;IACnC,aAAa,OAAO,IAAI,gBAAgB,EAAE;IAC1C,aAAa,OAAO,IAAI,gBAAgB,EAAE;IAC1C,SAAS,OAAO,IAAI,eAAe,EAAE,EAClC,MAAM,GAAG,EACT,OAAO,OAAO,EACd,KAAK;IACR,cAAc,OAAO,IAAI,iBAAiB,CAAC;IAC3C,cAAc,IAAI,iBAAiB,OAAO,OAAO,OAAO,IAAI,aAAa;EAC3E,EAAE;AACJ;AC7CA,IAAM,oBAAoB;AAC1B,IAAM,uBAAuB;AAC7B,IAAM,qBAAqB;AAK3B,IAAI,yBAAwC;AAErC,SAAS,4BAA2C;AACzD,SAAO;AACT;AAEO,SAAS,0BAA0BC,OAA2B;AACnE,2BAAyBA;AAC3B;AAEO,IAAM,+BAAN,cAA2C,MAAM;EACtD,cAAc;AACZ,UAAM,sCAAsC;AAC5C,SAAK,OAAO;EACd;AACF;AAEA,SAAS,cAAsB;AAC7B,MAAI,QAAQ,IAAI,mBAAoB,QAAO,QAAQ,IAAI;AAEvD,QAAM,kBAAkBH,UAAS;AACjC,MAAI,oBAAoB,UAAU;AAChC,WAAOP,OAAKG,SAAQ,GAAG,WAAW,uBAAuB,UAAU;EACrE;AACA,MAAI,oBAAoB,SAAS;AAC/B,UAAM,UAAU,QAAQ,IAAI,WAAW,QAAQ,IAAI;AACnD,WAAOH,OAAK,WAAWA,OAAKG,SAAQ,GAAG,WAAW,SAAS,GAAG,UAAU;EAC1E;AACA,SAAOH,OAAK,QAAQ,IAAI,iBAAiBA,OAAKG,SAAQ,GAAG,UAAU,OAAO,GAAG,UAAU;AACzF;AAEA,SAAS,iBAAyB;AAChC,SAAOH,OAAK,YAAY,GAAG,iBAAiB;AAC9C;AAEO,SAAS,sBAA+B;AAC7C,SAAO,QAAQ,IAAI,yBAAyB;AAC9C;AAEA,SAAS,qBAAqB,IAA0B;AACtD,KAAG,KAAK;;;;;;;;;;;;;GAaP;AACH;AAEA,SAAS,0BAA0B,IAA0B;AAC3D,KAAG,KAAK;;;;;;;;GAQP;AACH;AAEA,SAAS,kBAAkB,IAA0B;AACnD,KAAG,KAAK;;;;;GAKP;AACD,uBAAqB,EAAE;AACvB,4BAA0B,EAAE;AAC9B;AAEA,SAAS,uBAAuB,IAA4B;AAC1D,MACE,CAAC,YAAY,IAAI,YAAY,KAC7B,CAAC,aAAa,IAAI,cAAc,KAAK,KACrC,CAAC,aAAa,IAAI,cAAc,OAAO,GACvC;AACA,WAAO;EACT;AAEA,QAAM,MAAM,GAAG,QAAQ,oDAAoD,EAAE,IAAI;AAGjF,SAAO,OAAO,KAAK,SAAS,CAAC;AAC/B;AAEA,SAAS,6BAA6B,IAA4B;AAChE,QAAM,cAAc,eAAe,EAAE;AACrC,MAAI,cAAc,EAAG,QAAO;AAE5B,QAAM,gBAAgB,uBAAuB,EAAE;AAC/C,MAAI,gBAAgB,EAAG,QAAO;AAE9B,SAAO,YAAY,IAAI,WAAW,IAAI,IAAI;AAC5C;AAEA,SAAS,kBAAkB,IAA6B;AACtD,SAAO,YAAY,IAAI,YAAY,KAAK,YAAY,IAAI,WAAW;AACrE;AAEA,SAAS,sBAAsB,IAA0B;AACvD,oBAAkB,EAAE;AACpB,iBAAe,IAAI,oBAAoB;AACvC,KAAG;IACD;;;;;EAKF,EAAE,IAAI,OAAO,oBAAoB,CAAC;AACpC;AAEA,SAASkC,cAAa,IAAoB,QAAsB;AAC9D,QAAM,iBAAiB,6BAA6B,EAAE;AACtD,MAAI,mBAAmB,KAAK,CAAC,kBAAkB,EAAE,GAAG;AAClD,0BAAsB,EAAE;AACxB;EACF;AAEA,sBAAoB,IAAI;IACtB;IACA;IACA,eAAe;IACf,aAAa;IACb,cAAc,CAAC,aAAa,iBAAiB;IAC7C,YAAY;MACV,EAAE,SAAS,GAAG,SAAS,qBAAqB;MAC5C,EAAE,SAAS,GAAG,SAAS,0BAA0B;IACnD;EACF,CAAC;AAED,MAAI,iBAAiB,sBAAsB;AACzC,0BAAsB,EAAE;EAC1B;AACF;AAEO,SAAS,YAAe,IAAkC;AAC/D,QAAM,YAAY,eAAe;AACjC,QAAM,KAAK,OAAO,SAAS;AAC3B,MAAI,CAAC,GAAI,OAAM,IAAI,6BAA6B;AAEhD,MAAI;AACF,QAAI,0BAA0B,MAAM,WAAW;AAC7CA,oBAAa,IAAI,SAAS;AAC1B,gCAA0B,SAAS;IACrC;AACA,WAAO,GAAG,EAAE;EACd,UAAA;AACE,OAAG,MAAM;EACX;AACF;ACxKA,IAAM,kBAAkB,oBAAI,IAA4B;AAiBxD,SAAS,eAAe,WAAqC;AAC3D,QAAM,aAAa,0BAA0B,SAAS;AACtD,SAAO,KAAK,UAAU,CAAC,WAAW,WAAW,WAAW,SAAS,CAAC;AACpE;AAEA,SAAS,gBAAgB,UAAkC;AACzD,SAAO,SAAS,QAAQ,gBAAgB,SAAS,QAAQ;AAC3D;AAEA,SAAS,cAAc,WAA+C;AACpE,SAAO,UAAU,KAAK,CAAC,GAAG,MAAM;AAC9B,UAAM,gBAAgB,gBAAgB,CAAC,IAAI,gBAAgB,CAAC;AAC5D,WAAO,iBAAiB,EAAE,eAAe,EAAE;EAC7C,CAAC;AACH;AAEA,SAAS,sBAAwC;AAC/C,SAAO,cAAc,MAAM,KAAK,gBAAgB,OAAO,CAAC,CAAC;AAC3D;AAEA,SAAS,kBACP,UACsC;AACtC,QAAM,YAAY,0BAA0B,SAAS,SAAS;AAC9D,SAAO;IACL;IACA,SAAS;MACP,GAAG,SAAS;MACZ,IAAI,UAAU;MACd,MAAM,uBAAuB,SAAS;IACxC;EACF;AACF;AAEA,SAAS,qBAAqB,UAAgE;AAC5F,QAAM,MAAM,eAAe,SAAS,SAAS;AAC7C,QAAM,QAAQ;IACZ,GAAG;IACH,cAAc,gBAAgB,IAAI,GAAG,GAAG,gBAAgB,KAAK,IAAI;EACnE;AACA,kBAAgB,IAAI,KAAK,KAAK;AAC9B,SAAO;AACT;AAEA,SAAS,iBAAiB,KAAkC;AAC1D,QAAM,YAAY,0BAA0B;IAC1C,WAAW,OAAO,IAAI,cAAc,EAAE;IACtC,WAAW,OAAO,IAAI,cAAc,EAAE;EACxC,CAAC;AACD,SAAO;IACL;IACA,SAAS;MACP,IAAI,UAAU;MACd,MAAM,uBAAuB,SAAS;MACtC,OAAO,OAAO,IAAI,SAAS,EAAE;MAC7B,WAAW,OAAO,IAAI,aAAa,EAAE;MACrC,cAAc,OAAO,IAAI,gBAAgB,CAAC;MAC1C,cAAc,IAAI,gBAAgB,OAAO,SAAY,OAAO,IAAI,YAAY;MAC5E,OAAO,KAAK,MAAM,OAAO,IAAI,cAAc,IAAI,CAAC;IAClD;IACA,cAAc,OAAO,IAAI,iBAAiB,CAAC;EAC7C;AACF;AAEO,SAAS,gBAAkC;AAChD,MAAI,oBAAoB,GAAG;AACzB,WAAO,oBAAoB;EAC7B;AAEA,SAAO,YAAY,CAAC,OAAO;AACzB,UAAM,OAAO,GACV;MACC;;;;;;;;;;;;;IAaF,EACC,IAAI;AAEP,WAAO,KAAK,IAAI,gBAAgB;EAClC,CAAC;AACH;AAEO,SAAS,eAAe,UAAgE;AAC7F,QAAM,aAAa,kBAAkB,QAAQ;AAC7C,MAAI,oBAAoB,GAAG;AACzB,WAAO,qBAAqB,UAAU;EACxC;AAEA,SAAO,YAAY,CAAC,OAAO;AACzB,UAAM,WAAW,GACd;MACC;;;;;IAKF,EACC,IAAI,WAAW,UAAU,WAAW,WAAW,UAAU,SAAS;AAGrE,UAAM,eAAe,OAAO,UAAU,iBAAiB,KAAK,IAAI,CAAC;AAEjE,OAAG;MACD;;;;;;;;;;;;;;;;;;;;IAoBF,EAAE;MACA,WAAW,UAAU;MACrB,WAAW,UAAU;MACrB,uBAAuB,WAAW,SAAS;MAC3C,WAAW,QAAQ;MACnB,WAAW,QAAQ;MACnB,WAAW,QAAQ;MACnB,WAAW,QAAQ,gBAAgB;MACnC,KAAK,UAAU,WAAW,QAAQ,KAAK;MACvC;IACF;AAEA,WAAO,EAAE,GAAG,YAAY,aAAa;EACvC,CAAC;AACH;AAEO,SAAS,gBACd,WACkB;AAClB,QAAM,sBAAsB,UAAU,IAAI,iBAAiB;AAC3D,MAAI,oBAAoB,GAAG;AACzB,eAAW,YAAY,qBAAqB;AAC1C,2BAAqB,QAAQ;IAC/B;AACA,WAAO,oBAAoB;EAC7B;AAEA,SAAO,YAAY,CAAC,OAAO;AACzB,UAAM,eAAe,GAClB,QAAQ,6DAA6D,EACrE,IAAI;AACP,UAAM,gBAAgB,IAAI;MACxB,aAAa,IAAI,CAAC,QAAQ;QACxB,eAAe;UACb,WAAW,OAAO,IAAI,cAAc,EAAE;UACtC,WAAW,OAAO,IAAI,cAAc,EAAE;QACxC,CAAC;QACD,OAAO,IAAI,iBAAiB,CAAC;MAC/B,CAAC;IACH;AAEA,UAAM,SAAS,GAAG;MAChB;;;;;;;;;;;;;;;;;;;;IAoBF;AAEA,UAAM,QAAQ,GAAG,YAAY,MAAM;AACjC,iBAAW,YAAY,qBAAqB;AAC1C,cAAM,MAAM,eAAe,SAAS,SAAS;AAC7C,eAAO;UACL,SAAS,UAAU;UACnB,SAAS,UAAU;UACnB,uBAAuB,SAAS,SAAS;UACzC,SAAS,QAAQ;UACjB,SAAS,QAAQ;UACjB,SAAS,QAAQ;UACjB,SAAS,QAAQ,gBAAgB;UACjC,KAAK,UAAU,SAAS,QAAQ,KAAK;UACrC,cAAc,IAAI,GAAG,KAAK,KAAK,IAAI;QACrC;MACF;IACF,CAAC;AAED,UAAM;AACN,UAAM,OAAO,GACV;MACC;;;;;;;;;;;;;IAaF,EACC,IAAI;AACP,WAAO,KAAK,IAAI,gBAAgB;EAClC,CAAC;AACH;AAEO,SAAS,eAAe,WAAmC;AAChE,QAAM,aAAa,0BAA0B,SAAS;AACtD,MAAI,oBAAoB,GAAG;AACzB,oBAAgB,OAAO,eAAe,UAAU,CAAC;AACjD;EACF;AAEA,cAAY,CAAC,OAAO;AAClB,OAAG;MACD;;;;IAIF,EAAE,IAAI,WAAW,WAAW,WAAW,SAAS;EAClD,CAAC;AACH;AClRO,IAAM,2BAA2B;AAEjC,IAAM,8BAAN,cAA0C,MAAM;EACrD,cAAc;AACZ,UAAM,uBAAuB;AAC7B,SAAK,OAAO;EACd;AACF;AAeA,IAAM,gBAAgB,oBAAI,IAA0B;AAEpD,SAAS,YAAY,WAAqC;AACxD,QAAM,aAAa,0BAA0B,SAAS;AACtD,SAAO,KAAK,UAAU,CAAC,WAAW,WAAW,WAAW,SAAS,CAAC;AACpE;AAEA,SAAS,eAAe,KAAoC;AAC1D,QAAM,YAAY,0BAA0B;IAC1C,WAAW,OAAO,IAAI,cAAc,EAAE;IACtC,WAAW,OAAO,IAAI,cAAc,EAAE;EACxC,CAAC;AACD,SAAO;IACL;IACA,OAAO,OAAO,IAAI,SAAS,EAAE;IAC7B,WAAW,OAAO,IAAI,cAAc,CAAC;EACvC;AACF;AAEO,SAAS,sBAAsB,OAA8B;AAClE,QAAM,QAAQ,MAAM,KAAK;AACzB,MAAI,CAAC,SAAS,MAAM,SAAS,yBAA0B,QAAO;AAC9D,SAAO;AACT;AAEO,SAAS,qBAAqC;AACnD,MAAI,oBAAoB,EAAG,QAAO,CAAC,GAAG,cAAc,OAAO,CAAC;AAE5D,SAAO;IAAY,CAAC,OAEhB,GACG;MACC;;;;;IAKF,EACC,IAAI,EACP,IAAI,cAAc;EACtB;AACF;AAEO,SAAS,mBAAmB,WAA6B,OAA6B;AAC3F,QAAM,kBAAkB,sBAAsB,KAAK;AACnD,MAAI,CAAC,iBAAiB;AACpB,UAAM,IAAI,4BAA4B;EACxC;AAEA,QAAM,sBAAsB,0BAA0B,SAAS;AAC/D,QAAM,QAAsB;IAC1B,WAAW;IACX,OAAO;IACP,WAAW,KAAK,IAAI;EACtB;AACA,MAAI,oBAAoB,GAAG;AACzB,kBAAc,IAAI,YAAY,mBAAmB,GAAG,KAAK;AACzD,WAAO;EACT;AAEA,SAAO,YAAY,CAAC,OAAO;AACzB,OAAG;MACD;;;;;;;IAOF,EAAE,IAAI,MAAM,UAAU,WAAW,MAAM,UAAU,WAAW,MAAM,OAAO,MAAM,SAAS;AACxF,WAAO;EACT,CAAC;AACH;AAEO,SAAS,mBAAmB,WAAmC;AACpE,QAAM,sBAAsB,0BAA0B,SAAS;AAC/D,MAAI,oBAAoB,GAAG;AACzB,kBAAc,OAAO,YAAY,mBAAmB,CAAC;AACrD;EACF;AAEA,cAAY,CAAC,OAAO;AAClB,OAAG;MACD;;;;IAIF,EAAE,IAAI,oBAAoB,WAAW,oBAAoB,SAAS;EACpE,CAAC;AACH;AC7EO,IAAM,yBAAyB;AA6B/B,SAAS,eAAe,OAAqC;AAClE,SAAO,MAAM,gBAAgB,MAAM,qBAAqB,MAAM;AAChE;AAEO,SAAS,oBAAoB,SAA8B;AAChE,SAAO,mBAAmB,OAAO;AACnC;AAEO,SAAS,uBAAuB,SAA8B;AACnE,SAAO,QAAQ,gBAAgB,QAAQ;AACzC;AAMO,SAAS,eACd,UACA,SACoB;AACpB,QAAM,EAAE,cAAc,OAAO,MAAM,IAAI,aAAa,IAAI;AAExD,QAAM,eAAe,oBAAI,IAAqC;AAC9D,QAAM,uBAAuB,oBAAI,IAAoB;AACrD,aAAW,QAAQ,cAAc;AAC/B,QAAI,MAAM,SAAS,KAAK,YAAY,MAAM,MAAM,MAAO;AACvD,iBAAa,IAAI,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,QAAQ,EAAE,CAAC;AAC9D,yBAAqB,IAAI,KAAK,YAAY,GAAG,IAAI;EACnD;AAEA,MAAI,gBAAgB;AACpB,MAAI,gBAAgB;AACpB,MAAI,cAAc;AAClB,MAAI,YAAY;AAChB,MAAI,mBAAmB;AACvB,MAAI,iBAAiB;AACrB,QAAM,mBAA+C,CAAC;AACtD,QAAM,WAAW,oBAAI,IAAkD;AAEvE,QAAM,WAAW,oBAAI,IAAkC;AACvD,QAAM,gBAAgB,oBAAI,IAA8B;AACxD,MAAI,QAAQ,MAAM;AAChB,UAAM,aAAa,kBAAkB,MAAM,EAAE;AAC7C,aAAS,IAAI,GAAG,IAAI,YAAY,KAAK,GAAG;AACtC,YAAM,MAAM,iBAAiB,gBAAgB,MAAM,CAAC,CAAC;AACrD,eAAS,IAAI,KAAK,EAAE,MAAM,KAAK,UAAU,GAAG,UAAU,EAAE,CAAC;AACzD,oBAAc,IAAI,KAAK,EAAE,MAAM,KAAK,OAAO,GAAG,QAAQ,GAAG,YAAY,GAAG,cAAc,EAAE,CAAC;IAC3F;EACF;AAEA,QAAM,kBAAkB,kCAAkC,UAAU,MAAM,EAAE;AAC5E,aAAW,WAAW,iBAAiB;AACrC,QAAI,eAAe,OAAO,EAAG;AAC7B,UAAM,YAAY,oBAAoB,OAAO;AAC7C,QAAI,MAAM,SAAS,cAAc,MAAM,MAAO;AAC9C,QAAI,MAAM,eAAe,MAAM,YAAY;AACzC,YAAM,WAAW,QAAQ;AACzB,UACE,CAAC,YACD,CAAC,MAAM,eACP,CAAC,MAAM,cACP,SAAS,SAAS,MAAM,eACxB,SAAS,QAAQ,MAAM,YACvB;AACA;MACF;IACF;AAEA,UAAM,WAAW,uBAAuB,OAAO;AAE/C,UAAM,eAAe,QAAQ,MAAM;AACnC,UAAM,gBAAgB,eAAe,QAAQ,KAAK;AAClD,qBAAiB;AACjB,qBAAiB;AACjB,mBAAe;AACf,iBAAa,QAAQ,MAAM,cAAc;AACzC,QAAI,QAAQ,MAAM,gBAAgB,YAAa,oBAAmB;AAClE,QAAI,WAAW,eAAgB,kBAAiB;AAEhD,UAAM,YAAY,qBAAqB,IAAI,SAAS;AACpD,QAAI,WAAW;AACb,YAAM,SAAS,aAAa,IAAI,SAAS;AACzC,aAAO,YAAY;AACnB,aAAO,YAAY;AACnB,aAAO,UAAU;IACnB;AAEA,UAAM,MAAM,iBAAiB,QAAQ;AACrC,QAAI,SAAS,SAAS,IAAI,GAAG;AAC7B,QAAI,CAAC,QAAQ;AACX,eAAS,EAAE,MAAM,KAAK,UAAU,GAAG,UAAU,EAAE;AAC/C,eAAS,IAAI,KAAK,MAAM;IAC1B;AACA,WAAO,YAAY;AACnB,WAAO,YAAY;AAEnB,QAAI,cAAc,cAAc,IAAI,GAAG;AACvC,QAAI,CAAC,aAAa;AAChB,oBAAc,EAAE,MAAM,KAAK,OAAO,GAAG,QAAQ,GAAG,YAAY,GAAG,cAAc,EAAE;AAC/E,oBAAc,IAAI,KAAK,WAAW;IACpC;AACA,UAAM,YAAY,QAAQ,MAAM,2BAA2B;AAC3D,UAAM,cAAc,QAAQ,MAAM,6BAA6B;AAC/D,UAAM,YAAY,QAAQ,MAAM,qBAAqB,YAAY;AACjE,gBAAY,SAAS,KAAK,IAAI,GAAG,SAAS;AAC1C,gBAAY,UAAU,QAAQ,MAAM;AACpC,gBAAY,cAAc;AAC1B,gBAAY,gBAAgB;AAE5B,QAAI,QAAQ,aAAa;AACvB,iBAAW,CAAC,OAAO,MAAM,KAAK,OAAO,QAAQ,QAAQ,WAAW,GAAG;AACjE,cAAM,QAAQ,SAAS,IAAI,KAAK;AAChC,YAAI,OAAO;AACT,gBAAM,UAAU;AAChB,gBAAM,YAAY;QACpB,OAAO;AACL,mBAAS,IAAI,OAAO,EAAE,QAAQ,UAAU,EAAE,CAAC;QAC7C;MACF;IACF;AAEA,QAAI,cAAc,iBAAiB;AACnC,aAAS,IAAI,GAAG,IAAI,iBAAiB,QAAQ,KAAK,GAAG;AACnD,UAAI,WAAW,iBAAiB,CAAC,EAAG,UAAU;AAC5C,sBAAc;AACd;MACF;IACF;AACA,QAAI,cAAc,wBAAwB;AACxC,uBAAiB,OAAO,aAAa,GAAG,EAAE,SAAS,SAAS,CAAC;AAC7D,UAAI,iBAAiB,SAAS,uBAAwB,kBAAiB,IAAI;IAC7E;EACF;AAEA,QAAM,WAAiC,CAAC,GAAG,aAAa,QAAQ,CAAC,EAC9D,IAAI,CAAC,CAAC,MAAM,OAAO,MAAM;AACxB,UAAM,OAAO,cAAc,IAAI,IAAI;AACnC,WAAO;MACL;MACA,aAAa,MAAM,eAAe;MAClC,MAAM,MAAM,QAAQ;MACpB,aAAa,MAAM;MACnB,UAAU,QAAQ;MAClB,UAAU,QAAQ;MAClB,QAAQ,QAAQ;IAClB;EACF,CAAC,EACA,OAAO,CAAC,SAAS,KAAK,WAAW,CAAC,EAClC,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AAEzC,QAAM,gBAAgB,CAAC,GAAG,SAAS,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AACxF,QAAM,qBAAqB,CAAC,GAAG,cAAc,OAAO,CAAC,EAAE;IAAK,CAAC,GAAG,MAC9D,EAAE,KAAK,cAAc,EAAE,IAAI;EAC7B;AAEA,QAAM,oBAA8C,CAAC,GAAG,SAAS,QAAQ,CAAC,EACvE,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,UAAU,MAAM,CAAC,OAAO,EAAE,OAAO,QAAQ,UAAU,MAAM,EAAE,EAClF,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AAErC,QAAM,iBAA2C,iBAAiB,IAAI,CAAC,EAAE,QAAQ,MAAM;AACrF,UAAM,WAAW,oBAAoB,OAAO;AAC5C,WAAO;MACL,WAAW,EAAE,WAAW,UAAU,WAAW,QAAQ,GAAG;MACxD;IACF;EACF,CAAC;AAED,SAAO;IACL,QAAQ;MACN,UAAU;MACV,UAAU;MACV,QAAQ;MACR,MAAM;MACN,aAAa,YAAY,IAAK,mBAAmB,cAAc,aAAc;MAC7E,gBAAgB,kBAAkB;IACpC;IACA;IACA;IACA;IACA;IACA;EACF;AACF;ACtOA,SAAS,eAA+B;AACtC,SAAO,EAAE,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,kBAAkB,OAAO,YAAY,oBAAI,IAAI,EAAE;AAC3F;AAMO,SAAS,qBACd,UACA,UACmB;AACnB,QAAM,UAAU,oBAAI,IAA4B;AAEhD,aAAW,WAAW,UAAU;AAC9B,QAAI,eAAe,OAAO,EAAG;AAC7B,UAAM,WAAW,QAAQ;AACzB,QAAI,CAAC,SAAU;AAEf,UAAM,MAAM,sBAAsB,QAAQ;AAC1C,QAAI,UAAU,QAAQ,IAAI,GAAG;AAC7B,QAAI,CAAC,SAAS;AACZ,gBAAU,aAAa;AACvB,cAAQ,IAAI,KAAK,OAAO;IAC1B;AAEA,UAAM,SAAS,eAAe,QAAQ,KAAK;AAC3C,UAAM,OAAO,QAAQ,MAAM,cAAc;AACzC,YAAQ,YAAY,QAAQ,MAAM;AAClC,YAAQ,UAAU;AAClB,YAAQ,QAAQ;AAChB,QAAI,QAAQ,MAAM,gBAAgB,YAAa,SAAQ,mBAAmB;AAE1E,UAAM,YAAY,oBAAoB,OAAO;AAC7C,UAAM,QAAQ,QAAQ,WAAW,IAAI,SAAS;AAC9C,QAAI,OAAO;AACT,YAAM,YAAY;AAClB,YAAM,YAAY,QAAQ,MAAM;AAChC,YAAM,UAAU;AAChB,YAAM,QAAQ;IAChB,OAAO;AACL,cAAQ,WAAW,IAAI,WAAW;QAChC,MAAM;QACN,UAAU;QACV,UAAU,QAAQ,MAAM;QACxB;QACA;MACF,CAAC;IACH;EACF;AAEA,SAAO,SAAS,IAAI,CAAC,YAAY;AAC/B,UAAM,SAAS,QAAQ;MACrB,sBAAsB,EAAE,MAAM,QAAQ,cAAc,KAAK,QAAQ,YAAY,CAAC;IAChF;AACA,WAAO;MACL,GAAG;MACH,UAAU,QAAQ,YAAY;MAC9B,QAAQ,QAAQ,UAAU;MAC1B,MAAM,QAAQ,QAAQ;MACtB,aACE,UAAU,OAAO,OAAO,IACpB,OAAO,mBACL,cACA,aACF;MACN,YAAY,CAAC,GAAI,QAAQ,WAAW,OAAO,KAAK,CAAC,CAAE,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;IAC7F;EACF,CAAC;AACH;AC1DO,SAAS,qBACd,OACA,SACA,UACgB;AAChB,QAAM,SAAS,wBAAwB,OAAO,OAAO;AAErD,MAAI,CAAC,mBAAmB,OAAO,MAAM,OAAO,OAAO,GAAG;AACpD,WAAO,qBAAqB,UAAU,OAAO,OAAO;EACtD;AAEA,SAAO,sBAAsB,OAAO,OAAO,MAAM,OAAO,QAAQ,OAAO,OAAO;AAChF;AAKA,SAAS,mBAAmB,WAAmB,SAAiC;AAC9E,SAAO,QAAQ,aAAa,QAAQ,QAAQ,QAAQ,YAAY,QAAQ,OAAO,MAAM;AACvF;AAEA,SAAS,2BACP,SACA,SACA,cACS;AACT,MAAI,QAAQ,eAAe,QAAQ,YAAY;AAC7C,QACE,CAAC,QAAQ,eACT,CAAC,QAAQ,cACT,CAAC,uBAAuB,QAAQ,kBAAkB;MAChD,MAAM,QAAQ;MACd,KAAK,QAAQ;IACf,CAAC,GACD;AACA,aAAO;IACT;EACF;AACA,MAAI,gBAAgB,CAAC,oBAAoB,SAAS,YAAY,EAAG,QAAO;AACxE,MAAI,QAAQ,SAAS;AACnB,UAAM,gBAAgB,QAAQ,QAAQ,YAAY;AAClD,UAAM,cAAc;MAClB,QAAQ,kBAAkB;MAC1B,QAAQ,kBAAkB;MAC1B,QAAQ;IACV,EACG,OAAO,OAAO,EACd,KAAK,IAAI,EACT,YAAY;AACf,QAAI,CAAC,YAAY,SAAS,aAAa,EAAG,QAAO;EACnD;AACA,MAAI,QAAQ,MAAM,UAAU,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ,QAAQ,YAAY,SAAS,GAAG,CAAC,GAAG;AAC3F,WAAO;EACT;AACA,MAAI,CAAC,yBAAyB,SAAS,OAAO,EAAG,QAAO;AACxD,SAAO;AACT;AAIO,SAAS,4BACd,WACA,SACA,SACA,eAA2C,MAClC;AACT,MAAI,QAAQ,SAAS,cAAc,QAAQ,MAAO,QAAO;AACzD,QAAM,WAAW,uBAAuB,OAAO;AAC/C,MAAI,QAAQ,QAAQ,QAAQ,WAAW,QAAQ,KAAM,QAAO;AAC5D,MAAI,QAAQ,MAAM,QAAQ,WAAW,QAAQ,GAAI,QAAO;AACxD,SAAO,2BAA2B,SAAS,SAAS,YAAY;AAClE;AAEA,SAASC,qBAAoB,WAAmB,WAA2B;AACzE,SAAO,GAAG,SAAS,KAAS,SAAS;AACvC;AAEO,SAAS,8BACd,YACA,SACgB;AAChB,QAAM,eAAe,QAAQ,MAAM,0BAA0B,QAAQ,GAAG,IAAI;AAC5E,QAAM,cAAc,WAAW;IAAO,CAAC,cACrC;MACE,UAAU,UAAU;MACpB,UAAU;MACV;MACA;IACF;EACF;AACA,MAAI,CAAC,QAAQ,QAAQ,CAAC,QAAQ,YAAY,CAAC,QAAQ,OAAO,OAAQ,QAAO;AAEzE,QAAM,iBAAiB;IACrB,YAAY,IAAI,CAAC,eAAe;MAC9B,WAAW,UAAU,UAAU;MAC/B,WAAW,UAAU,UAAU;IACjC,EAAE;IACF;MACE,MAAM,QAAQ;MACd,UAAU,QAAQ;MAClB,OAAO,QAAQ;IACjB;EACF;AACA,SAAO,YAAY;IAAO,CAAC,cACzB,eAAe;MACbA,qBAAoB,UAAU,UAAU,WAAW,UAAU,UAAU,SAAS;IAClF;EACF;AACF;AAEA,SAAS,qBACP,UACA,SACgB;AAChB,QAAM,eAAe,QAAQ,MAAM,0BAA0B,QAAQ,GAAG,IAAI;AAC5E,QAAM,UAAU,QAAQ,QACnB,CAAC,CAAC,QAAQ,OAAO,SAAS,QAAQ,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,IACxD,OAAO,QAAQ,SAAS,OAAO;AAEnC,SAAO,QACJ;IAAQ,CAAC,CAAC,WAAW,QAAQ,MAC5B,SACG,OAAO,CAAC,YAAY,4BAA4B,WAAW,SAAS,SAAS,YAAY,CAAC,EAC1F,IAAI,CAAC,aAAa;MACjB,WAAW,EAAE,WAAW,WAAW,QAAQ,GAAG;MAC9C;IACF,EAAE;EACN,EACC;IACC,CAAC,GAAG,OACD,EAAE,QAAQ,gBAAgB,EAAE,QAAQ,iBACpC,EAAE,QAAQ,gBAAgB,EAAE,QAAQ;EACzC,EACC,MAAM,GAAG,QAAQ,SAAS,EAAE,EAC5B,IAAI,CAAC,EAAE,WAAW,QAAQ,OAAO;IAChC;IACA;IACA,SAAS,uBAAoB,QAAQ,SAAS;IAC9C,WAAW;EACb,EAAE;AACN;AAQA,SAAS,gBAAgB,OAAe,QAA2B,SAAgC;AACjG,SACE,QAAQ,SACP,CAAC,OAAO,OAAO,OAAO,QAAQ,OAAO,YACrC,CAAC,OAAO,iBAAiB,QAAQ,OAAO,QAAQ,QAAQ;AAE7D;AAEA,SAAS,yBAAyB,SAAyB,OAA+B;AACxF,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,SAAyB,CAAC;AAEhC,aAAW,UAAU,SAAS;AAC5B,UAAM,MAAMA,qBAAoB,OAAO,UAAU,WAAW,OAAO,UAAU,SAAS;AACtF,QAAI,KAAK,IAAI,GAAG,EAAG;AACnB,SAAK,IAAI,GAAG;AACZ,WAAO,KAAK,MAAM;AAClB,QAAI,OAAO,UAAU,MAAO;EAC9B;AAEA,SAAO;AACT;AAEA,SAAS,sBAAsB,WAAmB,WAA4B;AAC5E,SAAO,QAAQ,aAAa,CAAC,SAAS;AACxC;AAEA,SAAS,sBACP,OACA,WACA,QACA,SACgB;AAChB,QAAM,YAAY,gBAAgB,OAAO,QAAQ,OAAO;AACxD,QAAM,cAAc,YAAY,2BAA2B,WAAW,OAAO,IAAI,CAAC;AAClF,QAAM,iBAAiB,sBAAsB,WAAW,SAAS,IAC7D,CAAC,IACD,eAAe,OAAO,OAAO;AACjC,QAAM,sBACJ,aAAa,QAAQ,OACjB,IAAI;IACF,eAAe;MAAI,CAAC,WAClBA,qBAAoB,OAAO,UAAU,WAAW,OAAO,UAAU,SAAS;IAC5E;EACF,IACA;AACN,QAAM,sBAAsB,sBACxB,YAAY;IAAO,CAAC,WAClB,oBAAoB;MAClBA,qBAAoB,OAAO,UAAU,WAAW,OAAO,UAAU,SAAS;IAC5E;EACF,IACA;AAEJ,SAAO,yBAAyB,CAAC,GAAG,qBAAqB,GAAG,cAAc,GAAG,QAAQ,SAAS,EAAE;AAClG;","names":["sessionKey","pending","existsSync","readdirSync","readFileSync","statSync","join","basename","dirname","homedir","closeSync","openSync","readSync","platform","resolve","rmSync","path","pending","isInternalEventType","message","toolPart","text","require","parts","mapToolTitle","normalizeToolArguments","HEAD_INDEX_VERSION","parseTimestampMs","planText","normalizeToolOutputParts","composerId","PARSER_VERSION","result","toRecord","getCacheDir","getCachePath","normalizeToolName","db","amount","rows","ensureSchema","sessionReferenceKey"]}